-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmeasuring_distance.py
More file actions
227 lines (189 loc) · 8.53 KB
/
Copy pathmeasuring_distance.py
File metadata and controls
227 lines (189 loc) · 8.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
import cv2 as cv
import numpy as np
import copy
# 这个程序是测量到二维码的距离,好像也需要改,没有加畸变矫正
# 应该是主程序--Leo
# 第一个版本
log_file_one = open("distance_log.txt","w")
#
# 捕获本地视频,请自行修改自己存放视频的路径
cap = cv.VideoCapture("v3.mp4")
A = True
# 指定VideoWrite 的fourCC视频编码
fourcc = cv.VideoWriter_fourcc(*'DIVX')
# 检查是否导入视频成功
if not cap.isOpened():
print("视频无法打开")
exit()
while True:
# 捕获视频帧,返回ret,frame
# ret的true与false反应是否捕获成功,frame是画面
ret, frame = cap.read()
if not ret:
print("视频播放完毕")
break
def reshape_image(frame):
'''归一化图片尺寸:短边400,长边不超过800,短边400,长边超过800以长边800为主'''
width, height = frame.shape[1], frame.shape[0]
min_len = width
scale = width * 1.0 / 400
new_width = 400
new_height = int(height / scale)
if new_height > 800:
new_height = 800
scale = height * 1.0 / 800
new_width = int(width / scale)
out = cv.resize(frame, (new_width, new_height))
return out
def detecte(frame):
'''提取所有轮廓'''
gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
_, gray = cv.threshold(gray, 0, 255, cv.THRESH_OTSU + cv.THRESH_BINARY_INV)
contours, hierachy = cv.findContours(gray, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
return frame, contours, hierachy
def compute_1(contours, i, j):
'''最外面的轮廓和子轮廓的比例'''
area1 = cv.contourArea(contours[i])
area2 = cv.contourArea(contours[j])
if area2 == 0:
return False
ratio = area1 * 1.0 / area2
if abs(ratio - 49.0 / 25):
return True
return False
def compute_2(contours, i, j):
'''子轮廓和子子轮廓的比例'''
area1 = cv.contourArea(contours[i])
area2 = cv.contourArea(contours[j])
if area2 == 0:
return False
ratio = area1 * 1.0 / area2
if abs(ratio - 25.0 / 9):
return True
return False
def compute_center(contours, i):
'''计算轮廓中心点'''
M = cv.moments(contours[i])
cx = int(M['m10'] / M['m00'])
cy = int(M['m01'] / M['m00'])
return cx, cy
def detect_contours(vec):
'''判断这个轮廓和它的子轮廓以及子子轮廓的中心的间距是否足够小'''
distance_1 = np.sqrt((vec[0] - vec[2]) ** 2 + (vec[1] - vec[3]) ** 2)
distance_2 = np.sqrt((vec[0] - vec[4]) ** 2 + (vec[1] - vec[5]) ** 2)
distance_3 = np.sqrt((vec[2] - vec[4]) ** 2 + (vec[3] - vec[5]) ** 2)
if sum((distance_1, distance_2, distance_3)) / 3 < 3:
return True
return False
def juge_angle(rec):
'''判断寻找是否有三个点可以围成等腰直角三角形'''
if len(rec) < 3:
return -1, -1, -1
for i in range(len(rec)):
for j in range(i + 1, len(rec)):
for k in range(j + 1, len(rec)):
distance_1 = np.sqrt((rec[i][0] - rec[j][0]) ** 2 + (rec[i][1] - rec[j][1]) ** 2)
distance_2 = np.sqrt((rec[i][0] - rec[k][0]) ** 2 + (rec[i][1] - rec[k][1]) ** 2)
distance_3 = np.sqrt((rec[j][0] - rec[k][0]) ** 2 + (rec[j][1] - rec[k][1]) ** 2)
if abs(distance_1 - distance_2) < 5:
if abs(np.sqrt(np.square(distance_1) + np.square(distance_2)) - distance_3) < 5:
return i, j, k
elif abs(distance_1 - distance_3) < 5:
if abs(np.sqrt(np.square(distance_1) + np.square(distance_3)) - distance_2) < 5:
return i, j, k
elif abs(distance_2 - distance_3) < 5:
if abs(np.sqrt(np.square(distance_2) + np.square(distance_3)) - distance_1) < 5:
return i, j, k
return -1, -1, -1
def find(frame, contours, hierachy, root=0):
'''找到符合要求的轮廓'''
rec = []
for i in range(len(hierachy)):
child = hierachy[i][2]
child_child = hierachy[child][2]
if child != -1 and hierachy[child][2] != -1:
if compute_1(contours, i, child) and compute_2(contours, child, child_child):
cx1, cy1 = compute_center(contours, i)
cx2, cy2 = compute_center(contours, child)
cx3, cy3 = compute_center(contours, child_child)
if detect_contours([cx1, cy1, cx2, cy2, cx3, cy3]):
rec.append([cx1, cy1, cx2, cy2, cx3, cy3, i, child, child_child])
'''计算得到所有在比例上符合要求的轮廓中心点'''
i, j, k = juge_angle(rec)
if i == -1 or j == -1 or k == -1:
return
ts = np.concatenate((contours[rec[i][6]], contours[rec[j][6]], contours[rec[k][6]]))
rect = cv.minAreaRect(ts)
box = cv.boxPoints(rect)
box = np.int0(box)
result = copy.deepcopy(frame)
cv.drawContours(result, [box], 0, (0, 0, 255), 3)
cv.drawContours(frame, contours, rec[i][6], (255, 0, 0), 2)
cv.drawContours(frame, contours, rec[j][6], (255, 0, 0), 2)
cv.drawContours(frame, contours, rec[k][6], (255, 0, 0), 2)
# 将处理后的视频逐帧地显示
# cv.namedWindow("frame_window", 0) # 0可调大小,注意:窗口名必须imshow里面的一窗口名一直
# cv.resizeWindow("frame_window", 360, 640) # 设置长和宽
# cv.imshow('frame_window', result)
# 找到目标函数
def find_marker(image):
# 将图像转换为灰度,模糊图像,并检测边缘
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
gray = cv.GaussianBlur(gray, (5, 5), 0)
edged = cv.Canny(gray, 35, 125)
# 在边缘图像中找到轮廓并保留最大的一个;
# 我们将假设这是图像中我们的一张纸
(cnts, _) = cv.findContours(edged.copy(), cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)
# 求最大面积
c = max(cnts, key=cv.contourArea)
# 计算纸张区域的边界框并返回它
# cv2.minAreaRect() c代表点集,返回rect[0]是最小外接矩形中心点坐标,
# rect[1][0]是width,rect[1][1]是height,rect[2]是角度
return cv.minAreaRect(c)
# 距离计算函数
def distance_to_camera(knownWidth, focalLength, perWidth):
# 计算并返回从目标到摄像机的距离
return (knownWidth * focalLength) / perWidth
# 二维码的长和宽(单位:inches)
KNOWN_WIDTH = 3.5
KNOWN_HEIGHT = 3.5
# 焦距
focalLength = 123.7
marker = find_marker(result)
DISTANCE = distance_to_camera(KNOWN_WIDTH, focalLength, marker[1][0])
# print(DISTANCE * 2.54)
log_file_one.write(f"Detected distance: {DISTANCE * 2.54 + 14.8:.2f}cm\n")
with open("distance_log_two.txt","a") as log_file_two:
log_file_two.write(f"Detected distance: {DISTANCE * 2.54 + 14.8:.2f}cm\n")
# inches 转换为 cm
cv.putText(result, "%.2fcm" % (DISTANCE * 2.54+14.8),
(result.shape[1] - 400, result.shape[0] - 400), cv.FONT_HERSHEY_SIMPLEX,
2.0, (0, 255, 0), 3)
# 显示图片
cv.imshow("frame_window", result)
# cv.waitKey(0)
return
frame = reshape_image(frame)
# cv.waitKey(0)
frame, contours, hierachy = detecte(frame)
find(frame, contours, np.squeeze(hierachy))
# 获取按键动作,如果按下q,则退出循环
# 25毫秒是恰好的,如果太小,播放速度会很快,如果太大,播放速度会很慢
if cv.waitKey(25) == ord('q'):
break
pass
if A is True:
# 读取二维码
gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
# 设置检测器
qrcoder = cv.QRCodeDetector()
# retval, points
# 检测识别二维码
codeinfo, points, straight_qrcode = qrcoder.detectAndDecode(gray)
result = np.copy(frame)
cv.drawContours(result, [np.int32(points)], 0, (0, 0, 255), 2)
# 输出识别二维码的信息
print("二维码内容为 : \n%s" % codeinfo)
A = False
cap.release()
cv.destroyAllWindows()