如何使用`cv2.minAreaRect`来获取最大的轮廓,即使图像中有破碎的区域?

huangapple go评论59阅读模式
英文:

How can I use cv2.minAreaRect to obtain the largest contour, even if the image has broken regions?

问题

这是原始图像。

我想使用cv2.minAreaRect来获取最大轮廓,如下图所示。

尝试1 - 失败

cnt, hierarchy  = cv2.findContours(im_bw, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
min_rect = cv2.minAreaRect(cnt[0])
box = np.int0(cv2.boxPoints(min_rect))
cv2.drawContours(temp_result, [box], 0, (255, 0, 0), 2)

尝试2 - 失败

我参考了这篇帖子来获取用于绘制的有序坐标。但是,我得到了以下结果,其中线条不匹配,四个点无法与cv2.minAreaRect一起使用。

def order_points(pts):
	# 初始化一个将被排序的坐标列表,使得列表中的第一个条目是左上角,
	# 第二个条目是右上角,第三个是右下角,第四个是左下角
	rect = np.zeros((4, 2), dtype="float32")

	# 左上角的点将具有最小的和,而
	# 右下角的点将具有最大的和
	s = np.sum(pts, axis=1)
	rect[0] = pts[np.argmin(s)]  # 左上角
	rect[2] = pts[np.argmax(s)]  # 右下角

	# 现在,计算点之间的差异,右上角的点将具有最小的差异,
	# 而左下角将具有最大的差异
	diff = np.diff(pts, axis=1)
	rect[1] = pts[np.argmin(diff)]  # 右上角
	rect[3] = pts[np.argmax(diff)]  # 左下角

	# 返回有序的坐标
	return rect

# pts = [(93, 50), (109, 82), (76, 47), (93, 77), (58, 38), (76, 72), (36, 32), (54, 67), (20, 27), (35, 62), (3, 22), (18, 56), (111, 54), (128, 87)]

t = order_points(pts)
cv2.line(temp_result, pt1=(int(t[0][0]), int(t[0][1])), pt2=(int(t[1][0]), int(t[1][1])), color=(0, 0, 255), thickness=2)
cv2.line(temp_result, pt1=(int(t[3][0]), int(t[3][1])), pt2=(int(t[2][0]), int(t[2][1])), color=(0, 0, 255), thickness=2)

任何帮助将不胜感激。

英文:

This is the original image.
如何使用`cv2.minAreaRect`来获取最大的轮廓,即使图像中有破碎的区域?

I want to use cv2.minAreaRect to obtain the maximum contour, as shown in the following image.
如何使用`cv2.minAreaRect`来获取最大的轮廓,即使图像中有破碎的区域?

Attempt 1 - Fail

如何使用`cv2.minAreaRect`来获取最大的轮廓,即使图像中有破碎的区域?

cnt, hierarchy  = cv2.findContours(im_bw, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
min_rect = cv2.minAreaRect(cnt[0])
box = np.int0(cv2.boxPoints(min_rect))
cv2.drawContours(temp_result, [box], 0, (255, 0, 0), 2)

Attempt 2 - Fail

I referred to this post to obtain the ordered coordinates for drawing. However, I obtained the following result, where the lines don't match and the four points cannot be used with cv2.minAreaRect.
如何使用`cv2.minAreaRect`来获取最大的轮廓,即使图像中有破碎的区域?

def order_points(pts):
	# initialzie a list of coordinates that will be ordered
	# such that the first entry in the list is the top-left,
	# the second entry is the top-right, the third is the
	# bottom-right, and the fourth is the bottom-left
	rect = np.zeros((4, 2), dtype = "float32")

	# the top-left point will have the smallest sum, whereas
	# the bottom-right point will have the largest sum
	s = np.sum(pts, axis = 1)
	rect[0] = pts[np.argmin(s)] # top-left
	rect[2] = pts[np.argmax(s)] # bottom-right

	# now, compute the difference between the points, the
	# top-right point will have the smallest difference,
	# whereas the bottom-left will have the largest difference
	diff = np.diff(pts, axis = 1)
	rect[1] = pts[np.argmin(diff)] # top-right
	rect[3] = pts[np.argmax(diff)] # bottom-left

	# return the ordered coordinates
	return rect
#########################################################################
# pts = [(93, 50), (109, 82), (76, 47), (93, 77), (58, 38), (76, 72), (36, 32), (54, 67), (20, 27), (35, 62), (3, 22), (18, 56), (111, 54), (128, 87)]

t = order_points(pts)
cv2.line(temp_result, pt1=(int(t[0][0]), int(t[0][1])), pt2=(int(t[1][0]), int(t[1][1])), color=(0, 0, 255), thickness=2)
cv2.line(temp_result, pt1=(int(t[3][0]), int(t[3][1])), pt2=(int(t[2][0]), int(t[2][1])), color=(0, 0, 255), thickness=2)

Any help will be appreciated.

答案1

得分: 5

我们可以找到合并轮廓的凸包

<!-- language: lang-python -->

merged_cnt = cv2.convexHull(np.vstack(cnt))

代码示例:

<!-- language: lang-python -->

import cv2
import numpy as np

im_bw = cv2.imread('im_bw.png', cv2.IMREAD_GRAYSCALE)  # 将im_bw以灰度读取

temp_result = cv2.cvtColor(im_bw, cv2.COLOR_GRAY2BGR)

cnt, hierarchy  = cv2.findContours(im_bw, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 将所有轮廓合并为一个大轮廓 - 结果是所有轮廓的凸包。
merged_cnt = cv2.convexHull(np.vstack(cnt))

cv2.drawContours(temp_result, [merged_cnt], 0, (255, 0, 0), 2)

# 用于测试的显示结果
cv2.imshow('temp_result', temp_result)
cv2.waitKey()
cv2.destroyAllWindows()

结果:
如何使用`cv2.minAreaRect`来获取最大的轮廓,即使图像中有破碎的区域?


如果目标是将轮廓近似为矩形多边形,我们可以使用以下答案中的simplify_contour方法

<!-- language: lang-python -->

approx = simplify_contour(merged_cnt)

cv2.drawContours(temp_result, [approx], 0, (0, 0, 255), 2)

结果:
如何使用`cv2.minAreaRect`来获取最大的轮廓,即使图像中有破碎的区域?


如果目标是找到如标题所述的minAreaRect

<!-- language: lang-python -->

min_rect = cv2.minAreaRect(merged_cnt)  # 找到合并轮廓的minAreaRect
box = np.int0(cv2.boxPoints(min_rect))

我们得到以下输出:
如何使用`cv2.minAreaRect`来获取最大的轮廓,即使图像中有破碎的区域?

英文:

We may find the Convex hull of the merged contours:

<!-- language: lang-python -->

merged_cnt = cv2.convexHull(np.vstack(cnt))

Code sample:

<!-- language: lang-python -->

import cv2
import numpy as np

im_bw = cv2.imread(&#39;im_bw.png&#39;, cv2.IMREAD_GRAYSCALE)  # Read im_bw as grayscale

temp_result = cv2.cvtColor(im_bw, cv2.COLOR_GRAY2BGR)

cnt, hierarchy  = cv2.findContours(im_bw, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# Merge all the contours into one large contour - the result is the convex hull of all contour.
merged_cnt = cv2.convexHull(np.vstack(cnt))

cv2.drawContours(temp_result, [merged_cnt], 0, (255, 0, 0), 2)

# Show result for testing
cv2.imshow(&#39;temp_result&#39;, temp_result)
cv2.waitKey()
cv2.destroyAllWindows()

Result:
如何使用`cv2.minAreaRect`来获取最大的轮廓,即使图像中有破碎的区域?


In case the objective is to approximate the contour to rectangular polygon, we may use simplify_contour method from the following answer

<!-- language: lang-python -->

approx = simplify_contour(merged_cnt)

cv2.drawContours(temp_result, [approx], 0, (0, 0, 255), 2)

Result:
如何使用`cv2.minAreaRect`来获取最大的轮廓,即使图像中有破碎的区域?


In case the objective is to find minAreaRect as stated in the title:

<!-- language: lang-python -->

min_rect = cv2.minAreaRect(merged_cnt)  # Fine minAreaRect of the merged contours
box = np.int0(cv2.boxPoints(min_rect))

We are getting the following output:
如何使用`cv2.minAreaRect`来获取最大的轮廓,即使图像中有破碎的区域?

huangapple
  • 本文由 发表于 2023年2月24日 17:09:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/75554594.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定