当前位置:   article > 正文

基于yolov5的pcb板缺陷检测的边缘端部署(AidLux)_yolov5 pcb板系统

yolov5 pcb板系统

该项目通过yolov5算法实现了pcb板表面的六种常见缺陷的检测:

缺失孔、鼠牙洞 、开路、短路、毛刺、伪铜,并且成功在边缘端(AidLux)部署

可检测图片、视频以及调用摄像头实时监测,并且可在界面实时显示当前图片的缺陷个数

aidLux部署部分代码:

  1. import cv2
  2. import numpy as np
  3. from cvs import *
  4. import aidlite_gpu
  5. coco_class = ['missing_hole', 'mouse_bite', 'open_circuit', 'short', 'spur', 'spurious_copper' ]
  6. def xywh2xyxy(x):
  7. '''
  8. Box (center x, center y, width, height) to (x1, y1, x2, y2)
  9. '''
  10. y = np.copy(x)
  11. y[:, 0] = x[:, 0] - x[:, 2] / 2 # top left x
  12. y[:, 1] = x[:, 1] - x[:, 3] / 2 # top left y
  13. y[:, 2] = x[:, 0] + x[:, 2] / 2 # bottom right x
  14. y[:, 3] = x[:, 1] + x[:, 3] / 2 # bottom right y
  15. return y
  16. def xyxy2xywh(box):
  17. '''
  18. Box (left_top x, left_top y, right_bottom x, right_bottom y) to (left_top x, left_top y, width, height)
  19. '''
  20. box[:, 2:] = box[:, 2:] - box[:, :2]
  21. return box
  22. def NMS(dets, thresh):
  23. '''
  24. 单类NMS算法
  25. dets.shape = (N, 5), (left_top x, left_top y, right_bottom x, right_bottom y, Scores)
  26. '''
  27. x1 = dets[:,0]
  28. y1 = dets[:,1]
  29. x2 = dets[:,2]
  30. y2 = dets[:,3]
  31. areas = (y2-y1+1) * (x2-x1+1)
  32. scores = dets[:,4]
  33. keep = []
  34. index = scores.argsort()[::-1]
  35. while index.size >0:
  36. i = index[0] # every time the first is the biggst, and add it directly
  37. keep.append(i)
  38. x11 = np.maximum(x1[i], x1[index[1:]]) # calculate the points of overlap
  39. y11 = np.maximum(y1[i], y1[index[1:]])
  40. x22 = np.minimum(x2[i], x2[index[1:]])
  41. y22 = np.minimum(y2[i], y2[index[1:]])
  42. w = np.maximum(0, x22-x11+1) # the weights of overlap
  43. h = np.maximum(0, y22-y11+1) # the height of overlap
  44. overlaps = w*h
  45. ious = overlaps / (areas[i]+areas[index[1:]] - overlaps)
  46. idx = np.where(ious<=thresh)[0]
  47. index = index[idx+1] # because index start from 1
  48. return dets[keep]
  49. def letterbox(img, new_shape=(640, 640), color=(114, 114, 114), auto=True, scaleFill=False, scaleup=True, stride=32):
  50. # Resize and pad image while meeting stride-multiple constraints
  51. shape = img.shape[:2] # current shape [height, width]
  52. if isinstance(new_shape, int):
  53. new_shape = (new_shape, new_shape)
  54. # Scale ratio (new / old)
  55. r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])
  56. if not scaleup: # only scale down, do not scale up (for better test mAP)
  57. r = min(r, 1.0)
  58. # Compute padding
  59. ratio = r, r # width, height ratios
  60. new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r))
  61. dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1] # wh padding
  62. if auto: # minimum rectangle
  63. dw, dh = np.mod(dw, stride), np.mod(dh, stride) # wh padding
  64. elif scaleFill: # stretch
  65. dw, dh = 0.0, 0.0
  66. new_unpad = (new_shape[1], new_shape[0])
  67. ratio = new_shape[1] / shape[1], new_shape[0] / shape[0] # width, height ratios
  68. dw /= 2 # divide padding into 2 sides
  69. dh /= 2
  70. if shape[::-1] != new_unpad: # resize
  71. img = cv2.resize(img, new_unpad, interpolation=cv2.INTER_LINEAR)
  72. top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1))
  73. left, right = int(round(dw - 0.1)), int(round(dw + 0.1))
  74. img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color) # add border
  75. return img, ratio, (dw, dh)
  76. def preprocess_img(img, target_shape:tuple=None, div_num=255, means:list=[0.485, 0.456, 0.406], stds:list=[0.229, 0.224, 0.225]):
  77. '''
  78. 图像预处理:
  79. target_shape: 目标shape
  80. div_num: 归一化除数
  81. means: len(means)==图像通道数,通道均值, None不进行zscore
  82. stds: len(stds)==图像通道数,通道方差, None不进行zscore
  83. '''
  84. img_processed = np.copy(img)
  85. # resize
  86. if target_shape:
  87. #img_processed = cv2.resize(img_processed, target_shape)
  88. img_processed = letterbox(img_processed, target_shape, stride=None, auto=False)[0]
  89. img_processed = cv2.cvtColor(img_processed, cv2.COLOR_BGR2RGB).astype(np.float32)
  90. img_processed = img_processed/div_num
  91. # z-score
  92. if means is not None and stds is not None:
  93. means = np.array(means).reshape(1, 1, -1)
  94. stds = np.array(stds).reshape(1, 1, -1)
  95. img_processed = (img_processed-means)/stds
  96. # unsqueeze
  97. img_processed = img_processed[None, :]
  98. return img_processed.astype(np.float32)
  99. def convert_shape(shapes:tuple or list, int8=False):
  100. '''
  101. 转化为aidlite需要的格式
  102. '''
  103. if isinstance(shapes, tuple):
  104. shapes = [shapes]
  105. out = []
  106. for shape in shapes:
  107. nums = 1 if int8 else 4
  108. for n in shape:
  109. nums *= n
  110. out.append(nums)
  111. return out
  112. def scale_coords(img1_shape, coords, img0_shape, ratio_pad=None):
  113. # Rescale coords (xyxy) from img1_shape to img0_shape
  114. if ratio_pad is None: # calculate from img0_shape
  115. gain = min(img1_shape[0] / img0_shape[0], img1_shape[1] / img0_shape[1]) # gain = old / new
  116. pad = (img1_shape[1] - img0_shape[1] * gain) / 2, (img1_shape[0] - img0_shape[0] * gain) / 2 # wh padding
  117. else:
  118. gain = ratio_pad[0][0]
  119. pad = ratio_pad[1]
  120. coords[:, [0, 2]] -= pad[0] # x padding
  121. coords[:, [1, 3]] -= pad[1] # y padding
  122. coords[:, :4] /= gain
  123. clip_coords(coords, img0_shape)
  124. return coords
  125. def clip_coords(boxes, img_shape):
  126. # Clip bounding xyxy bounding boxes to image shape (height, width)
  127. boxes[:, 0].clip(0, img_shape[1], out=boxes[:, 0]) # x1
  128. boxes[:, 1].clip(0, img_shape[0], out=boxes[:, 1]) # y1
  129. boxes[:, 2].clip(0, img_shape[1], out=boxes[:, 2]) # x2
  130. boxes[:, 3].clip(0, img_shape[0], out=boxes[:, 3]) # y2
  131. def detect_postprocess(prediction, img0shape, img1shape, conf_thres=0.25, iou_thres=0.45):
  132. '''
  133. 检测输出后处理
  134. prediction: aidlite模型预测输出
  135. img0shape: 原始图片shape
  136. img1shape: 输入图片shape
  137. conf_thres: 置信度阈值
  138. iou_thres: IOU阈值
  139. return: list[np.ndarray(N, 5)], 对应类别的坐标框信息, xywh、conf
  140. '''
  141. h, w, _ = img1shape
  142. cls_num = prediction.shape[-1] - 5
  143. valid_condidates = prediction[prediction[..., 4] > conf_thres]
  144. valid_condidates[:, 0] *= w
  145. valid_condidates[:, 1] *= h
  146. valid_condidates[:, 2] *= w
  147. valid_condidates[:, 3] *= h
  148. valid_condidates[:, :4] = xywh2xyxy(valid_condidates[:, :4])
  149. valid_condidates = valid_condidates[(valid_condidates[:, 0] > 0) & (valid_condidates[:, 1] > 0) & (valid_condidates[:, 2] > 0) & (valid_condidates[:, 3] > 0)]
  150. box_cls = valid_condidates[:, 5:].argmax(1)
  151. cls_box = []
  152. for i in range(cls_num):
  153. temp_boxes = valid_condidates[box_cls == i]
  154. if(len(temp_boxes) == 0):
  155. cls_box.append([])
  156. continue
  157. temp_boxes = NMS(temp_boxes, iou_thres)
  158. temp_boxes[:, :4] = scale_coords([h, w], temp_boxes[:, :4] , img0shape).round()
  159. temp_boxes[:, :4] = xyxy2xywh(temp_boxes[:, :4])
  160. cls_box.append(temp_boxes[:, :5])
  161. return cls_box

效果展示:

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/749307
推荐阅读
相关标签
  

闽ICP备14008679号