opencv 如何检测接触边界的轮廓?

31moq8wy  于 2022-12-27  发布在  其他
关注(0)|答案(2)|浏览(216)

我正在编写一个程序,可以使用Python和OpenCV检测3D打印机粉末层的不一致性。到目前为止,我所做的是使用边缘检测创建一个蒙版图像,然后再次执行边缘检测,并排除任何接触边界的轮廓。然而我想检测轮廓接触边界以及。我已经尝试了各种方法,但似乎没有达到的结果,我正在寻找。This article看起来和我有同样的问题,并提供了答案,但它是用C++编写的,我不完全理解。
例如,下面是一个轮廓与边界接触的图像:image.
这是执行边缘检测后的图像:image。正如你所看到的,图像的边界包含在我试图检测的轮廓中。注意,边界并不总是正方形,而是可以是任何多边形形状。

yeotifhr

yeotifhr1#

下面是在Python/OpenCV中实现这一点的一种方法。

  • 读取输入
  • 转换为灰色
  • 阈值
  • 获取白色像素的边界
  • 将输入裁剪到这些边界以移除黑色边框
  • 对裁剪图像设置阈值以隔离较亮区域
  • 应用形态学对其进行清理
  • 获取轮廓及其边界框
  • 测试边界框是否接触裁剪图像的4个边中的任何一个
  • 在输入图像上绘制轮廓边界框
  • 保存结果

输入:

import cv2
import numpy as np

# load image as grayscale
img = cv2.imread('streak.png')

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# threshold 
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1]

# get bounds of white pixels
white = np.where(thresh==255)
xmin, ymin, xmax, ymax = np.min(white[1]), np.min(white[0]), np.max(white[1]), np.max(white[0])
print(xmin,xmax,ymin,ymax)

# crop the gray image at the bounds
crop = gray[ymin:ymax, xmin:xmax]
hh, ww = crop.shape

# do adaptive thresholding
thresh2 = cv2.adaptiveThreshold(crop, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 3, 1.1)

# apply morphology
kernel = np.ones((1,7), np.uint8)
morph = cv2.morphologyEx(thresh2, cv2.MORPH_CLOSE, kernel)
kernel = np.ones((5,5), np.uint8)
morph = cv2.morphologyEx(morph, cv2.MORPH_OPEN, kernel)

# invert
morph = 255 - morph

# get contours (presumably just one) and its bounding box
contours = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
for cntr in contours:
    x,y,w,h = cv2.boundingRect(cntr)

# draw bounding box on input
bbox = img.copy()
cv2.rectangle(bbox, (x+xmin, y+ymin), (x+xmin+w, y+ymin+h), (0,0,255), 1)

# test if contour touches sides of image
if x == 0 or y == 0 or x+w == ww or y+h == hh:
    print('region touches the sides')
else:
    print('region does not touch the sides')

# save resulting masked image
cv2.imwrite('streak_thresh.png', thresh)
cv2.imwrite('streak_crop.png', crop)
cv2.imwrite('streak_bbox.png', bbox)

# display result
cv2.imshow("thresh", thresh)
cv2.imshow("crop", crop)
cv2.imshow("thresh2", thresh2)
cv2.imshow("morph", morph)
cv2.imshow("bbox", bbox)
cv2.waitKey(0)
cv2.destroyAllWindows()

用于查找边界的阈值图像:

裁剪输入:

形态清洁第二阈值:

输入上区域轮廓的边界框:

打印消息:

region touches the sides
ttp71kqs

ttp71kqs2#

您可以使用此代码来查找轮廓是否接触边界,相对而言,这要快得多:

import cv2
from skimage import measure
from skimage.segmentation import clear_border

img = cv2.imread('image.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_,im_bw = cv2.threshold(gray,127,255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)

cntrs,_ = cv2.findContours(im_bw, 1, 2)
cntrs = sorted(cntrs, key=cv2.contourArea)

# you can also for loop here to find border touching for each contours
# For now, I am only doing it for single contour

cnt = cntr[-1]   #finding whether the last contour is touching the border or not

im_bw = cv2.fillPoly(im_bw, pts=[cnt], color=(1)) #converting to 0/1 pixel range
cleared = clear_border(im_bw)

if len(np.unique(cleared)) == 1:
  print("Contour is touching the border")
else:
  print("Contour is not touching the border")

# If its True, contour is touching the border else it is not touching

相关问题