如何用cv2.minAreaRect获取存在断裂区域图像的最大轮廓?
问题描述
原始图像:
希望用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)
解决方案
核心问题分析
- 尝试1直接取了第一个轮廓
cnt[0],但该轮廓并非图像中面积最大的目标轮廓; - 尝试2误用了透视变换的点排序逻辑,
cv2.minAreaRect需要传入完整的轮廓数据,而非零散点集。
正确实现步骤
方法1:从二值图像中提取最大轮廓并绘制最小外接矩形
import cv2 import numpy as np # 假设im_bw是你的二值图像,temp_result是用于绘制的彩色/灰度图像 cnt, hierarchy = cv2.findContours(im_bw, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 筛选出面积最大的轮廓 max_contour = max(cnt, key=cv2.contourArea) # 计算最小外接矩形 min_rect = cv2.minAreaRect(max_contour) # 将矩形的四个角点转换为整数格式 box = np.int0(cv2.boxPoints(min_rect)) # 在结果图上绘制矩形 cv2.drawContours(temp_result, [box], 0, (255, 0, 0), 2)
方法2:针对零散点集生成最小外接矩形
如果你的输入是类似尝试2中的零散点列表,需要先将其转换为OpenCV轮廓的格式(形状为(N,1,2)的numpy数组),再传入cv2.minAreaRect:
import cv2 import numpy as np # 你的零散点列表 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)] # 转换为OpenCV接受的轮廓格式 pts_contour = np.array(pts, dtype=np.int32).reshape((-1, 1, 2)) # 计算并绘制最小外接矩形 min_rect = cv2.minAreaRect(pts_contour) box = np.int0(cv2.boxPoints(min_rect)) cv2.drawContours(temp_result, [box], 0, (0, 0, 255), 2)
内容的提问来源于stack exchange,提问作者Creek
相关产品推荐
相关产品推荐

