python 最小外接矩形:
cnt = np.array([[data_0_x, data_0_y], [data_1_x, data_1_y], [data_2_x, data_2_y], [data_3_x, data_3_y]]) # 必须是array数组的形式 rect = cv2.minAreaRect(cnt) # 得到最小外接矩形的(中心(x,y), (宽,高), 旋转角度) box = cv2.boxPoints(rect) # 获取最小外接矩形的4个顶点坐标(ps: cv2.boxPoints(rect) for OpenCV 3.x) box = np.int0(box) cv2.drawContours(img, [box], 0, (255, 0, 0), 1)
最大内接矩形,从轮廓中所有坐标中获取其中4个坐标即可:
python 获取过程如下:
转自:图像轮廓最大内接矩形的求法 - 奥布莱恩 - 博客园
def order_points(pts): # pts为轮廓坐标 # 列表中存储元素分别为左上角,右上角,右下角和左下角 rect = np.zeros((4, 2), dtype = "float32") # 左上角的点具有最小的和,而右下角的点具有最大的和 s = pts.sum(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 img = cv2.imread(path) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) blurred = cv2.blur(gray, (9, 9)) _, thresh = cv2.threshold(blurred, 155, 255, cv2.THRESH_BINARY) _, cnts, _ = cv2.findContours( thresh.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) c = sorted(cnts, key=cv2.contourArea, reverse=True)[0]
先找出轮廓点 rect = order_points(c.reshape(c.shape[0], 2)) print(rect) xs = [i[0] for i in rect] ys = [i[1] for i in rect] xs.sort() ys.sort() #内接矩形的坐标为 print(xs[1],xs[2],ys[1],ys[2])
一下内容转自:
python-opencv 图像捕捉多个不规则轮廓,与轮廓内接区域(圆/矩形)思路-持续更新编辑中(会附上详细的思路解释和图片) - Lorzen - 博客园
def drawInRectgle(img, cont, cX, cY, x_min, x_max, y_min, y_max): """绘制不规则最大内接正矩形""" # img 对应的是原图, 四个极值坐标对应的是最大外接矩形的四个顶点 c = cont # 单个轮廓 # print(c) range_x, range_y = x_max - x_min, y_max - y_min # 轮廓的X,Y的范围 x1, x2, y1, y2 = cX, cX, cY, cY # 中心扩散矩形的四个顶点x,y cnt_range, radio = 0, 0 shape_flag = 1 # 1:轮廓X轴方向比Y长;0:轮廓Y轴方向比X长 if range_x > range_y: # 判断轮廓 X方向更长 radio, shape_flag = int(range_x / range_y), 1 range_x_left = cX - x_min range_x_right = x_max - cX if range_x_left >= range_x_right: # 取轴更长范围作for循环 cnt_range = int(range_x_left) if range_x_left < range_x_right: cnt_range = int(range_x_right) else: # 判断轮廓 Y方向更长 radio, shape_flag = int(range_y / range_x), 0 range_y_top = cY - y_min range_y_bottom = y_max - cY if range_y_top >= range_y_bottom: # 取轴更长范围作for循环 cnt_range = int(range_y_top) if range_y_top < range_y_bottom: cnt_range = int(range_y_bottom) print("X radio Y: %d " % radio) print("---------new drawing range: %d-------------------------------------" % cnt_range) flag_x1, flag_x2, flag_y1, flag_y2 = False, False, False, False radio = 5 # 暂时设5,统一比例X:Y=5:1 因为发现某些会出现X:Y=4:1, 某些会出现X:Y=5:1 if shape_flag == 1: radio_x = radio - 1 radio_y = 1 else: radio_x = 1 radio_y = radio - 1 for ix in range(1, cnt_range, 1): # X方向延展,假设X:Y=3:1,那延展步进值X:Y=3:1 # 第二象限延展 if flag_y1 == False: y1 -= 1 * radio_y # 假设X:Y=1:1,轮廓XY方向长度接近,可理解为延展步进X:Y=1:1 p_x1y1 = cv.pointPolygonTest(c, (x1, y1), False) p_x2y1 = cv.pointPolygonTest(c, (x2, y1), False) if p_x1y1 <= 0 or y1 <= y_min or p_x2y1 <= 0: # 在轮廓外,只进行y运算,说明y超出范围 for count in range(0, radio_y - 1, 1): # 最长返回步进延展 y1 += 1 # y超出, 步进返回 p_x1y1 = cv.pointPolygonTest(c, (x1, y1), False) if p_x1y1 <= 0 or y1 <= y_min or p_x2y1 <= 0: pass else: break # print("y1 = %d, P=%d" % (y1, p_x1y1)) flag_y1 = True if flag_x1 == False: x1 -= 1 * radio_x p_x1y1 = cv.pointPolygonTest(c, (x1, y1), False) # 满足第二象限的要求,像素都在轮廓内 p_x1y2 = cv.pointPolygonTest(c, (x1, y2), False) # 满足第三象限的要求,像素都在轮廓内 if p_x1y1 <= 0 or x1 <= x_min or p_x1y2 <= 0: # 若X超出轮廓范围 # x1 += 1 # x超出, 返回原点 for count in range(0, radio_x-1, 1): # x1 += 1 # x超出, 步进返回 p_x1y1 = cv.pointPolygonTest(c, (x1, y1), False) # 满足第二象限的要求,像素都在轮廓内 p_x1y2 = cv.pointPolygonTest(c, (x1, y2), False) # 满足第三象限的要求,像素都在轮廓内 if p_x1y1 <= 0 or x1 <= x_min or p_x1y2 <= 0: pass else: break # print("x1 = %d, P=%d" % (x1, p_x1y1)) flag_x1 = True # X轴像左延展达到轮廓边界,标志=True # 第三象限延展 if flag_y2 == False: y2 += 1 * radio_y p_x1y2 = cv.pointPolygonTest(c, (x1, y2), False) p_x2y2 = cv.pointPolygonTest(c, (x2, y2), False) if p_x1y2 <= 0 or y2 >= y_max or p_x2y2 <= 0: # 在轮廓外,只进行y运算,说明y超出范围 for count in range(0, radio_y - 1, 1): # 最长返回步进延展 y2 -= 1 # y超出, 返回原点 p_x1y2 = cv.pointPolygonTest(c, (x1, y2), False) if p_x1y2 <= 0 or y2 >= y_max or p_x2y2 <= 0: # 在轮廓外,只进行y运算,说明y超出范围 pass else: break # print("y2 = %d, P=%d" % (y2, p_x1y2)) flag_y2 = True # Y轴像左延展达到轮廓边界,标志=True # 第一象限延展 if flag_x2 == False: x2 += 1 * radio_x p_x2y1 = cv.pointPolygonTest(c, (x2, y1), False) # 满足第一象限的要求,像素都在轮廓内 p_x2y2 = cv.pointPolygonTest(c, (x2, y2), False) # 满足第四象限的要求,像素都在轮廓内 if p_x2y1 <= 0 or x2 >= x_max or p_x2y2 <= 0: for count in range(0, radio_x - 1, 1): # 最长返回步进延展 x2 -= 1 # x超出, 返回原点 p_x2y1 = cv.pointPolygonTest(c, (x2, y1), False) # 满足第一象限的要求,像素都在轮廓内 p_x2y2 = cv.pointPolygonTest(c, (x2, y2), False) # 满足第四象限的要求,像素都在轮廓内 if p_x2y1 <= 0 or x2 >= x_max or p_x2y2 <= 0: pass elif p_x2y2 > 0: break # print("x2 = %d, P=%d" % (x2, p_x2y1)) flag_x2 = True if flag_y1 and flag_x1 and flag_y2 and flag_x2: print("(x1,y1)=(%d,%d)" % (x1, y1)) print("(x2,y2)=(%d,%d)" % (x2, y2)) break # cv.line(img, (x1,y1), (x2,y1), (255, 0, 0)) cv.rectangle(img, (x1, y1), (x2, y2), (255, 255, 255), 1, 8) return x1, x2, y1, y2
c++版
OpenCVSharp 小练习 最大内接矩形_tfarcraw的博客-CSDN博客
opencv:求区域的内接矩形_cfqcfqcfqcfqcfq的博客-CSDN博客_opencv 内接矩形
#include#include #include using namespace cv; using namespace std; bool expandEdge(const Mat & img, int edge[], const int edgeID) { //[1] --初始化参数 int nc = img.cols; int nr = img.rows; switch (edgeID) { case 0: if (edge[0]>nr) return false; for (int i = edge[3]; i <= edge[1]; ++i) { if (img.at (edge[0], i) == 255)//遇见255像素表明碰到边缘线 return false; } edge[0]++; return true; break; case 1: if (edge[1]>nc) return false; for (int i = edge[2]; i <= edge[0]; ++i) { if (img.at (i, edge[1]) == 255)//遇见255像素表明碰到边缘线 return false; } edge[1]++; return true; break; case 2: if (edge[2]<0) return false; for (int i = edge[3]; i <= edge[1]; ++i) { if (img.at (edge[2], i) == 255)//遇见255像素表明碰到边缘线 return false; } edge[2]--; return true; break; case 3: if (edge[3]<0) return false; for (int i = edge[2]; i <= edge[0]; ++i) { if (img.at (i, edge[3]) == 255)//遇见255像素表明碰到边缘线 return false; } edge[3]--; return true; break; default: return false; break; } } cv::Rect InSquare(Mat &img, const Point center) { // --[1]参数检测 if (img.empty() ||img.channels()>1|| img.depth()>8) return Rect(); // --[2] 初始化变量 int edge[4]; edge[0] = center.y + 1;//top edge[1] = center.x + 1;//right edge[2] = center.y - 1;//bottom edge[3] = center.x - 1;//left //[2] // --[3]边界扩展(中心扩散法) bool EXPAND[4] = { 1,1,1,1 };//扩展标记位 int n = 0; while (EXPAND[0] || EXPAND[1] || EXPAND[2] || EXPAND[3]) { int edgeID = n % 4; EXPAND[edgeID] = expandEdge(img, edge, edgeID); n++; } //[3] //qDebug() << edge[0] << edge[1] << edge[2] << edge[3]; Point tl = Point(edge[3], edge[0]); Point br = Point(edge[1], edge[2]); return Rect(tl, br); } int main() { bool isExistence = false; float first_area = 0; /// 加载源图像 Mat src; src = imread("cen.bmp", 1); //src = imread("C:\Users\Administrator\Desktop\测试图片\xxx190308152516.jpg",1); //src = imread("C:\Users\Administrator\Desktop\测试图片\xx190308151912.jpg",1); //src = imread("C:\Users\Administrator\Desktop\测试图像\BfImg17(x-247 y--91 z--666)-(492,280).jpg",1); cvtColor(src, src, CV_RGB2GRAY); threshold(src, src, 100, 255, THRESH_BINARY); Rect ccomp; Point center(src.cols / 2, src.rows / 2); //floodFill(src, center, Scalar(255, 255, 55), &ccomp, Scalar(20, 20, 20), Scalar(20, 20, 20)); if (src.empty()) { cout << "fali" << endl; } //resize(src, src, cv::Size(496, 460), cv::INTER_LINEAR); imshow("src", src); Rect rr = InSquare(src, center); rectangle(src, rr, Scalar(255), 1, 8); imshow("src2", src); waitKey(0); getchar(); return 0; }
原图和效果图:
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)