自从我上一个回答错过了角落问题的重点。
我试图找到一个更合适的解决方案:
我还尝试了像 cv2.morphologyEx 这样的形态转换
但最后结果一点都不好。
那么:为什么不添加人工边框来关闭所有轮廓?
一般工作流程:
a) 扩展图像并添加边框
b)应用一些高斯滤波器
c) 转换为灰度
d) 在树层次结构中找到轮廓
e) 使用结构找到正确的轮廓
所以代码看起来像:
import cv2
from random import randrange
# read the image
image = cv2.imread('QFqC8m.jpeg')
#we extend the image to add a small border
borderSize = 1
image = cv2.copyMakeBorder(image,borderSize,borderSize,borderSize,borderSize,cv2.BORDER_CONSTANT,value=[255,255,255])
# convert the image to grayscale format
img_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv2.imshow('Binary image', img_gray)
cv2.waitKey(0)
#we apply GaussianBlur filter
image_blured = cv2.GaussianBlur(img_gray,(3,3),0)
cv2.imshow('Blured image', image_blured)
cv2.waitKey(0)
# apply binary thresholding
ret, img_thres = cv2.threshold(image_blured, 50, 200, cv2.THRESH_BINARY)
# visualize the binary image
cv2.imshow('Threshold image', img_thres)
cv2.waitKey(0)
# detect the contours on the
contours, hierarchy = cv2.findContours(image=img_thres, mode=cv2.RETR_TREE, method=cv2.CHAIN_APPROX_NONE)
hierarchy = hierarchy[0] # Remove redundant dimension of hiers.
# we iterate the hierachy
# openCV represents it as an array of four values :
# 0 1 2 3
#[Next, Previous, First_Child, Parent]
# Find contour with the maximum area our artifical box is the largest contour
# its the outside square box
rootSquareContour = max(contours, key=cv2.contourArea)
rootSquareContourArea = cv2.contourArea(rootSquareContour)
# we do search the right first tree lvl via hand
#first lvl
root_idx = contours.index(rootSquareContour)
root_hierarchy = hierarchy[root_idx]
child_idx = root_hierarchy[2] # Index of the first child
while child_idx != -1:
child_hierarchy = hierarchy[child_idx]
#get the contour
c = contours[child_idx]
#we draw it with random color
cv2.fillPoly(image,pts=[c],color=(randrange(255),randrange(255),randrange(255)))
#get next element
child_hierarchy = hierarchy[child_idx]
child_idx = child_hierarchy[0] #get next element on same lvl
#TODO might need not all lvl ?
if child_idx==-1: #switch to next lvl
child_idx = child_hierarchy[2]
cv2.imshow("Filled Contours", image)
cv2.imwrite("filled.jpg", image)
cv2.waitKey(0)
cv2.destroyAllWindows()
还有一些工作要做,但代码解释了背后的想法。
关于层次结构的一个很好的解释可以在here
找到