检测 table 作为一个表面给出了很多矩形
Detection table as a surface gives a lot of rectangles
我想得到 table 表面的矩形。所以我想我可以用 opencv 的 findContours 和 contourArea 函数来做到这一点。现在,当结果是当我采用最大 contourArea 时,它将所有内容都视为一个区域。当我不这样做时,它会给出不同的结果,请参见图片。
有没有办法组合这些矩形,以便将 table 检测为表面?因为我想知道那些东西是在表面上还是从表面上移开了。
代码:
import cv2
import numpy as np
file = "/Users/mars/Downloads/table.jpg"
im1 = cv2.imread(file, 0)
im = cv2.imread(file)
ret, thresh_value = cv2.threshold(im1, 180, 255, cv2.THRESH_BINARY_INV)
kernel = np.ones((5, 5), np.uint8)
dilated_value = cv2.dilate(thresh_value, kernel, iterations=1)
contours, hierarchy = cv2.findContours(dilated_value, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
areas = [cv2.contourArea(c) for c in contours]
max_index = np.argmax(areas)
cnt = contours[max_index]
x, y, w, h = cv2.boundingRect(cnt)
cv2.rectangle(im, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.imwrite('result.jpg', im)
您的代码无法正常工作的主要原因是您正在使用 cv2.THRESH_BINARY_INV
。
反转极性,将 table 区域变为黑色,findContours
正在搜索白色轮廓。
我建议使用以下阶段:
- 转换为二进制图像 - 使用
THRESH_OTSU
作为自动阈值(它比使用固定阈值更可靠)。
- 使用"closing"形态学运算(闭合就像膨胀而不是腐蚀)。
关闭优于 dilate
,因为它不会改变轮廓的大小。
- 找轮廓,用
RETR_EXTERNAL
代替RETR_TREE
,因为你要找的是外轮廓。
- 求出面积最大的等高线。
代码如下:
import numpy as np
import cv2
# Read input image
im = cv2.imread('table.jpg')
# Drop one row and column from each side (because the image you posted has a green rectangle around it).
im = im[1:-2, 1:-2, :]
# Convert to Grayscale
im1 = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
# Convert to binary image - use THRESH_OTSU for automatic threshold.
ret, thresh_value = cv2.threshold(im1, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# Use "closing" morphological operation (closing is like dilate and than erode)
thresh = cv2.morphologyEx(thresh_value, cv2.MORPH_CLOSE, np.ones((5, 5)))
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2] # [-2] indexing is used due to OpenCV compatibility issues.
# Get contour with maximum area
c = max(cnts, key=cv2.contourArea)
# Mark contour with green line
cv2.drawContours(im, [c], -1, (0, 255, 0), 2)
# Show output
cv2.imshow('im', cv2.resize(im, (im.shape[1]//4, im.shape[0]//4)))
cv2.waitKey(0)
cv2.destroyAllWindows()
结果:
我想得到 table 表面的矩形。所以我想我可以用 opencv 的 findContours 和 contourArea 函数来做到这一点。现在,当结果是当我采用最大 contourArea 时,它将所有内容都视为一个区域。当我不这样做时,它会给出不同的结果,请参见图片。
有没有办法组合这些矩形,以便将 table 检测为表面?因为我想知道那些东西是在表面上还是从表面上移开了。
代码:
import cv2
import numpy as np
file = "/Users/mars/Downloads/table.jpg"
im1 = cv2.imread(file, 0)
im = cv2.imread(file)
ret, thresh_value = cv2.threshold(im1, 180, 255, cv2.THRESH_BINARY_INV)
kernel = np.ones((5, 5), np.uint8)
dilated_value = cv2.dilate(thresh_value, kernel, iterations=1)
contours, hierarchy = cv2.findContours(dilated_value, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
areas = [cv2.contourArea(c) for c in contours]
max_index = np.argmax(areas)
cnt = contours[max_index]
x, y, w, h = cv2.boundingRect(cnt)
cv2.rectangle(im, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.imwrite('result.jpg', im)
您的代码无法正常工作的主要原因是您正在使用 cv2.THRESH_BINARY_INV
。
反转极性,将 table 区域变为黑色,findContours
正在搜索白色轮廓。
我建议使用以下阶段:
- 转换为二进制图像 - 使用
THRESH_OTSU
作为自动阈值(它比使用固定阈值更可靠)。 - 使用"closing"形态学运算(闭合就像膨胀而不是腐蚀)。
关闭优于dilate
,因为它不会改变轮廓的大小。 - 找轮廓,用
RETR_EXTERNAL
代替RETR_TREE
,因为你要找的是外轮廓。 - 求出面积最大的等高线。
代码如下:
import numpy as np
import cv2
# Read input image
im = cv2.imread('table.jpg')
# Drop one row and column from each side (because the image you posted has a green rectangle around it).
im = im[1:-2, 1:-2, :]
# Convert to Grayscale
im1 = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
# Convert to binary image - use THRESH_OTSU for automatic threshold.
ret, thresh_value = cv2.threshold(im1, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# Use "closing" morphological operation (closing is like dilate and than erode)
thresh = cv2.morphologyEx(thresh_value, cv2.MORPH_CLOSE, np.ones((5, 5)))
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2] # [-2] indexing is used due to OpenCV compatibility issues.
# Get contour with maximum area
c = max(cnts, key=cv2.contourArea)
# Mark contour with green line
cv2.drawContours(im, [c], -1, (0, 255, 0), 2)
# Show output
cv2.imshow('im', cv2.resize(im, (im.shape[1]//4, im.shape[0]//4)))
cv2.waitKey(0)
cv2.destroyAllWindows()
结果: