与轮廓中最多点接触的最大正方形
Largest square in contact with most points in contour
我有一张图片,我从 opencv 找到并绘制了轮廓(见左图)。
我想画一个盒子(像右边那个)如下,它应该与轮廓中最多的点接触。
这里有什么功能有用?我想尝试找到最大的矩形,但如您所见,该区域内部有一些区域,因此它会排除该区域?
非常感谢您的帮助!
首先,您需要将图像转换为二进制(黑色或白色像素)以区分轮廓和图像的其余部分(在示例中,轮廓是黑色背景上的白色)。然后你可以“行扫描”图像,意思是计算每一行和每一列的白色像素的数量。矩形的第一个水平边缘(具有最多白色像素的水平线)应位于图像高度的前半部分,下一个水平边缘应位于图像高度的后半部分。同样对于垂直边缘(具有最多白色像素的垂直线),第一个应该在图像宽度的前半部分,下一个在下一个。看一下下面的代码就清楚了。
示例代码:
import cv2
import numpy as np
img = cv2.imread("2.png")
h, w = img.shape[:2]
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU+cv2.THRESH_BINARY_INV)[1]
thresh = cv2.rectangle(thresh, (0, 0), (w, h), (0, 0, 0), 3)
width = 1
horizontal_line = []
best_hor_one = 0
best_hor_two = 0
count_hor_one = 0
count_hor_two = 0
for y in range(h):
area = thresh[y:y+width, 0:h]
try:
line = cv2.countNonZero(area)
if line >= count_hor_one and y < h//2:
best_hor_one = y
count_hor_one = line
if line >= count_hor_two and y >= h//2:
best_hor_two = y
count_hor_two = line
except TypeError:
pass
best_ver_one = 0
best_ver_two = 0
count_ver_one = 0
count_ver_two = 0
for x in range(w):
area = thresh[0:h, x:x+width]
try:
line = cv2.countNonZero(area)
if line > count_ver_one and x < w//2:
best_ver_one = x
count_ver_one = line
if line > count_ver_two and x >= w//2:
best_ver_two = x
count_ver_two = line
except TypeError:
pass
cv2.line(img, (best_ver_one, best_hor_one),
(best_ver_two, best_hor_one), (0, 255, 0), 3)
cv2.line(img, (best_ver_one, best_hor_two),
(best_ver_two, best_hor_two), (0, 255, 0), 3)
cv2.line(img, (best_ver_one, best_hor_one),
(best_ver_one, best_hor_two), (0, 255, 0), 3)
cv2.line(img, (best_ver_two, best_hor_one),
(best_ver_two, best_hor_two), (0, 255, 0), 3)
cv2.imwrite("res.png", img)
cv2.imshow("img", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果:
输入图像:
我有一张图片,我从 opencv 找到并绘制了轮廓(见左图)。
我想画一个盒子(像右边那个)如下,它应该与轮廓中最多的点接触。
这里有什么功能有用?我想尝试找到最大的矩形,但如您所见,该区域内部有一些区域,因此它会排除该区域?
非常感谢您的帮助!
首先,您需要将图像转换为二进制(黑色或白色像素)以区分轮廓和图像的其余部分(在示例中,轮廓是黑色背景上的白色)。然后你可以“行扫描”图像,意思是计算每一行和每一列的白色像素的数量。矩形的第一个水平边缘(具有最多白色像素的水平线)应位于图像高度的前半部分,下一个水平边缘应位于图像高度的后半部分。同样对于垂直边缘(具有最多白色像素的垂直线),第一个应该在图像宽度的前半部分,下一个在下一个。看一下下面的代码就清楚了。
示例代码:
import cv2
import numpy as np
img = cv2.imread("2.png")
h, w = img.shape[:2]
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU+cv2.THRESH_BINARY_INV)[1]
thresh = cv2.rectangle(thresh, (0, 0), (w, h), (0, 0, 0), 3)
width = 1
horizontal_line = []
best_hor_one = 0
best_hor_two = 0
count_hor_one = 0
count_hor_two = 0
for y in range(h):
area = thresh[y:y+width, 0:h]
try:
line = cv2.countNonZero(area)
if line >= count_hor_one and y < h//2:
best_hor_one = y
count_hor_one = line
if line >= count_hor_two and y >= h//2:
best_hor_two = y
count_hor_two = line
except TypeError:
pass
best_ver_one = 0
best_ver_two = 0
count_ver_one = 0
count_ver_two = 0
for x in range(w):
area = thresh[0:h, x:x+width]
try:
line = cv2.countNonZero(area)
if line > count_ver_one and x < w//2:
best_ver_one = x
count_ver_one = line
if line > count_ver_two and x >= w//2:
best_ver_two = x
count_ver_two = line
except TypeError:
pass
cv2.line(img, (best_ver_one, best_hor_one),
(best_ver_two, best_hor_one), (0, 255, 0), 3)
cv2.line(img, (best_ver_one, best_hor_two),
(best_ver_two, best_hor_two), (0, 255, 0), 3)
cv2.line(img, (best_ver_one, best_hor_one),
(best_ver_one, best_hor_two), (0, 255, 0), 3)
cv2.line(img, (best_ver_two, best_hor_one),
(best_ver_two, best_hor_two), (0, 255, 0), 3)
cv2.imwrite("res.png", img)
cv2.imshow("img", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果:
输入图像: