如何使用 cv2.minAreaRect(cnt) 在多轮廓图像上获得唯一的最小区域矩形?
How to get the only min area rectangle on a multiple contours image with cv2.minAreaRect(cnt)?
我只想用一个矩形来覆盖这张图中的圆:
然后用 cv2.minAreaRect(cnt)
得到这个结果:
这张图片好像分成了多个部分。也许是因为这张图片的边缘有一些断点。你能告诉我如何只使用一个矩形来覆盖我图像的这一圈吗?非常感谢!
这是我的代码:
def draw_min_rect_circle(img, cnts): # conts = contours
img = np.copy(img)
for cnt in cnts:
x, y, w, h = cv2.boundingRect(cnt)
cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2) # blue
min_rect = cv2.minAreaRect(cnt) # min_area_rectangle
min_rect = np.int0(cv2.boxPoints(min_rect))
cv2.drawContours(img, [min_rect], 0, (0, 255, 0), 2) # green
(x, y), radius = cv2.minEnclosingCircle(cnt)
center, radius = (int(x), int(y)), int(radius) # center and radius of minimum enclosing circle
img = cv2.circle(img, center, radius, (0, 0, 255), 2) # red
return img
你需要做的是你需要通过合并轮廓以某种方式从图像中仅获得1个轮廓,这有点困难,所以如果你只想要一个包围所有轮廓的矩形,你可以做这样的事情
def draw_min_rect_circle(img, cnts): # conts = contours
img = np.copy(img)
x1,y1 = np.inf
x2,y2 = 0
for cnt in cnts:
x, y, w, h = cv2.boundingRect(cnt)
if x > x1:
x1=x
if y > y1:
y1=y
if x2 < x+w
x2 = x+w
if y2 < y+h
y2 = y+h
w = x2 - x1
h = y2 - y1
r = math.sqrt((w*w) + (h*h)) / 2
cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
cv2.circle(img, (x1+w/2,y1+h/2), r, (0, 0, 255), 2)
您可能使用 cv2.findContours()
搜索轮廓并遍历它们以在图像上绘制矩形。问题是你的图像没有由一条连接线组成的圆圈,而是许多虚线。
轮廓是连接所有连续点(沿着边界)的曲线,具有相同的颜色或强度(OpenCV 文档)。
因此,为了获得更好的结果,您应该先准备图像,然后再搜索轮廓。您可以使用各种工具对图像进行预处理(您可以搜索 OpenCV 文档)。在这种情况下,我会尝试使用一个小内核来执行名为 "closing" 的过程。关闭是先膨胀后像素腐蚀。它可以帮助将您的小轮廓连接到一个大轮廓(圆)。然后你可以 select 最大的一个并绘制一个边界矩形。
示例:
输入图像:
import cv2
import numpy as np
img = cv2.imread('test.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
kernel = np.ones((3,3), dtype=np.uint8)
closing = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
_, contours, hierarchy = cv2.findContours(closing, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cnt = max(contours, key=cv2.contourArea)
x,y,w,h = cv2.boundingRect(cnt)
cv2.rectangle(img, (x,y), (x+w, y+h), (255,255,0), 1)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果:
执行关闭操作后的图像:
希望对您有所帮助。干杯!
可以将所有轮廓连接成一个轮廓,因为它们只是描述轮廓的点坐标的 numpy 数组。您可以使用 np.concatenate(contours) 并且 cv2.minAreaRect 函数似乎并不关心新数组中的点是否连续。在我的例子中,这比使用关闭函数效果更好,因为我有更复杂的对象。如果您愿意,可以尝试一下,这很简单。你的函数应该是这样的:
def draw_min_rect_circle(img, cnts): # conts = contours
img = np.copy(img)
join_cnts = np.concatenate(cnts)
x, y, w, h = cv2.boundingRect(join_cnts)
cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2) # blue
min_rect = cv2.minAreaRect(join_cnts) # min_area_rectangle
min_rect = np.int0(cv2.boxPoints(min_rect))
cv2.drawContours(img, [min_rect], 0, (0, 255, 0), 2) # green
(x, y), radius = cv2.minEnclosingCircle(join_cnts)
center, radius = (int(x), int(y)), int(radius) # center and radius of minimum enclosing circle
img = cv2.circle(img, center, radius, (0, 0, 255), 2) # red
return img
我只想用一个矩形来覆盖这张图中的圆:
然后用 cv2.minAreaRect(cnt)
得到这个结果:
这张图片好像分成了多个部分。也许是因为这张图片的边缘有一些断点。你能告诉我如何只使用一个矩形来覆盖我图像的这一圈吗?非常感谢!
这是我的代码:
def draw_min_rect_circle(img, cnts): # conts = contours
img = np.copy(img)
for cnt in cnts:
x, y, w, h = cv2.boundingRect(cnt)
cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2) # blue
min_rect = cv2.minAreaRect(cnt) # min_area_rectangle
min_rect = np.int0(cv2.boxPoints(min_rect))
cv2.drawContours(img, [min_rect], 0, (0, 255, 0), 2) # green
(x, y), radius = cv2.minEnclosingCircle(cnt)
center, radius = (int(x), int(y)), int(radius) # center and radius of minimum enclosing circle
img = cv2.circle(img, center, radius, (0, 0, 255), 2) # red
return img
你需要做的是你需要通过合并轮廓以某种方式从图像中仅获得1个轮廓,这有点困难,所以如果你只想要一个包围所有轮廓的矩形,你可以做这样的事情
def draw_min_rect_circle(img, cnts): # conts = contours
img = np.copy(img)
x1,y1 = np.inf
x2,y2 = 0
for cnt in cnts:
x, y, w, h = cv2.boundingRect(cnt)
if x > x1:
x1=x
if y > y1:
y1=y
if x2 < x+w
x2 = x+w
if y2 < y+h
y2 = y+h
w = x2 - x1
h = y2 - y1
r = math.sqrt((w*w) + (h*h)) / 2
cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
cv2.circle(img, (x1+w/2,y1+h/2), r, (0, 0, 255), 2)
您可能使用 cv2.findContours()
搜索轮廓并遍历它们以在图像上绘制矩形。问题是你的图像没有由一条连接线组成的圆圈,而是许多虚线。
轮廓是连接所有连续点(沿着边界)的曲线,具有相同的颜色或强度(OpenCV 文档)。
因此,为了获得更好的结果,您应该先准备图像,然后再搜索轮廓。您可以使用各种工具对图像进行预处理(您可以搜索 OpenCV 文档)。在这种情况下,我会尝试使用一个小内核来执行名为 "closing" 的过程。关闭是先膨胀后像素腐蚀。它可以帮助将您的小轮廓连接到一个大轮廓(圆)。然后你可以 select 最大的一个并绘制一个边界矩形。
示例:
输入图像:
import cv2
import numpy as np
img = cv2.imread('test.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
kernel = np.ones((3,3), dtype=np.uint8)
closing = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
_, contours, hierarchy = cv2.findContours(closing, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cnt = max(contours, key=cv2.contourArea)
x,y,w,h = cv2.boundingRect(cnt)
cv2.rectangle(img, (x,y), (x+w, y+h), (255,255,0), 1)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果:
执行关闭操作后的图像:
希望对您有所帮助。干杯!
可以将所有轮廓连接成一个轮廓,因为它们只是描述轮廓的点坐标的 numpy 数组。您可以使用 np.concatenate(contours) 并且 cv2.minAreaRect 函数似乎并不关心新数组中的点是否连续。在我的例子中,这比使用关闭函数效果更好,因为我有更复杂的对象。如果您愿意,可以尝试一下,这很简单。你的函数应该是这样的:
def draw_min_rect_circle(img, cnts): # conts = contours
img = np.copy(img)
join_cnts = np.concatenate(cnts)
x, y, w, h = cv2.boundingRect(join_cnts)
cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2) # blue
min_rect = cv2.minAreaRect(join_cnts) # min_area_rectangle
min_rect = np.int0(cv2.boxPoints(min_rect))
cv2.drawContours(img, [min_rect], 0, (0, 255, 0), 2) # green
(x, y), radius = cv2.minEnclosingCircle(join_cnts)
center, radius = (int(x), int(y)), int(radius) # center and radius of minimum enclosing circle
img = cv2.circle(img, center, radius, (0, 0, 255), 2) # red
return img