测量梯形OpenCV的中心宽度
measure center width of Trapezoid OpenCV
我正在尝试测量以下梯形的中心宽度 (w3),但没有成功。
无论如何我可以测量这个吗?
目前我可以测量中心点并打印每个轮廓点。
这是我的代码:
Mat gray;
cvtColor(inputImage, gray, CV_BGR2GRAY);
cv::findContours(gray, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_NONE);
vector<Moments>mu(contours.size());
for(int i=0; i < contours.size(); i++)
{
mu[i] = moments(contours[i],false);
}
vector<Point2f>mc(contours.size());
for(int i=0; i < contours.size(); i++)
{
mc[i] = Point2f(mu[i].m10/mu[i].m00, mu[i].m01/mu[i].m00);
//cout << mu[i].m01/mu[i].m00 <<endl;
for(size_t cP=0; cP < contours[i].size(); cP++)
{
cv::Point currentContourPixel = contours[i][cP];
//cout <<currentContourPixel<<endl;
}
}
trapezoid
这可以通过使用初等数学函数来完成。
正确准备图像(colospace 转换、阈值...)并搜索轮廓,然后 select 梯形。
计算最高点和最低点。
梯形每边(a, b, c, d)各做4个表,临时(b+d)做一个表
遍历轮廓并附加到 a、c 和临时 b+d。 a 中的点应具有与最低点 y 轴相同的 y 轴。 c 中的点应具有与最高点 y 轴相同的 y 轴。 b+d 中的点应具有所有其他点。
按 x 轴从小到大对 a 和 c 进行排序。
遍历 b+d 并追加 b 和 d。 d 中的点应与 c 中的第一个元素具有相同或更小的 x 轴。 b 中的点应与 c 中的最后一个元素具有相同或更大的 x 轴。
计算所有边的中点。每边中点的公式 X,Y = ((x2+x1)/2, (y2+y1)/2)
你的宽度等于d的中点到b的中点之间的距离。两点距离公式sqrt((x2-x1)^2 + (y2-y1)^2)
.
我在Python中做了一个例子(我不知道C++语法)但是它应该很容易翻译成C++。希望能有所帮助。干杯!
示例:
import cv2
import numpy as np
# Read the image
img = cv2.imread('trapez.png')
# Transform to gray colorspace and invert Otsu threshold the image
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
# Search for contours and select the biggest
_, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt = max(contours, key=cv2.contourArea)
# Calclate the higest and lowest point
top = tuple(cnt[cnt[:, :, 1].argmin()][0])
bottom = tuple(cnt[cnt[:, :, 1].argmax()][0])
# Make 4 lists for every side of trapezoid and one for temporary bd
a = []
b = []
c = []
d = []
bd_temp = []
# Iterate through contour and append to a, c and temporary list
## Points in a should have the same y axis as the lowest point y axis
## Points in c should have the same y axis as the highest point y axis
## Temporary should have all others (b and d)
for i in cnt:
if i[0][1] == top[1]:
c.append(tuple(i[0]))
if i[0][1] == bottom[1]:
a.append(tuple(i[0]))
else:
bd_temp.append(tuple(i[0]))
# Sort a and c by their x axis - smallest to biggest
a.sort(key = lambda x: x[0])
c.sort(key = lambda x: x[0])
# Itterate through bd_temp and append b and d
## Points in d should have the same or smaller x axis as the first element in c
## Points in b should have the same or bigger x axis as the last element in c
for i in bd_temp:
if i[0] <= c[0][0]:
d.append(i)
if i[0] >= c[-1][0]:
b.append(i)
# Sort b and d by their x axis - smallest to biggest
b.sort(key = lambda x: x[1])
d.sort(key = lambda x: x[1])
# Calculate middle points for all sides ((x2+x1)/2, (y2+y1)/2)
half_line_a = tuple([int((a[0][0]+a[-1][0])/2), int((a[0][1]+a[-1][1])/2)])
half_line_c = tuple([int((c[0][0]+c[-1][0])/2), int((c[0][1]+c[-1][1])/2)])
half_line_b = tuple([int((b[0][0]+b[-1][0])/2), int((b[0][1]+b[-1][1])/2)])
half_line_d = tuple([int((d[0][0]+d[-1][0])/2), int((d[0][1]+d[-1][1])/2)])
# Optional integers for calculating the width
x2 = half_line_b[0]
x1 = half_line_d[0]
y2 = half_line_b[1]
y1 = half_line_d[1]
# Width equals to distance between middle point of d to middle point of b
## Formula for distance between two points sqrt((x2-x1)^2 + (y2-y1)^2)
width = np.sqrt(((x2-x1)**2)+((y2-y2)**2))
center = tuple([half_line_c[0], y1])
# Optional drawing on the image
cv2.arrowedLine(img, half_line_b, half_line_d, (0,0,255), 1)
cv2.arrowedLine(img, half_line_d, half_line_b, (0,0,255), 1)
cv2.circle(img, center, 2, (255,0,0), -1)
cv2.putText(img,'Width = '+str(width),(20,20), cv2.FONT_HERSHEY_SIMPLEX, 0.5,(0,0,0),1,cv2.LINE_AA)
# Display the image
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果:
我正在尝试测量以下梯形的中心宽度 (w3),但没有成功。
无论如何我可以测量这个吗?
目前我可以测量中心点并打印每个轮廓点。
这是我的代码:
Mat gray;
cvtColor(inputImage, gray, CV_BGR2GRAY);
cv::findContours(gray, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_NONE);
vector<Moments>mu(contours.size());
for(int i=0; i < contours.size(); i++)
{
mu[i] = moments(contours[i],false);
}
vector<Point2f>mc(contours.size());
for(int i=0; i < contours.size(); i++)
{
mc[i] = Point2f(mu[i].m10/mu[i].m00, mu[i].m01/mu[i].m00);
//cout << mu[i].m01/mu[i].m00 <<endl;
for(size_t cP=0; cP < contours[i].size(); cP++)
{
cv::Point currentContourPixel = contours[i][cP];
//cout <<currentContourPixel<<endl;
}
}
trapezoid
这可以通过使用初等数学函数来完成。
正确准备图像(colospace 转换、阈值...)并搜索轮廓,然后 select 梯形。
计算最高点和最低点。
梯形每边(a, b, c, d)各做4个表,临时(b+d)做一个表
遍历轮廓并附加到 a、c 和临时 b+d。 a 中的点应具有与最低点 y 轴相同的 y 轴。 c 中的点应具有与最高点 y 轴相同的 y 轴。 b+d 中的点应具有所有其他点。
按 x 轴从小到大对 a 和 c 进行排序。
遍历 b+d 并追加 b 和 d。 d 中的点应与 c 中的第一个元素具有相同或更小的 x 轴。 b 中的点应与 c 中的最后一个元素具有相同或更大的 x 轴。
计算所有边的中点。每边中点的公式
X,Y = ((x2+x1)/2, (y2+y1)/2)
你的宽度等于d的中点到b的中点之间的距离。两点距离公式
sqrt((x2-x1)^2 + (y2-y1)^2)
.
我在Python中做了一个例子(我不知道C++语法)但是它应该很容易翻译成C++。希望能有所帮助。干杯!
示例:
import cv2
import numpy as np
# Read the image
img = cv2.imread('trapez.png')
# Transform to gray colorspace and invert Otsu threshold the image
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
# Search for contours and select the biggest
_, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt = max(contours, key=cv2.contourArea)
# Calclate the higest and lowest point
top = tuple(cnt[cnt[:, :, 1].argmin()][0])
bottom = tuple(cnt[cnt[:, :, 1].argmax()][0])
# Make 4 lists for every side of trapezoid and one for temporary bd
a = []
b = []
c = []
d = []
bd_temp = []
# Iterate through contour and append to a, c and temporary list
## Points in a should have the same y axis as the lowest point y axis
## Points in c should have the same y axis as the highest point y axis
## Temporary should have all others (b and d)
for i in cnt:
if i[0][1] == top[1]:
c.append(tuple(i[0]))
if i[0][1] == bottom[1]:
a.append(tuple(i[0]))
else:
bd_temp.append(tuple(i[0]))
# Sort a and c by their x axis - smallest to biggest
a.sort(key = lambda x: x[0])
c.sort(key = lambda x: x[0])
# Itterate through bd_temp and append b and d
## Points in d should have the same or smaller x axis as the first element in c
## Points in b should have the same or bigger x axis as the last element in c
for i in bd_temp:
if i[0] <= c[0][0]:
d.append(i)
if i[0] >= c[-1][0]:
b.append(i)
# Sort b and d by their x axis - smallest to biggest
b.sort(key = lambda x: x[1])
d.sort(key = lambda x: x[1])
# Calculate middle points for all sides ((x2+x1)/2, (y2+y1)/2)
half_line_a = tuple([int((a[0][0]+a[-1][0])/2), int((a[0][1]+a[-1][1])/2)])
half_line_c = tuple([int((c[0][0]+c[-1][0])/2), int((c[0][1]+c[-1][1])/2)])
half_line_b = tuple([int((b[0][0]+b[-1][0])/2), int((b[0][1]+b[-1][1])/2)])
half_line_d = tuple([int((d[0][0]+d[-1][0])/2), int((d[0][1]+d[-1][1])/2)])
# Optional integers for calculating the width
x2 = half_line_b[0]
x1 = half_line_d[0]
y2 = half_line_b[1]
y1 = half_line_d[1]
# Width equals to distance between middle point of d to middle point of b
## Formula for distance between two points sqrt((x2-x1)^2 + (y2-y1)^2)
width = np.sqrt(((x2-x1)**2)+((y2-y2)**2))
center = tuple([half_line_c[0], y1])
# Optional drawing on the image
cv2.arrowedLine(img, half_line_b, half_line_d, (0,0,255), 1)
cv2.arrowedLine(img, half_line_d, half_line_b, (0,0,255), 1)
cv2.circle(img, center, 2, (255,0,0), -1)
cv2.putText(img,'Width = '+str(width),(20,20), cv2.FONT_HERSHEY_SIMPLEX, 0.5,(0,0,0),1,cv2.LINE_AA)
# Display the image
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果: