Guest User

Untitled

a guest
Dec 21st, 2021
88
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.66 KB | None | 0 0
  1. from pypylon import pylon
  2. import cv2, numpy as np
  3. from PyQt5.QtCore import Qt
  4. from PyQt5.QtGui import QImage, QPixmap
  5. import asyncio
  6. from time import sleep
  7. import csv
  8. from timer import Timer
  9. from concurrent.futures import ThreadPoolExecutor
  10. from threading import Thread
  11. from queue import Queue
  12.  
  13. # A thread that produces data
  14. def image_producer(camera, out_q, running ):
  15. converter = pylon.ImageFormatConverter()
  16. converter.OutputPixelFormat = pylon.PixelType_BGR8packed
  17. converter.OutputBitAlignment = pylon.OutputBitAlignment_MsbAligned
  18. camera.StartGrabbing(pylon.GrabStrategy_LatestImageOnly)
  19. counter = 0
  20. while running:
  21. # Produce some data
  22. while camera.IsGrabbing():
  23. #grabResult = self.loop.run_in_executor(self.pool,self.camera.RetrieveResult,5000, pylon.TimeoutHandling_ThrowException)
  24. try:
  25. grabResult = camera.RetrieveResult(5000, pylon.TimeoutHandling_ThrowException)
  26. if grabResult.GrabSucceeded():
  27. img = converter.Convert(grabResult)
  28. img = img.GetArray()
  29. out_q.put(img)
  30. grabResult.Release()
  31. counter = 0
  32. except:
  33. counter += 1
  34. print(f'\rCamera stalled {counter} times', end = '', flush = True)
  35. break
  36. if not (running):
  37. break
  38.  
  39. class Visualize_Sample:
  40. camera = None
  41. calibration = True
  42. top_left_corner = (0, 0)
  43. width_and_height = (100, 100)
  44. threshold_low = 0
  45. threshold_high = 255
  46. final_dark_tol = 1
  47. final_index_pad = 1
  48. final_bottom_trim = 2
  49. capture_profile = False
  50. image_stream = None
  51. data_file = None
  52. writer = None
  53. orig_height = 1
  54. orig_width_padding = None
  55. orig_height_padding = None
  56. orig_sample = None
  57. orig_top = None
  58. orig_bottom = None
  59. orig_left = None
  60. orig_right = None
  61. offset = None
  62. sensitivity = None
  63. sample_size = None
  64. sample = 0
  65. image_counter = 0
  66. x_adj = 0
  67. y_adj = 0
  68. resample = True
  69. left_edge = 0
  70. right_edge = 0
  71. max_threads = 7
  72. pool = None
  73. loop = None
  74. image_queue = None
  75. running = False
  76.  
  77. def __init__(self):
  78. self.init_camera()
  79. self.loop = asyncio.get_running_loop()
  80. self.pool = ThreadPoolExecutor(self.max_threads)
  81. self.image_queue = Queue()
  82.  
  83. async def Stop_Imaging(self):
  84. self.running = False
  85. self.image_stream.cancel()
  86.  
  87.  
  88. async def get_profile(self):
  89. self.capture_profile = True
  90.  
  91. await asyncio.sleep(1)
  92. await self.Stop_Imaging()
  93.  
  94. async def get_newsample(self):
  95. self.resample = True
  96.  
  97. def label_image(self, image, label, position, color):
  98. font = cv2.FONT_HERSHEY_SIMPLEX
  99. fontScale = 1
  100. color = (255, 255, 0)
  101. thickness = 7
  102. labelled_image = cv2.putText(image, label, position, font, fontScale, color, thickness, cv2.LINE_AA)
  103. return labelled_image
  104.  
  105. async def stop_run(self):
  106. self.camera.StopGrabbing()
  107. self.image_stream.cancel()
  108.  
  109. def Update_GUI_Labels(self, top_platen, sample_top, bottom_platen):
  110. self.parent.ui.lb_PLATEN_to_PLATEN.setText(str(bottom_platen - top_platen))
  111. self.parent.ui.lb_PLATEN_to_SAMPLE.setText(str(sample_top - top_platen))
  112. self.parent.ui.lb_SAMPLE_to_BOTTOM_PLATEN.setText(str(int(bottom_platen) - int(sample_top)))
  113. self.parent.ui.lb_SAMPLE_TOP_to_ORIGINAL_SAMPLE_TOP.setText(str(int(sample_top) - int(self.orig_sample)))
  114. self.parent.ui.lb_ORIGINALSAMPLE_to_BOTTOM_PLATEN.setText(str(int(self.orig_bottom) - int(self.orig_sample)))
  115.  
  116. def Emit_Strain(self, val):
  117. self.parent.current_strain = val
  118.  
  119. async def find_platens(self, calibration, img):
  120. top = 0
  121. gap = 0
  122. read_size = 25
  123. h, w = img.shape[:2]
  124. for i in range(0, read_size):
  125. top += np.argmax((img[:, i] == 255), axis=0)[0]
  126. gap += np.count_nonzero((img[:, i] == 255), axis=0)[0]
  127.  
  128. for i in range(w - 1, w - 1 - read_size, -1):
  129. top += np.argmax((img[:, i] == 255), axis=0)[0]
  130. gap += np.count_nonzero((img[:, i] == 255), axis=0)[0]
  131.  
  132. top /= 2 * read_size
  133. gap /= 2 * read_size
  134. return (
  135. int(top), int(top + gap))
  136.  
  137. async def find_sample(self, calibration, img, top, bottom):
  138. h, w = img.shape[:2]
  139. left_edge = 0
  140. right_edge = w - 1
  141. step_leftedge = int(w / 8)
  142. step_rightedge = int(w / 8)
  143. threshold = 0.05
  144. gap = bottom - top
  145. iter = 10
  146. if calibration:
  147. for i in range(0, iter):
  148. test_left = np.count_nonzero((img[:, left_edge] == 255), axis=0)[0]
  149. test_right = np.count_nonzero((img[:, right_edge] == 255), axis=0)[0]
  150. #print('step A1')
  151. #print(f' left_edge = {left_edge} test_left = {test_left} right_edge = {right_edge} test_right = {test_right} gap = {gap}')
  152. if abs(test_left - gap) < gap * threshold:
  153. # print('branch 1')
  154. left_edge = left_edge + step_leftedge
  155. else:
  156. # print('branch 2')
  157. step_leftedge = int(step_leftedge / 2)
  158. if (left_edge - step_leftedge > 0):
  159. left_edge = left_edge - step_leftedge
  160. else:
  161. left_edge = 0
  162. #print('step A2')
  163. if abs(test_right - gap) < gap * threshold:
  164. # print('branch 4')
  165. right_edge = right_edge - step_rightedge
  166. else:
  167. # print('branch 5')
  168. step_rightedge = int(step_rightedge / 2)
  169. if (right_edge + step_rightedge < w - 1):
  170. right_edge = right_edge + step_rightedge
  171. else:
  172. right_edge = w-1
  173. self.left_edge = left_edge
  174. self.right_edge = right_edge
  175. else:
  176. left_edge = self.left_edge
  177. right_edge = self.right_edge
  178. #print('step B')
  179. if calibration:
  180. if self.resample:
  181. sample_size = int(self.parent.ui.sld_SAMPLE_DENSITY.value())
  182. surface_points = np.random.choice(np.arange(left_edge, right_edge, dtype=int), sample_size, replace=False)
  183. self.surface_points = surface_points
  184. self.resample = False
  185. self.sample_density = sample_size
  186. else:
  187. surface_points = self.surface_points
  188. sample_size = self.sample_density
  189. else:
  190. surface_points = self.surface_points - self.x_adj
  191. sample_size = self.sample_density
  192. sample_height = 0
  193. for col in surface_points:
  194. top = np.argmax((img[:, col] == 255), axis=0)[0]
  195. gap = np.count_nonzero((img[:, col] == 255), axis=0)[0]
  196. sample_height += top + gap
  197. sample_height /= sample_size
  198. return (left_edge, right_edge, sample_height)
  199.  
  200. async def annotate_image(self, calibration, img, lines):
  201. if calibration:
  202. raw_img = None
  203. else:
  204. raw_img = img.copy()
  205. if len(lines) == 2:
  206. top = lines[0][0][1]
  207. bottom = lines[1][0][1]
  208. new_height = bottom - top
  209. sample = 0
  210. else:
  211. top = lines[0][0][1]
  212. sample = lines[2][0][1]
  213. bottom = lines[1][0][1]
  214. new_height = bottom - sample
  215. left = lines[0][0][0]
  216. right = lines[0][1][0]
  217. for line in lines:
  218. point_1 = tuple(line[0])
  219. point_2 = tuple(line[1])
  220. img = cv2.line(img, point_1, point_2, (0, 0, 255), 30)
  221. if calibration:
  222. height_padding = int(self.parent.ui.sld_HEIGHT_PADDING.value())
  223. if top - height_padding < 0:
  224. top = height_padding
  225. if bottom + height_padding > 4023:
  226. bottom = 4023 - height_padding
  227. width_padding = int(self.parent.ui.sld_WIDTH_PADDING.value())
  228. if left - width_padding < 0:
  229. left = width_padding
  230. if right + width_padding > 4023:
  231. right = 4023 - width_padding
  232. cropped_img = img[top - height_padding:bottom + height_padding, left - width_padding:right + width_padding]
  233. cropped_img = cv2.cvtColor(cropped_img, cv2.COLOR_BGR2RGB)
  234. else:
  235. cropped_img = img
  236. if self.capture_profile:
  237. self.orig_top = top
  238. self.orig_sample = sample
  239. self.orig_bottom = bottom
  240. self.orig_height = bottom - sample
  241. self.orig_left = left
  242. self.orig_right = right
  243. self.width_padding = width_padding
  244. self.height_padding = height_padding
  245. self.sample_density = int(self.parent.ui.sld_SAMPLE_DENSITY.value())
  246. self.x_adj = left - width_padding
  247. self.y_adj = top - height_padding
  248. self.capture_profile = False
  249. return (cropped_img, raw_img)
  250.  
  251. async def overlay_original_data(self, img):
  252. color = (0, 255, 255)
  253. point_1 = (
  254. self.orig_left - self.x_adj, self.orig_top - self.y_adj)
  255. point_2 = (self.orig_right - self.x_adj, self.orig_top - self.y_adj)
  256. img = cv2.line(img, point_1, point_2, color, 30)
  257. point_1 = (self.orig_left - self.x_adj, self.orig_bottom - self.y_adj)
  258. point_2 = (self.orig_right - self.x_adj, self.orig_bottom - self.y_adj)
  259. img = cv2.line(img, point_1, point_2, color, 30)
  260. point_1 = (self.orig_left - self.x_adj, self.orig_sample - self.y_adj)
  261. point_2 = (self.orig_right - self.x_adj, self.orig_sample - self.y_adj)
  262. img = cv2.line(img, point_1, point_2, color, 30)
  263. img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
  264. return img
  265.  
  266. async def calibrate_aquisition(self, img):
  267. # print('step 1')
  268. top_platen, bottom_platen = await self.find_platens(True, img)
  269. # print('step 2')
  270. sample_left, sample_right, sample_height = await self.find_sample(True, img, top_platen, bottom_platen)
  271. # print('step 3')
  272. if sample_height == 9999:
  273. top_platen = np.array([(sample_left, top_platen), (sample_right, top_platen)], dtype=int)
  274. bottom_platen = np.array([(sample_left, bottom_platen), (sample_right, bottom_platen)], dtype=int)
  275. lines = [top_platen, bottom_platen]
  276. else:
  277. top_platen = np.array([(sample_left, top_platen), (sample_right, top_platen)], dtype=int)
  278. bottom_platen = np.array([(sample_left, bottom_platen), (sample_right, bottom_platen)], dtype=int)
  279. sample = np.array([(sample_left, sample_height), (sample_right, sample_height)], dtype=int)
  280. lines = [top_platen, bottom_platen, sample]
  281. cropped_img, raw_img = await self.annotate_image(True, img, lines)
  282. return (img, cropped_img)
  283.  
  284. def save_image(self, img,name):
  285. np.save(name, img, allow_pickle=False)
  286.  
  287. async def process_image(self, img):
  288. top_platen, bottom_platen = await self.find_platens(False, img)
  289. sample_left, sample_right, sample_height = await self.find_sample(False, img, top_platen, bottom_platen)
  290. if sample_height == 9999:
  291. new_height = bottom_platen - top_platen
  292. top = top_platen
  293. bottom = bottom_platen
  294. top_platen = np.array([(sample_left, top_platen), (sample_right, top_platen)], dtype=int)
  295. bottom_platen = np.array([(sample_left, bottom_platen), (sample_right, bottom_platen)], dtype=int)
  296. lines = [top_platen, bottom_platen]
  297. else:
  298. new_height = bottom_platen - sample_height
  299. top = top_platen
  300. bottom = bottom_platen
  301. top_platen = np.array([(sample_left, top_platen), (sample_right, top_platen)], dtype=int)
  302. bottom_platen = np.array([(sample_left, bottom_platen), (sample_right, bottom_platen)], dtype=int)
  303. sample = np.array([(sample_left, sample_height), (sample_right, sample_height)], dtype=int)
  304. lines = [top_platen, bottom_platen, sample]
  305. cropped_img, raw_img = await self.annotate_image(False, img, lines)
  306. cropped_img = await self.overlay_original_data(cropped_img)
  307. self.Update_GUI_Labels(top_platen[(0, 1)], sample[(0, 1)], bottom_platen[(0,1)])
  308. self.image_counter += 1
  309. strain = float(100 - new_height / self.orig_height * 100)
  310. await asyncio.sleep(0)
  311. self.Emit_Strain(strain)
  312. await asyncio.sleep(0)
  313. time, timestamp, force, angle = await self.parent.Emit_Data()
  314. data = [str(timestamp), str(time), str(force), str(angle),
  315. str(strain), str(top), str(sample_height),
  316. str(bottom), str(self.orig_top - self.y_adj),
  317. str(self.orig_sample - self.y_adj), str(self.orig_bottom - self.y_adj)]
  318. filename = f"./unprocessed_images/image-{int(self.image_counter):06d}-{timestamp}-{angle}-{force}.npy"
  319. self.writer.writerow(data)
  320. #np.save(filename, raw_img, allow_pickle=False)
  321. self.loop.run_in_executor(self.pool,self.save_image,raw_img,filename)
  322. return cropped_img
  323.  
  324. def Emit_Strain(self, val):
  325. self.parent.current_strain = val
  326.  
  327. def init_camera(self):
  328. serial_number = '23437639'
  329. info = None
  330. for i in pylon.TlFactory.GetInstance().EnumerateDevices():
  331. if i.GetSerialNumber() == serial_number:
  332. info = i
  333. break
  334. else:
  335. print('Camera with {} serial number not found '.format(serial_number))
  336. if info is not None:
  337. self.camera = pylon.InstantCamera(pylon.TlFactory.GetInstance().CreateDevice(info))
  338. self.camera.Open()
  339. self.camera.ReverseY.SetValue(True)
  340. self.converter = pylon.ImageFormatConverter()
  341. self.converter.OutputPixelFormat = pylon.PixelType_BGR8packed
  342. self.converter.OutputBitAlignment = pylon.OutputBitAlignment_MsbAligned
  343.  
  344. async def process_image_stream(self):
  345. self.running = True
  346. t1 = Thread(target = image_producer, args =(self.camera,self.image_queue,self.running))
  347. stopwatch = Timer()
  348. t1.start()
  349. print('aquire_images trying at least:')
  350. while self.running:
  351. stopwatch.start()
  352. img_data = self.image_queue.get()
  353. print(' got image from queue')
  354. if self.calibration:
  355. print('check point 1')
  356. h, w, ch = img_data.shape
  357. print(img_data.shape)
  358. original_img, final_img = await self.calibrate_aquisition(img_data)
  359. bytesPerLine = ch * w
  360. original_QT = QImage(original_img.data, w, h, bytesPerLine, QImage.Format_RGB888)
  361. cropped_h, cropped_w, ch = final_img.shape
  362. cropped_bytesPerLine = cropped_w * ch
  363. final_QT = QImage(final_img.data, cropped_w, cropped_h, cropped_bytesPerLine, QImage.Format_RGB888)
  364. if not original_QT.isNull():
  365. p0 = original_QT.scaled(480, 480, Qt.KeepAspectRatio)
  366. self.parent.ui.original_image.setPixmap(QPixmap.fromImage(p0))
  367. if not final_QT.isNull():
  368. p2 = final_QT.scaled(480, 480, Qt.KeepAspectRatio)
  369. self.parent.ui.final_image.setPixmap(QPixmap.fromImage(p2))
  370. time = stopwatch.stop()
  371. self.parent.ui.lb_TIME_ELAPSED.setText(f"{time:0.4f} seconds")
  372. self.parent.ui.lb_FPS.setText(f"{1 / time:0.1f} FPS")
  373. else:
  374. final_img = await self.process_image(img_data)
  375. #cropped_h, cropped_w, ch = final_img.shape
  376. #bytesPerLine = cropped_w * ch
  377. #final_QT = QImage(final_img.data, cropped_w, cropped_h, bytesPerLine, QImage.Format_RGB888)
  378. #if not final_QT.isNull():
  379. # p0 = final_QT.scaled(480, 480, Qt.KeepAspectRatio)
  380. # self.parent.ui.camera_image.setPixmap(QPixmap.fromImage(p0))
  381. time = stopwatch.stop()
  382. self.parent.ui.lb_FPS.setText(f"{1 / time:0.1f} FPS")
  383. await asyncio.sleep(0) # required to allow GUI to update
  384.  
  385.  
  386. async def aquire_images(self, calibration, calling_window):
  387. self.parent = calling_window
  388. if calibration:
  389. self.calibration = True
  390. else:
  391. self.calibration = False
  392. width = int((self.orig_right - self.orig_left) + 2* self.width_padding)
  393. height = int((self.orig_bottom - self.orig_top) + 2* self.height_padding)
  394. top = max(self.orig_top - int(0.25*2*self.height_padding),1)
  395. left = max(self.orig_left- int(2*self.width_padding),1)
  396. self.camera.Width.SetValue(width)
  397. self.camera.Height.SetValue(height)
  398. self.camera.OffsetX.SetValue(left)
  399. self.camera.OffsetY.SetValue(top)
  400. self.running = True
  401. self.data_file = open('run_data.csv', 'w', newline='')
  402. self.writer = csv.writer(self.data_file)
  403. header = ['timestamp', 'time_s', 'force_g', 'position', 'strain', 'top_platen', 'sample_top', 'bottom_platen', 'orig_top_platen', 'orig_sample_top', 'orig_bottom_platen']
  404. self.writer.writerow(header)
  405. self.image_stream = asyncio.create_task(self.process_image_stream())
Advertisement
Add Comment
Please, Sign In to add comment