完成“残缺”图像的轮廓

时间:2018-12-18 00:24:58

标签: python opencv image-processing

我有一个嘈杂的灰度图像,我想对其分割/遮盖其余图像上的大弧。我打算遮罩弧线以及弧线上方的所有像素。

为此,我将图像阈值化以创建二进制图像,并使用cv2.findContours()来跟踪弧的轮廓。

原始图片:

original image

大津阈值后的图像:

image after threshold

阈值+关闭:

image after closing

闭合图像的轮廓:

resulting contours

如您所见,闭合的图像不会产生实心弧。闭合进一步会使弧失去形状。绿线是闭合图像的轮廓。蓝线是用approxpolyDP()创建的,但我无法使用它。有没有更好的方法可以掩盖图像中的弧形?

这是我的代码:

import cv2, matplotlib
import numpy as np
import matplotlib.pyplot as plt

# read an image
img = cv2.imread('oct.png')

# get gray image and apply Gaussian blur
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (5, 5), 0)

# get binary image
ret, thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

# close image to "solidify" it
kernel = np.ones((3,3),np.uint8)
closing = cv2.morphologyEx(thresh,cv2.MORPH_CLOSE,kernel, iterations = 3)


# find contours
(_, contours, _) = cv2.findContours(closing, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

cnt = contours[0]
max_area = cv2.contourArea(cnt)

for cont in contours:
    if cv2.contourArea(cont) > max_area:
        cnt = cont
        max_area = cv2.contourArea(cont)

# define main arc contour approx. and hull
perimeter = cv2.arcLength(cnt, True)
epsilon = 0.1 * cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, epsilon, True)

# hull = cv2.convexHull(cnt)

# cv2.isContourConvex(cnt)
imgcopy = np.copy(img)
cv2.drawContours(imgcopy, [cnt], -1, (0, 255, 0), 3)
cv2.drawContours(imgcopy, [approx], -1, (0, 0, 255), 3)

# plot figures
plt.figure(1)
plt.imshow(imgcopy, cmap="gray")
plt.figure(2)
plt.imshow(thresh, cmap="gray")
plt.figure(3)
plt.imshow(closing, cmap="gray")

2 个答案:

答案 0 :(得分:2)

您在正确的道路上。如果先稍微平滑一下图像,关闭效果可能会更好。我喜欢在形态学运算之后最后应用阈值。在这种情况下,关闭和阈值排序的顺序实际上并不重要,但在优化预处理时,将阈值保留在最后有助于以后。一旦阈值丢失了很多信息,就需要确保保留了所有需要的信息,因此在阈值确定之前,正确过滤图像非常重要。

这是一个快速尝试,我敢肯定它可以改进:

import matplotlib.pyplot as pp
import PyDIP as dip

img = pp.imread('/Users/cris/Downloads/MipBB.jpg')
img = img[:,:,0]
smooth = dip.Gauss(img, [3])        # Gaussian smoothing with sigma=3
smooth = dip.Closing(smooth, 25)    # Note! This uses a disk SE with diameter 25 pixels
out = dip.Threshold(smooth, 'triangle')[0]
pp.imsave('/Users/cris/Downloads/MipBB_out.png', out)

output of the code above

我使用了三角形阈值方法(也称为和弦方法或倾斜的双峰阈值,请参见PL Rosin,“单峰阈值”,模式识别34(11):2083-2096,2001),因为它可以更好地工作在这种情况下。

代码使用PyDIP,但我确定您可以使用OpenCV重新创建相同的过程。

答案 1 :(得分:2)

我建议使用RANSAC方法使用弧的边缘信息来拟合2个椭圆。只需使用canny或您认为合适的任何其他方法即可获得Edge。当然,该方法仅在圆弧为椭圆形时才有效。如果它是一条直线,则可以用直线拟合零件代替椭圆拟合零件。

这是结果:

enter image description here

代码如下:

escape sequence