-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathcalibration.py
391 lines (323 loc) · 15 KB
/
calibration.py
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
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
import threading
import time
import cv2
import numpy as np
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtGui import QPixmap, QImage, QTextCursor
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QVBoxLayout, QHBoxLayout, QTextEdit, QGridLayout
import sys
# 海康相机图像获取线程
def hik_camera_get():
# 获得设备信息
global camera_image
deviceList = MV_CC_DEVICE_INFO_LIST()
tlayerType = MV_GIGE_DEVICE | MV_USB_DEVICE
# ch:枚举设备 | en:Enum device
# nTLayerType [IN] 枚举传输层 ,pstDevList [OUT] 设备列表
while 1:
ret = MvCamera.MV_CC_EnumDevices(tlayerType, deviceList)
if ret != 0:
print("enum devices fail! ret[0x%x]" % ret)
# sys.exit()
if deviceList.nDeviceNum == 0:
print("find no device!")
# sys.exit()
else:
print("Find %d devices!" % deviceList.nDeviceNum)
break
for i in range(0, deviceList.nDeviceNum):
mvcc_dev_info = cast(deviceList.pDeviceInfo[i], POINTER(MV_CC_DEVICE_INFO)).contents
if mvcc_dev_info.nTLayerType == MV_GIGE_DEVICE:
print("\ngige device: [%d]" % i)
# 输出设备名字
strModeName = ""
for per in mvcc_dev_info.SpecialInfo.stGigEInfo.chModelName:
strModeName = strModeName + chr(per)
print("device model name: %s" % strModeName)
# 输出设备ID
nip1 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0xff000000) >> 24)
nip2 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0x00ff0000) >> 16)
nip3 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0x0000ff00) >> 8)
nip4 = (mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0x000000ff)
print("current ip: %d.%d.%d.%d\n" % (nip1, nip2, nip3, nip4))
# 输出USB接口的信息
elif mvcc_dev_info.nTLayerType == MV_USB_DEVICE:
print("\nu3v device: [%d]" % i)
strModeName = ""
for per in mvcc_dev_info.SpecialInfo.stUsb3VInfo.chModelName:
if per == 0:
break
strModeName = strModeName + chr(per)
print("device model name: %s" % strModeName)
strSerialNumber = ""
for per in mvcc_dev_info.SpecialInfo.stUsb3VInfo.chSerialNumber:
if per == 0:
break
strSerialNumber = strSerialNumber + chr(per)
print("user serial number: %s" % strSerialNumber)
# 手动选择设备
# nConnectionNum = input("please input the number of the device to connect:")
# 自动选择设备
nConnectionNum = '0'
if int(nConnectionNum) >= deviceList.nDeviceNum:
print("intput error!")
sys.exit()
# ch:创建相机实例 | en:Creat Camera Object
cam = MvCamera()
# ch:选择设备并创建句柄 | en:Select device and create handle
# cast(typ, val),这个函数是为了检查val变量是typ类型的,但是这个cast函数不做检查,直接返回val
stDeviceList = cast(deviceList.pDeviceInfo[int(nConnectionNum)], POINTER(MV_CC_DEVICE_INFO)).contents
ret = cam.MV_CC_CreateHandle(stDeviceList)
if ret != 0:
print("create handle fail! ret[0x%x]" % ret)
sys.exit()
# ch:打开设备 | en:Open device
ret = cam.MV_CC_OpenDevice(MV_ACCESS_Exclusive, 0)
if ret != 0:
print("open device fail! ret[0x%x]" % ret)
sys.exit()
print(get_Value(cam, param_type="float_value", node_name="ExposureTime"),
get_Value(cam, param_type="float_value", node_name="Gain"),
get_Value(cam, param_type="enum_value", node_name="TriggerMode"),
get_Value(cam, param_type="float_value", node_name="AcquisitionFrameRate"))
# 设置设备的一些参数
set_Value(cam, param_type="float_value", node_name="ExposureTime", node_value=16000) # 曝光时间
set_Value(cam, param_type="float_value", node_name="Gain", node_value=17.9) # 增益值
# 开启设备取流
start_grab_and_get_data_size(cam)
# 主动取流方式抓取图像
stParam = MVCC_INTVALUE_EX()
memset(byref(stParam), 0, sizeof(MVCC_INTVALUE_EX))
ret = cam.MV_CC_GetIntValueEx("PayloadSize", stParam)
if ret != 0:
print("get payload size fail! ret[0x%x]" % ret)
sys.exit()
nDataSize = stParam.nCurValue
pData = (c_ubyte * nDataSize)()
stFrameInfo = MV_FRAME_OUT_INFO_EX()
memset(byref(stFrameInfo), 0, sizeof(stFrameInfo))
while True:
ret = cam.MV_CC_GetOneFrameTimeout(pData, nDataSize, stFrameInfo, 1000)
if ret == 0:
image = np.asarray(pData)
# 处理海康相机的图像格式为OPENCV处理的格式
camera_image = image_control(data=image, stFrameInfo=stFrameInfo)
else:
print("no data[0x%x]" % ret)
def video_capture_get():
global camera_image
cam = cv2.VideoCapture(1)
while True:
ret, img = cam.read()
if ret:
camera_image = img
time.sleep(0.016) # 60fps
color = [(255, 255, 255), (0, 255, 0), (0, 0, 255)]
class MyUI(QWidget):
def __init__(self):
super().__init__()
self.capturing = True
self.initUI()
def initUI(self):
# 左上角部分
self.state = state
self.left_top_label = QLabel(self)
self.left_top_label.setFixedSize(1350, 1000)
self.left_top_label.setStyleSheet("border: 2px solid black;")
self.left_top_label.mousePressEvent = self.left_top_clicked
self.image_points = [[(0, 0), (0, 0), (0, 0), (0, 0)], [(0, 0), (0, 0), (0, 0), (0, 0)],
[(0, 0), (0, 0), (0, 0), (0, 0)], [(0, 0), (0, 0), (0, 0), (0, 0)]]
self.map_points = [[(0, 0), (0, 0), (0, 0), (0, 0)], [(0, 0), (0, 0), (0, 0), (0, 0)],
[(0, 0), (0, 0), (0, 0), (0, 0)], [(0, 0), (0, 0), (0, 0), (0, 0)]]
self.image_count = 0
self.map_count = 0
# 右上角部分
self.right_top_label = QLabel(self)
self.right_top_label.setFixedSize(550, 900)
self.right_top_label.setStyleSheet("border: 2px solid black;")
self.right_top_label.mousePressEvent = self.right_top_clicked
# 左下角部分
self.left_bottom_text = QTextEdit(self)
self.left_bottom_text.setFixedSize(300, 60)
# 右下角部分
self.button1 = QPushButton('开始标定', self)
self.button1.setFixedSize(100, 30)
self.button1.clicked.connect(self.button1_clicked)
self.button2 = QPushButton('切换高度', self)
self.button2.setFixedSize(100, 30)
self.button2.clicked.connect(self.button2_clicked)
self.button3 = QPushButton('加载坐标', self)
self.button3.setFixedSize(100, 30)
self.button3.clicked.connect(self.button3_clicked)
self.button4 = QPushButton('保存计算', self)
self.button4.setFixedSize(100, 30)
self.button4.clicked.connect(self.button4_clicked)
self.height = 0
self.T = []
if self.state == 'R':
self.save_path = 'arrays_test_red.npy'
right_image_path = "images/map_red.jpg" # 替换为右边图片的路径
else:
self.save_path = 'arrays_test_blue.npy'
right_image_path = "images/map_blue.jpg" # 替换为右边图片的路径
# _,left_image = self.camera_capture.read()
left_image = camera_image
right_image = cv2.imread(right_image_path)
# 记录缩放比例
self.left_scale_x = left_image.shape[1] / 1350.0
self.left_scale_y = left_image.shape[0] / 1000.0
self.right_scale_x = right_image.shape[1] / 550.0
self.right_scale_y = right_image.shape[0] / 900.0
left_image = cv2.cvtColor(left_image, cv2.COLOR_BGR2RGB)
self.left_image = cv2.resize(left_image, (1350, 1000))
right_image = cv2.cvtColor(right_image, cv2.COLOR_BGR2RGB)
self.right_image = cv2.resize(right_image, (550, 900))
# 缩放图像
self.update_images()
self.camera_timer = QTimer(self)
self.camera_timer.timeout.connect(self.update_camera)
self.camera_timer.start(50) # 50毫秒更新一次相机
# 设置按钮样式
self.set_button_style(self.button1)
self.set_button_style(self.button2)
self.set_button_style(self.button3)
self.set_button_style(self.button4)
grid_layout = QGridLayout()
grid_layout.addWidget(self.button1, 0, 0)
grid_layout.addWidget(self.button2, 0, 1)
grid_layout.addWidget(self.button3, 1, 0)
grid_layout.addWidget(self.button4, 1, 1)
buttons_and_text_widget = QWidget()
hbox_buttons_and_text = QHBoxLayout(buttons_and_text_widget)
hbox_buttons_and_text.addLayout(grid_layout)
hbox_buttons_and_text.addWidget(self.left_bottom_text)
vbox_left = QVBoxLayout()
vbox_left.addWidget(self.left_top_label)
vbox_right = QVBoxLayout()
vbox_right.addWidget(self.right_top_label)
vbox_right.addWidget(buttons_and_text_widget)
hbox = QHBoxLayout()
hbox.addLayout(vbox_left)
hbox.addLayout(vbox_right)
self.setLayout(hbox)
self.setGeometry(0, 0, 1900, 1000)
self.setWindowTitle('Calibration UI')
self.setWindowFlags(Qt.FramelessWindowHint)
self.show()
def keyPressEvent(self, event):
# 按下键盘事件
if event.key() == Qt.Key_Escape:
self.close()
def update_images(self):
left_pixmap = self.convert_cvimage_to_pixmap(self.left_image)
self.left_top_label.setPixmap(left_pixmap)
right_pixmap = self.convert_cvimage_to_pixmap(self.right_image)
self.right_top_label.setPixmap(right_pixmap)
def update_camera(self):
if self.capturing:
img0 = camera_image
left_image = cv2.cvtColor(img0, cv2.COLOR_BGR2RGB)
self.left_image = cv2.resize(left_image, (1350, 1000))
self.update_images()
def left_top_clicked(self, event):
# 图像点击事件
if not self.capturing:
x = int(event.pos().x() * self.left_scale_x)
y = int(event.pos().y() * self.left_scale_y)
self.image_points[self.height][self.image_count % 4] = (x, y)
cv2.circle(self.left_image, (int(x / self.left_scale_x), int(y / self.left_scale_y)), 4, color[self.height],
-1)
cv2.putText(self.left_image, str(self.image_count % 4),
(int(x / self.left_scale_x), int(y / self.left_scale_y)), cv2.FONT_HERSHEY_SIMPLEX, 1,
color[self.height], 3)
self.image_count += 1
self.update_images()
self.append_text(f'图像真实点击坐标:({x}, {y})')
def right_top_clicked(self, event):
# 地图点击事件
if not self.capturing:
x = int(event.pos().x() * self.right_scale_x)
y = int(event.pos().y() * self.right_scale_y)
self.map_points[self.height][self.map_count % 4] = (x, y)
cv2.circle(self.right_image, (int(x / self.right_scale_x), int(y / self.right_scale_y)), 4,
color[self.height],
-1)
cv2.putText(self.right_image, str(self.map_count % 4),
(int(x / self.right_scale_x), int(y / self.right_scale_y)), cv2.FONT_HERSHEY_SIMPLEX, 1,
color[self.height], 2)
self.map_count += 1
self.update_images()
self.append_text(f'地图真实点击坐标:({x}, {y})')
def button1_clicked(self):
# 按钮1点击事件
self.append_text('开始标定')
self.capturing = False
print('开始标定')
def button2_clicked(self):
# 按钮2点击事件
self.append_text('切换高度')
self.image_count = 0
self.map_count = 0
self.height = (self.height + 1) % 3
print('切换高度')
def button3_clicked(self):
# 按钮3点击事件
self.append_text('加载坐标') # 该功能还未制作
print('加载坐标')
def button4_clicked(self):
# 按钮4点击事件
print(self.image_points)
print(self.map_points)
for i in range(0, 3):
image_point = np.array(self.image_points[i], dtype=np.float32)
map_point = np.array(self.map_points[i], dtype=np.float32)
self.T.append(cv2.getPerspectiveTransform(image_point, map_point))
np.save(self.save_path, self.T)
self.append_text('保存计算')
print('保存计算', self.save_path)
time.sleep(1)
sys.exit()
def convert_cvimage_to_pixmap(self, cvimage):
height, width, channel = cvimage.shape
bytes_per_line = 3 * width
qimage = QImage(cvimage.data, width, height, bytes_per_line, QImage.Format_RGB888)
pixmap = QPixmap.fromImage(qimage)
return pixmap
def set_button_style(self, button):
button.setStyleSheet("QPushButton { font-size: 18px; }")
def append_text(self, text):
# 在文本组件中追加文本
current_text = self.left_bottom_text.toPlainText()
self.left_bottom_text.setPlainText(current_text + '\n' + text)
# 自动向下滚动文本组件
cursor = self.left_bottom_text.textCursor()
cursor.movePosition(QTextCursor.End)
self.left_bottom_text.setTextCursor(cursor)
if __name__ == '__main__':
camera_mode = 'hik' # 'test':测试模式,'hik':海康相机,'video':USB相机(videocapture)
camera_image = None
state = 'B' # R:红方/B:蓝方
if camera_mode == 'test':
camera_image = cv2.imread('images/test_image.jpg')
elif camera_mode == 'hik':
# 海康相机图像获取线程
from hik_camera import call_back_get_image, start_grab_and_get_data_size, close_and_destroy_device, set_Value, \
get_Value, image_control
if sys.platform.startswith("win"):
from MvImport.MvCameraControl_class import *
print("win")
else:
from MvImport_Linux.MvCameraControl_class import *
print('linux')
thread_camera = threading.Thread(target=hik_camera_get, daemon=True)
thread_camera.start()
elif camera_mode == 'video':
# USB相机图像获取线程
thread_camera = threading.Thread(target=video_capture_get, daemon=True)
thread_camera.start()
while camera_image is None:
print("等待图像。。。")
time.sleep(0.5)
app = QApplication(sys.argv)
myui = MyUI()
sys.exit(app.exec_())