opencv图像分割算法

加载源图像并检查是否已正确加载,然后显示:
watershed详情见另一篇博客https://blog.csdn.net/weixin_43886213/article/details/103092283

from __future__ import print_function
import cv2 as cv
import numpy as np
import argparse
import random as rng
rng.seed(12345)
parser = argparse.ArgumentParser(description='Code for Image Segmentation with Distance Transform and Watershed Algorithm.\
    Sample code showing how to segment overlapping objects using Laplacian filtering, \
    in addition to Watershed and Distance Transformation')
parser.add_argument('--input', help='Path to input image.', default='cards.png')
args = parser.parse_args()
src = cv.imread(cv.samples.findFile(args.input))
if src is None:
    print('Could not open or find the image:', args.input)
    exit(0)
# Show source image
cv.imshow('Source Image', src)

然后,如果我们有一个带有白色背景的图像,最好将其转换为黑色。当我们应用距离变换时,这将有助于我们更轻松地区分前景对象:

src[np.all(src == 255, axis=2)] = 0
cv.imshow('Black Background Image', src)

然后,我们将锐化图像以锐化前景对象的边缘。我们将使用拉普拉斯滤波器和一个很强的滤波器(二阶导数的近似值)

imgLaplacian = cv.filter2D(src, cv.CV_32F, kernel)
sharp = np.float32(src)
imgResult = sharp - imgLaplacian

# convert back to 8bits gray scale
imgResult = np.clip(imgResult, 0, 255)
imgResult = imgResult.astype('uint8')
imgLaplacian = np.clip(imgLaplacian, 0, 255)
imgLaplacian = np.uint8(imgLaplacian)

#cv.imshow('Laplace Filtered Image', imgLaplacian)
cv.imshow('New Sharped Image', imgResult)

现在,我们将新的锐化后的源图像分别转换为灰度和二进制图像

bw = cv.cvtColor(imgResult, cv.COLOR_BGR2GRAY)
cv.imshow('Binary Image', bw)
_, bw = cv.threshold(bw, 40, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
cv.imshow('Binary Image1', bw)

现在我们准备在二进制图像上应用距离变换。此外,我们对输出图像进行归一化,以便能够可视化和阈值化结果:

dist = cv.distanceTransform(bw, cv.DIST_L2, 5)

# Normalize the distance image for range = {0.0, 1.0}
# so we can visualize and threshold it
cv.normalize(dist, dist, 0, 1.0, cv.NORM_MINMAX)
cv.imshow('Distance Transform Image', dist)

我们对dist图像进行阈值处理,然后执行一些形态学运算(即膨胀),以便从上述图像中提取峰

_, dist = cv.threshold(dist, 0.4, 1.0, cv.THRESH_BINARY)
# Dilate a bit the dist image
kernel1 = np.ones((3,3), dtype=np.uint8)
dist = cv.dilate(dist, kernel1)
cv.imshow('Peaks', dist)

然后,在每个blob中,借助cv :: findContours函数为分水岭算法创建一个种子/标记

dist_8u = dist.astype('uint8')

# Find total markers
contours, _ = cv.findContours(dist_8u, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)

# Create the marker image for the watershed algorithm
markers = np.zeros(dist.shape, dtype=np.uint8)

# Draw the foreground markers
for i in range(len(contours)):
    cv.drawContours(markers, contours, i, (i+1), -1)
# Draw the background marker
cv.circle(markers, (5,5), 3, (255,255,255), -1)
markers=markers.astype('uint8')
cv.imshow('Markers', markers*10000)

最后,我们可以应用分水岭算法,并可视化结果:

markers=markers.astype('int32')
#然后应用分水岭算法。然后,我们的标记将使用给定的标签进行更新,并且对象的边界的值为-1
cv.watershed(imgResult, markers)
#任何灰度图像都可以视为地形图表面,其中高强度表示山峰和丘陵,而低强度表示山谷。
# 您开始用不同颜色的水(标签)填充每个孤立的山谷(局部最小值)。随着水的上升,取决于附近的峰(梯度),来自不同山谷(显然具有不同颜色)的水将开始合并。
# 为了避免这种情况,您可以在水汇合的位置建造障碍。您将继续填充水和建造障碍物的工作,直到所有山峰都在水下。然后,您创建的障碍将为您提供细分结果
#mark = np.zeros(markers.shape, dtype=np.uint8)
mark = markers.astype('uint8')
#cv.imshow('Markers_v1', mark)黑图白轮廓
mark = cv.bitwise_not(mark)
# uncomment this if you want to see how the mark
# image looks like at that point
#cv.imshow('Markers_v2', mark)白图黑轮廓
# Generate random colors
colors = []
for contour in contours:
    colors.append((rng.randint(0,256), rng.randint(0,256), rng.randint(0,256)))
#print(colors)[(213, 5, 152), (188, 99, 138), (223, 82, 191), (63, 221, 133), (89, 95, 181), (46, 211, 85), (75, 105, 39), (97, 174, 164), (12, 234, 173)
# , (13, 212, 1), (3, 83, 91), (146, 50, 212), (54, 93, 192), (119, 168, 20), (118, 61, 255), (110, 95, 131), (222, 66, 21), (84, 154, 4)]
# Create the result image
dst = np.zeros((markers.shape[0], markers.shape[1], 3), dtype=np.uint8)
#print(markers)[[ -1  -1  -1 ...  -1  -1  -1]
# [ -1 255 255 ... 255 255  -1][ -1 255 255 ... 255 255  -1] ... [ -1 255 255 ... 255 255  -1] [ -1 255 255 ... 255 255  -1] [ -1  -1  -1 ...  -1  -1  -1]]
#print(markers.shape[0])243
#print(markers.shape[1])300
#print(len(contours))18
# Fill labeled objects with random colors
for i in range(markers.shape[0]):
    for j in range(markers.shape[1]):
        index = markers[i,j]
        if index > 0 and index <= len(contours):
            dst[i,j,:] = colors[index-1]
# Visualize the final image
cv.imshow('Final Result', dst)
## [watershed]

cv.waitKey()

你可能感兴趣的:(opencv图像分割算法)