[附完整源码] Python检测物品数量(螺丝)的缺漏

系列文章

Python 学习之open cv检测pcb板上的螺丝数量


文章目录

  • 系列文章
  • 前言
  • 一、作者心得与代码背景
  • 二、代码实现
    • 1.代码思路
    • 2.详细步骤
      • 2.2.1编写相关的头文件
      • 2.2.2导入相关的检测图片
      • 2.2.3规定区域的位置设置
      • 2.2.4检测图片预处理
      • 2.2.5轮廓检测(霍夫圆)
      • 2.2.6尾部编写
    • 3.完整源代码
  • 总结

前言

该文章介绍了如何用python来检测自己的pcb板上螺丝是否有缺失,可以运用到不同的业务场景中,本文用于学术交流,禁止商用与冒用,违者后果自负,谢谢!!!


一、作者心得与代码背景

国家最近几年都在推崇数字化转型,在许多的流水线工厂也跟着响应,那作者在实习的时候,发现了一个业务需求困扰了很多企业。
该需求就是:检测流水作业上的pcb板螺丝是否漏打,如下图中左侧红框中的两颗螺丝。
检测物品

对此,作者提出了自己的思考方式,通过python与open-cv的编写,来解决该问题。
该方法耗费了作者许多的时间与精力,如果各位看官觉得该文章有用,还请给予一个赞与收藏

二、代码实现

1.代码思路

思路如下:
我们要去检测有无螺丝的漏打情况,就得先去定位螺丝的位置,保证螺丝打在了正确的位置后,才能开始检测。

  1. 传入我们所需要的检测图片
  2. 划定检测区域,定位螺丝的位置
  3. 处理相关部分的图片
  4. 通过霍夫圆检测来确定螺丝的轮廓,并进行判断是否有螺丝漏打的情况

2.详细步骤


2.2.1编写相关的头文件

代码如下:

import cv2
import numpy as np

2.2.2导入相关的检测图片

代码和图片如下:

#传进来螺丝图片
img = cv2.imread('文件名称')

检测图片


2.2.3规定区域的位置设置

代码和图片如下:

# 下面是规定区域的位置设置
#第一个框
w1 = 0
h1 = 0
width  = 350
height = 300
x1 = int(width / 2 - w1 / 2)
y1 = int(height / 2 - h1 / 2 - 100)
# print(x1, y1, x1 + w1, y1 + h1)
cv2.rectangle(img, (w1, h1), (x1 + width, y1 + height), (0, 255, 0), 2)  # 在原视频上绘制矩形框

#第二个框
w2 = 250
h2 = 710
width2  = 300
height2 = 300
# print(x1, y1, x1 + w1, y1 + h1)
cv2.rectangle(img, (w2, h2),  (w2 + width2, h2 + height2),(0, 255, 0), 2)  # 在原视频上绘制矩形框


#绿框截取
x11 = w1
y11 = h1
x22 = x1 + width
y22 = y1 + height
# y写在前,x写在后,对角坐标
ims1 = img[y11:y22, x11:x22]

x21 = w2
y21 = h2
x32 = w2 + width2
y32 = h2 + height2
# y写在前,x写在后,对角坐标
ims2 = img[y21:y32, x21:x32]


cv2.imshow("Tailoring1",ims1)


cv2.imshow("Tailoring2",ims2)

确定螺丝位置
黄色圈圈为霍夫圆检测的轮廓,该阶段不需要注意


2.2.4检测图片预处理

代码如下:

#设置色域范围

HSV1 = cv2.cvtColor(ims1,cv2.COLOR_BGR2HSV)
H, S, V = cv2.split(HSV1)

HSV2 = cv2.cvtColor(ims2,cv2.COLOR_BGR2HSV)
H, S, V = cv2.split(HSV2)

#色域下限
lower_red = np.array([0, 0, 46])

#色域上限
upper_red = np.array([180, 43, 220])
mask1 = cv2.inRange(HSV1, lower_red, upper_red)
mask1 = cv2.medianBlur(mask1, 5)
maskAnd1 = cv2.bitwise_and(ims1, ims1, mask=mask1)

upper_red = np.array([180, 43, 220])
mask2 = cv2.inRange(HSV2, lower_red, upper_red)
mask2 = cv2.medianBlur(mask2, 5)
maskAnd2 = cv2.bitwise_and(ims2, ims2, mask=mask2)


# 找出轮廓
gray1 = cv2.cvtColor(maskAnd1, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray1, 175, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

gray2 = cv2.cvtColor(maskAnd2, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray2, 175, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

cv2.imshow('maskAnd99', gray1)
cv2.imshow('maskAnd98', gray2)

图片处理
这样处理完后,我们就只会得到银色部分的图片,接下来我们就可以去取轮廓了


2.2.5轮廓检测(霍夫圆)

代码如下:

# 圆形检测
circles1 = cv2.HoughCircles(gray1, cv2.HOUGH_GRADIENT, dp=1, minDist=50, param1=100, param2=40, minRadius=10,maxRadius=100)

circles2 = cv2.HoughCircles(gray2, cv2.HOUGH_GRADIENT, dp=1, minDist=50, param1=100, param2=40, minRadius=10,maxRadius=100)


sum = 0


if circles1 is not None:
    try:
        for circle in circles1[0]:
            # 坐标行列-圆心坐标
            x = int(circle[0])
            y = int(circle[1])
            # 半径
            r = int(circle[2])
            # 在原图用指定颜色标记出圆的边界
            cv2.circle(ims1, (x, y), r, (0, 255, 255), 3)
            # 画出圆的圆心
            cv2.circle(gray1, (x, y), r, (0, 255, 255), 3)
            circles = np.round(circles1[0, :]).astype("int")
            # 计算圆形的数量
            sum += 1
    except TypeError:
        print("一个都没打")



if circles2 is not None:
    try:
        for circle in circles2[0]:
            # 坐标行列-圆心坐标
            x = int(circle[0])
            y = int(circle[1])
            # 半径
            r = int(circle[2])
            # 在原图用指定颜色标记出圆的边界
            cv2.circle(ims2, (x, y), r, (0, 255, 255), 3)
            # 画出圆的圆心
            cv2.circle(gray2, (x, y), r, (0, 255, 255), 3)
            circles = np.round(circles2[0, :]).astype("int")
            # 计算圆形的数量
            sum += 1
    except TypeError:
        print("一个都没打")


print('螺丝个数为:', sum)
if(sum==2):
        print("OK")
else:
        print("NG")

螺丝轮廓检测
至此我们可以的得到两颗螺丝的轮廓,就是图中黄色圈圈标注的内容,同时还进行了螺丝的漏打判断,下面一幅图为只打了一颗螺丝的情况
只打了一颗螺丝


2.2.6尾部编写

代码如下:

#展示图片
cv2.imshow('maskAnd1', img)
cv2.waitKey()
cv2.destroyAllWindows()

3.完整源代码

import cv2
import numpy as np


#传进来螺丝图片
img = cv2.imread('jc1.jpg')


# 下面是规定区域的位置设置
#第一个框
w1 = 0
h1 = 0
width  = 350
height = 300
x1 = int(width / 2 - w1 / 2)
y1 = int(height / 2 - h1 / 2 - 100)
# print(x1, y1, x1 + w1, y1 + h1)
cv2.rectangle(img, (w1, h1), (x1 + width, y1 + height), (0, 255, 0), 2)  # 在原视频上绘制矩形框

#第二个框
w2 = 250
h2 = 710
width2  = 300
height2 = 300
# print(x1, y1, x1 + w1, y1 + h1)
cv2.rectangle(img, (w2, h2),  (w2 + width2, h2 + height2),(0, 255, 0), 2)  # 在原视频上绘制矩形框


#绿框截取
x11 = w1
y11 = h1
x22 = x1 + width
y22 = y1 + height
# y写在前,x写在后,对角坐标
ims1 = img[y11:y22, x11:x22]

x21 = w2
y21 = h2
x32 = w2 + width2
y32 = h2 + height2
# y写在前,x写在后,对角坐标
ims2 = img[y21:y32, x21:x32]


cv2.imshow("Tailoring1",ims1)


cv2.imshow("Tailoring2",ims2)


#设置色域范围

HSV1 = cv2.cvtColor(ims1,cv2.COLOR_BGR2HSV)
H, S, V = cv2.split(HSV1)

HSV2 = cv2.cvtColor(ims2,cv2.COLOR_BGR2HSV)
H, S, V = cv2.split(HSV2)

#色域下限
lower_red = np.array([0, 0, 46])

#色域上限
upper_red = np.array([180, 43, 220])
mask1 = cv2.inRange(HSV1, lower_red, upper_red)
mask1 = cv2.medianBlur(mask1, 5)
maskAnd1 = cv2.bitwise_and(ims1, ims1, mask=mask1)

upper_red = np.array([180, 43, 220])
mask2 = cv2.inRange(HSV2, lower_red, upper_red)
mask2 = cv2.medianBlur(mask2, 5)
maskAnd2 = cv2.bitwise_and(ims2, ims2, mask=mask2)


# 找出轮廓
gray1 = cv2.cvtColor(maskAnd1, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray1, 175, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

gray2 = cv2.cvtColor(maskAnd2, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray2, 175, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

cv2.imshow('maskAnd99', gray1)
cv2.imshow('maskAnd98', gray2)

# 圆形检测
circles1 = cv2.HoughCircles(gray1, cv2.HOUGH_GRADIENT, dp=1, minDist=50, param1=100, param2=40, minRadius=10,maxRadius=100)

circles2 = cv2.HoughCircles(gray2, cv2.HOUGH_GRADIENT, dp=1, minDist=50, param1=100, param2=40, minRadius=10,maxRadius=100)


sum = 0


if circles1 is not None:
    try:
        for circle in circles1[0]:
            # 坐标行列-圆心坐标
            x = int(circle[0])
            y = int(circle[1])
            # 半径
            r = int(circle[2])
            # 在原图用指定颜色标记出圆的边界
            cv2.circle(ims1, (x, y), r, (0, 255, 255), 3)
            # 画出圆的圆心
            cv2.circle(gray1, (x, y), r, (0, 255, 255), 3)
            circles = np.round(circles1[0, :]).astype("int")
            # 计算圆形的数量
            sum += 1
    except TypeError:
        print("一个都没打")



if circles2 is not None:
    try:
        for circle in circles2[0]:
            # 坐标行列-圆心坐标
            x = int(circle[0])
            y = int(circle[1])
            # 半径
            r = int(circle[2])
            # 在原图用指定颜色标记出圆的边界
            cv2.circle(ims2, (x, y), r, (0, 255, 255), 3)
            # 画出圆的圆心
            cv2.circle(gray2, (x, y), r, (0, 255, 255), 3)
            circles = np.round(circles2[0, :]).astype("int")
            # 计算圆形的数量
            sum += 1
    except TypeError:
        print("一个都没打")


print('螺丝个数为:', sum)
if(sum==2):
        print("OK")
else:
        print("NG")
#展示图片


cv2.imshow('maskAnd1', img)
cv2.waitKey()
cv2.destroyAllWindows()

总结

以上就是今天要讲的内容,本文通过python与open-cv的编写,来解决了螺丝检测的业务需求,感谢您的观看