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]<br>先找出輪廓點
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<opencv2\opencv.hpp>
#include <iostream>
#include<vector>
using namespace cv;
using namespace std;
/**
* @brief expandEdge 擴展邊界函式
* @param img:輸入影像,單通道二值圖,深度為8
* @param edge 邊界陣列,存放4條邊界值
* @param edgeID 當前邊界號
* @return 布林值 確定當前邊界是否可以擴展
*/
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<uchar>(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<uchar>(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<uchar>(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<uchar>(i, edge[3]) == 255)//遇見255像素表明碰到邊緣線
return false;
}
edge[3]--;
return true;
break;
default:
return false;
break;
}
}
/**
* @brief 求取連通區域內接矩
* @param img:輸入影像,單通道二值圖,深度為8
* @param center:最小外接矩的中心
* @return 最大內接矩形
* 基于中心擴展演算法
*/
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\\測驗圖片\\xxx\\20190308152516.jpg",1);
//src = imread("C:\\Users\\Administrator\\Desktop\\測驗圖片\\xx\\20190308151912.jpg",1);
//src = imread("C:\\Users\\Administrator\\Desktop\\測驗影像\\2\\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;
}
原圖和效果圖:


轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/344079.html
標籤:AI
