当前位置:   article > 正文

【项目实战】 Python + Opencv 的工业级机器视觉检测系统_python视觉检测

python视觉检测

目录

前言

一、系统介绍

1.1 设计目的

1.2 硬件配置

二、程序描述

2.1 视觉检测流程

2.2 程序描述

2.2.1 清空文件夹模块

2.2.2 ROI区域划分模块

2.2.3 黑白占比计算

2.2.4 图像处理模块

三、系统简易展示

3.1 合格展示

3.2 不合格展示

四、系统框架代码


前言

 1. 由于受到软件著作权保护,本视觉检测系统仅提供部分算法设计思路。该系统建议作为一个框架使用,通过调整算法结构,具体参数和文件路径实现视觉检测。
 2. 完整版本已投入工业现场使用。

一、系统介绍

1.1 设计目的


本系统主要针对PCB进行检测,PCB在焊锡过程中可能出现以下问题:

 - (1)焊点缺失
 - (2)焊点粘连

因此提出以下要求:

 - (1)对PCB上的焊点进行检测
 - (2)对所有焊点进行判断是否存在缺陷,有缺陷则报警,无缺陷则显示合格
 - (3)将视觉检测系统与PLC进行通讯,通过三色灯显示检测结果

1.2 硬件配置

名称

型号规格

高清工业相机

AA1300 -90GC

相机镜头

HF1628-6MP

LED面光源

BL120*60

光源控制器

模拟恒流

工控机

CV-A6-08128

IO控制器

DAM0808D

二、程序描述

2.1 视觉检测流程

检测思路:

  1. 当系统启动时,首先判断寄存文件夹的文件数量,当文件数量不为1时,删除除了最新图片外的所有图片,然后进行图片读取。当文件数量为1时直接进行图片读取。
  2. 在读取到图片后对图片通过掩膜进行裁剪,然后进行图像处理,消除图片噪声,提取有用的特征。
  3. 用黑白像素的占比计算来作为合格条件进行判断,当白像素超出阈值时为不合格,通过与PLC通讯使得三色灯亮,低于阈值时三色灯绿灯亮,最终显示OK/NG结果,系统结束。

2.2 程序描述

2.2.1 清空文件夹模块

 

模块介绍:

    1.通过python内置的os库来进行文件读取,获得目标文件夹长度list,通过len(list)计算文件夹长度。

    2.当目标文件夹长度不为1时,显示长度(文件夹内图片数量),通过for循环递增文件夹长度的倒数第二个位置,用os.Remove()将图片删除,剩下最后一张即最新的图片。

    3.当目标文件夹长度为1时,说明相机驱动软件MVS采集到最新图片,直接pass进入下一模块。

2.2.2 ROI区域划分模块

 

模块介绍:

    1.图片在计算机中以数组形式显示,相机分辨率为1280*1024,受限于焦距和光圈限制,不能完全覆盖PCB大小,因此需要把 1280*1024的原图裁剪成 和PCB大小相同的 300*350 的图片。PCB板的焊锡分布为上面五个,中间三个,下面三个,生成目标区域的掩膜mask,并且将掩膜像素全置为255,三个mask区域大小分别为:

    2.通过位操作cv.bitwise_and将图像和掩膜进行合并,分别提取出三个目标区域,最后通多cv.add()将区域相加,使得原本图像只剩下三个目标区域:

2.2.3 黑白占比计算

模块介绍:

    用black-pixel和white-pixel两个变量储存黑白像素点的数量,通过遍历1280*1024即13,107,200个像素,使用PLI包内的Image模块,image.size()用于读取PIL方式image.open()打开的图片,该模式下读取图片的宽和长,将值返回到width和height两个变量中。通过image.getpixel()获取某点处像素,统计图片画幅中的像素点数量,当遍历完所有像素后,计算黑白占比并显示,流程结束。

2.2.4 图像处理模块

    图像处理模块是一个线性流程,其中的图像处理算法为灰度处理 - 形态学处理(腐蚀 - 膨胀 - 开运算)- 高斯滤波 - 轮廓提取,分别使用到以下函数:

表2 — 图像处理函数表

类型

函数名称

结构元大小

腐蚀

cv.erode()

(5,5)

膨胀

cv.dilate()

(3,3)

开运算

cv.morphologyEx()

(7,7)

高斯滤波

cv.GaussianBlur()

(1,1)

二值化

cv.threshold()

发现轮廓

cv.findContours()

绘制轮廓

cv.drawContours()

具体函数的使用如下:

三、系统简易展示

处理前图片为PCB板,因涉及专利设计保护,因此使用SW模型代替。

3.1 合格展示

  

图1 处理前图片                                                      图2 处理后图片

 

图3 检测结果显示

3.2 不合格展示

  

 图4 处理前图片                                         图5 处理后图片

 

 图6 处理前图片   

四、系统框架代码

  1. import os
  2. import time
  3. import cv2 as cv
  4. import numpy as np
  5. from PIL import Image
  6. from appdirs import unicode
  7. '''
  8. 算法设计:
  9. (1)形态学处理 -- 1、(腐蚀5*5,膨胀3*3,开运算7*7,均为矩形结构元) 2、高斯滤波
  10. (2)blob筛选 -- 提取并绘制轮廓,减少图片噪声
  11. '''
  12. '''
  13. 检测流程:
  14. (1)从文件夹内读取RGB图片
  15. (2)对RGB图片进行灰度处理,形态学处理,高斯滤波和轮廓提取,其中灰度处理后需要进行掩膜处理,提取目标区域.
  16. (3)对处理完的图片进行黑白占比计算,焊锡点缺失会导致焊锡处反光,导致亮度过高.当白色占比超过阈值,判断为焊锡缺失
  17. (4)输出合格与不合格后,与PLC通过modbus通讯
  18. '''
  19. def cut(cut):
  20. '''
  21. 主要功能:把 1024*1280 的原图 裁剪成 PCB大小的 300*350 的图片
  22. 然后将三个焊锡区域提取出来并合并
  23. '''
  24. img = cut[350:650, 500:850] # 把 1280*1024 的原图 裁剪成 PCB大小的 300*350 的图片
  25. # 分割区域1 -- 上面五个焊锡点
  26. mask1 = np.zeros(img.shape[:2], np.uint8)
  27. mask1[10:60, 10:330] = 255
  28. mask1_img = cv.bitwise_and(img, img, mask=mask1)
  29. # cv.imshow('mask1',mask1_img)
  30. # 分割区域2 -- 中间三个焊锡点
  31. mask2 = np.zeros(img.shape[:2], np.uint8)
  32. mask2[80:130, 70:270] = 255
  33. mask2_img = cv.bitwise_and(img, img, mask=mask2)
  34. # cv.imshow('mask2',mask2_img)
  35. # 分割区域3 -- 下面三个焊锡点
  36. mask3 = np.zeros(img.shape[:2], np.uint8)
  37. mask3[240:290, 70:270] = 255
  38. mask3_img = cv.bitwise_and(img, img, mask=mask3)
  39. # cv.imshow('mask3',mask3_img)
  40. pic1 = cv.add(mask1_img, mask2_img) # 区域1+区域2
  41. pic = cv.add(pic1, mask3_img) # 区域(1+2)+区域3
  42. return pic
  43. def remove():
  44. '''
  45. 主要功能:保证文件夹内只有最新的那一张图片
  46. '''
  47. # 时间在0.01以内,因此不记录时间
  48. path = r'C:\Users\-libr\Desktop\PCB\PCB input_dir'
  49. file = unicode(path)
  50. files = os.listdir(file) # 创建由文件名组成的列表
  51. #print('filelist:', files)
  52. if len(os.listdir(path)) > 1:
  53. print(f"图片数量为:{len(os.listdir(path))}")
  54. for i in range(len(os.listdir(path))-1):
  55. #设置 len(os.listdir(path))-1 是为了保证i递增到倒数第二,留下最新的图片
  56. i += 1
  57. #print(i)
  58. os.remove(os.path.join(path, f'PCB{i}.jpg'))
  59. elif len(os.listdir(path)) == 1:
  60. print(f"图片数量为:1 ")
  61. #文件夹内只有最新的那张图片
  62. pass
  63. def count(image):
  64. '''
  65. 主要功能;输入单张图片图片,计算并输出'黑白占比的计算结果'和'计算一次的时间'
  66. '''
  67. start = time.time()
  68. white_pixel = 0
  69. black_pixel = 0
  70. width, height = image.size
  71. for i in range(width):
  72. for j in range(height):
  73. if image.getpixel((i,j)):
  74. white_pixel += 1
  75. else:
  76. black_pixel += 1
  77. black = black_pixel / (width * height)
  78. white = white_pixel / (width * height)
  79. end = time.time()
  80. cost = end - start
  81. print('黑白检测时间:%s'%cost)
  82. print('黑色占比:%s\n白色占比:%s'%(black,white))
  83. #判断黑白占比阈值,输出检验结果
  84. if black > 0.99:
  85. return(print('合格\n'))
  86. else:
  87. return(print('不合格\n'))
  88. def convert(input_dir, output_dir):
  89. for filename in os.listdir(input_dir):
  90. '''
  91. 主要功能:读取文件夹内的图片,进行图像处理后,并将其保存到指定文件
  92. '''
  93. path = input_dir + "/" + filename # 获取文件路径
  94. gray_img = cv.imread(path, 0) # 读取图片,参数0为直接以灰度模式读取
  95. cut_pic = cut(gray_img) #提取三个焊锡区域后的图片
  96. # 腐蚀
  97. kernel1 = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))
  98. img_erode = cv.erode(cut_pic, kernel1)
  99. # 膨胀
  100. kernel2 = cv.getStructuringElement(cv.MORPH_RECT, (3, 3))
  101. img_dilate = cv.dilate(img_erode, kernel2)
  102. # 开运算
  103. kernel3 = cv.getStructuringElement(cv.MORPH_RECT, (7, 7))
  104. img_open = cv.morphologyEx(img_dilate, cv.MORPH_OPEN, kernel3, iterations=1)
  105. # 高斯滤波
  106. img_gaussian = cv.GaussianBlur(img_open, (1, 1), 2)
  107. # 二值化
  108. ret, img_turn = cv.threshold(img_gaussian, 127, 255, 0)
  109. # 发现轮廓
  110. contours, heriachy = cv.findContours(img_turn, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
  111. for i, contour in enumerate(contours):
  112. # 绘制每条轮廓
  113. cv.drawContours(img_turn, contours, i, (0, 0, 255), 2)
  114. cv.imwrite(output_dir + '/' + filename, img_turn)
  115. cv.imshow("PCB", img_turn)
  116. cv.waitKey()
  117. cv.destroyAllWindows()
  118. # cv.destroyAllWindows(1)
  119. def read_path(output_dir):
  120. for filename in os.listdir(output_dir):
  121. '''
  122. 主要功能:定义读取路径的函数,为用PIL打开图片获得
  123. '''
  124. path = output_dir + "/" + filename # 获取文件路径
  125. image = Image.open(path).convert('L')
  126. count(image)
  127. if __name__ == '__main__':
  128. # 输入RGB图片
  129. input_dir = r'C:\Users\-libr\Desktop\PCB\PCB input_dir' # 输入文件夹
  130. output_dir = r'C:\Users\-libr\Desktop\PCB\PCB output_dir' # 输出文件夹
  131. #1、保持文件夹内只有最新图片
  132. remove()
  133. #2、对图片进行读取,处理和保存
  134. convert(input_dir, output_dir)
  135. #3、对图片进行黑白占比计算并判断
  136. read_path(r'C:\Users\-libr\Desktop\PCB\PCB output_dir')
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/正经夜光杯/article/detail/734403
推荐阅读
相关标签
  

闽ICP备14008679号