复习opencv:螺丝螺纹缺陷检测

简述

  • 今天收到了一个检测螺牙缺陷的问题,当复习opencv练个手,记录一下基础知识。
  • 这里的代码是检测弯曲的,其他缺陷用yolo处理。
  • 东家给的图片有的是有干扰的(红框标识),所以要求一下最大凸包。
    在这里插入图片描述
  • 里面很多知识是复习用,最终代码在最后一行,给的101张图片,有2个弯曲度超过0.25,来到了0.33以上
  • 有个小技巧可以提高弯直的区分度,这里就不介绍了,需要的私信。

去噪

椒盐噪声

import cv2

img = cv2.imread('image.jpg')
median = cv2.medianBlur(img, 5)
cv2.imshow('Median filter', median)
cv2.waitKey(0)
cv2.destroyAllWindows()

高斯噪声

import cv2

img = cv2.imread('image.jpg')
gaussian = cv2.GaussianBlur(img, (5,5), 0)
cv2.imshow('Gaussian filter', gaussian)
cv2.waitKey(0)
cv2.destroyAllWindows()

小波变换

import cv2
import pywt

img = cv2.imread('image.jpg', 0)
coeffs = pywt.dwt2(img, 'haar')
cA, (cH, cV, cD) = coeffs
cv2.imshow('Wavelet denoising', pywt.idwt2((cA, (None, None, None)), 'haar'))
cv2.waitKey(0)
cv2.destroyAllWindows()

引导滤波

import numpy as np
import cv2

main_path="D:/Handletiling/NG_org_20230602103406819.bmp"

def guideFilter(I, p, winSize, eps):

    mean_I = cv2.blur(I, winSize)    
    mean_p = cv2.blur(p, winSize)       

    mean_II = cv2.blur(I * I, winSize)  
    mean_Ip = cv2.blur(I * p, winSize) 

    var_I = mean_II - mean_I * mean_I  
    cov_Ip = mean_Ip - mean_I * mean_p  

    a = cov_Ip / (var_I + eps)        
    b = mean_p - a * mean_I          

    mean_a = cv2.blur(a, winSize)     
    mean_b = cv2.blur(b, winSize)     

    q = mean_a * I + mean_b
    return q


if __name__ == '__main__':
    eps = 0.01
    winSize = (5,5)
    image = cv2.imread(main_path, cv2.IMREAD_ANYCOLOR)
    image = cv2.resize(image, None,fx=0.7, fy=0.7, interpolation=cv2.INTER_CUBIC)
    I = image/255.0        #将图像归一化
    p =I
    guideFilter_img = guideFilter(I, p, winSize, eps)

    # 保存导向滤波结果
    guideFilter_img  = guideFilter_img  * 255
    guideFilter_img [guideFilter_img  > 255] = 255
    guideFilter_img  = np.round(guideFilter_img )
    guideFilter_img  = guideFilter_img.astype(np.uint8)
    cv2.imshow("image",image)
    cv2.imshow("winSize_5", guideFilter_img )
    cv2.waitKey(0)
    cv2.destroyAllWindows()

求最大凸包

import cv2
import os
import numpy as np
from skimage.measure import label

main_path="D:\Handletiling\luoya/NG/NG_org_20230602103407364.bmp"

##method1 --opencv
def get_lagrest_connect_component1(img):

    # rgb->gray
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # gaussian filter
    img_gray = cv2.GaussianBlur(img_gray, (5, 5), 0)
    # binary exp-threshold=0
    # https://blog.csdn.net/weixin_42272768/article/details/110746790
    _, img_gray = cv2.threshold(img_gray, 0, 255, cv2.THRESH_BINARY_INV)  # ret==threshold
    # find contour
    contours, _ = cv2.findContours(img_gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    # cv2.drawContours(img_gray, contours, -1, 255, 3)

    # find the area_max region
    area = []
    for i in range(len(contours)):
        area.append(cv2.contourArea(contours[i]))
    if len(area) >= 1:
        max_idx = np.argmax(area)
        max_contour_area = area[max_idx]

        for k in range(len(contours)):
            if k != max_idx:
                cv2.fillPoly(img_gray, [contours[k]], 0)
    else:
        max_contour_area = 0

    return max_contour_area, img_gray

if __name__ == '__main__':
    img = cv2.imread(main_path)
    max_area, img_gray = get_lagrest_connect_component1(img)
    print(max_area)
    cv2.imwrite('img_gray.jpg', img_gray)

判断曲直

1.查找轮廓,提取凸包
2.获得点集
3.计算导数方差
4.比较阈值

def calccurl(str,thresh):
    img = cv2.imread(str)
    # cv2.imshow('src',img)
    #提取凸包
    max_area, img_gray =get_lagrest_connect_component1(img)

    gray = img_gray
    #阈值处理
    ret,binary = cv2.threshold(gray,127,255,0)
    #查找轮廓,提取凸包
    contours,hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
    hull = cv2.convexHull(contours[0])
    cv2.polylines(img_gray,[hull],True,(255,255,0),2)
    min_x=min(hull[:,0,0])
    max_x=max(hull[:,0,0])
    topList=[]
    bottomList=[]
    thresh_left=220
    thresh_right=30
    count=hull.shape[0]
    isthesame=False
    for i in range(hull.shape[0]):
        point = tuple(hull[i][0]) #  
        # cv2.circle(img, point, 1, (0, 255, 0) , 12)
        if point[0]<(max_x-thresh_right) and point[0]>(min_x+thresh_left):
            length=binary.shape[0]
            x1 = np.linspace(start=0, stop=length-1, num=length)
            temp=x1 * (binary[:, point[0]] / 255)
            n = np.sum(temp > 0)
            index=temp.sum()/(n*1.)
            # if i in[0,count-1]:
            #     if not isthesame:
            #         isthesame=True
            #     else:
            #         continue
            if point[1]>index:
                bottomList.append(point)
            else:
                topList.append(point)    

    space = np.linspace(start=min_x+thresh_left, stop=max_x-thresh_right, num=15)
    space= np.ceil(space)
    length = img_gray.shape[0]
    x1 = np.linspace(start=0, stop=length - 1, num=length)
    tempM = (img_gray / 255.)* x1[:,None]

    if len(topList) >len(bottomList):
        topList.clear()
        for x in space:
            temp=tempM[:, int(x)]
            temp = temp[temp != 0]
            topList.append([x,temp.min()])

        line = np.array(topList, dtype=float)

    else:
        bottomList.clear()
        for x in space:
            temp = tempM[:, int(x)]
            temp = temp[temp != 0]
            bottomList.append([x, temp.max()])

        line = np.array(bottomList, dtype=float)
       if line.size > 0:
        #method1
        slopend=(line[-1,1]-line[0,1])/(line[-1,0]-line[0,0])
        slop=(line[1:,1]-line[:-1,1])/((line[1:,0]-line[:-1,0])+0.0001)
        dis=slop-slopend
        std = np.std(dis)
        if std>thresh:
            return 0,std

    return 1,0
        # method2
        # std= np.std(slop)


if __name__ == '__main__':
    filesPath = os.listdir(main_path)
    threshstd=0.025

    files = tqdm(filesPath)
    for file in files:
        absolute_file_path = os.path.join(main_path, file)
        if '.bmp' in absolute_file_path.lower():
            result,std=calccurl(absolute_file_path,threshstd)
            if result:
                print(absolute_file_path+":", std)

在这里插入图片描述

结果
--------------------
std: 0.037498851806574245

全部代码

import cv2
import numpy as np

import os
from tqdm import tqdm
import shutil

#需要检测弯曲的图片的文件夹地址
main_path="D:\Handletiling\src"

def get_lagrest_connect_component1(img):

    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    img_gray = cv2.GaussianBlur(img_gray, (5, 5), 0)

    _, img_gray = cv2.threshold(img_gray, 0, 255, cv2.THRESH_BINARY_INV)  # ret==threshold

    contours, _ = cv2.findContours(img_gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    area = []
    for i in range(len(contours)):
        area.append(cv2.contourArea(contours[i]))
    if len(area) >= 1:
        max_idx = np.argmax(area)
        max_contour_area = area[max_idx]

        for k in range(len(contours)):
            if k != max_idx:
                cv2.fillPoly(img_gray, [contours[k]], 0)
    else:
        max_contour_area = 0

    return max_contour_area, img_gray

def calccurl(str,thresh):
    img = cv2.imread(str)

    #提取凸包
    max_area, img_gray =get_lagrest_connect_component1(img)

    gray = img_gray
    #阈值处理
    ret,binary = cv2.threshold(gray,127,255,0)
    #查找轮廓
    contours,hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
    hull = cv2.convexHull(contours[0])
    cv2.polylines(img_gray,[hull],True,(255,255,0),2)
    min_x=min(hull[:,0,0])
    max_x=max(hull[:,0,0])
    topList=[]
    bottomList=[]
    thresh_left=220
    thresh_right=30
    count=hull.shape[0]
    isthesame=False
    for i in range(hull.shape[0]):
        point = tuple(hull[i][0]) #
        # cv2.circle(img, point, 1, (0, 255, 0) , 12)
        if point[0]<(max_x-thresh_right) and point[0]>(min_x+thresh_left):
            length=binary.shape[0]
            x1 = np.linspace(start=0, stop=length-1, num=length)
            temp=x1 * (binary[:, point[0]] / 255)
            n = np.sum(temp > 0)
            index=temp.sum()/(n*1.)
            # if i in[0,count-1]:
            #     if not isthesame:
            #         isthesame=True
            #     else:
            #         continue
            if point[1]>index:
                bottomList.append(point)

            else:
                topList.append(point)


    space = np.linspace(start=min_x+thresh_left, stop=max_x-thresh_right, num=15)
    space= np.ceil(space)
    length = img_gray.shape[0]
    x1 = np.linspace(start=0, stop=length - 1, num=length)
    tempM = (img_gray / 255.)* x1[:,None]

    if len(topList) >len(bottomList):
        topList.clear()
        for x in space:
            temp=tempM[:, int(x)]
            temp = temp[temp != 0]
            topList.append([x,temp.min()])

        line = np.array(topList, dtype=float)

    else:
        bottomList.clear()
        for x in space:
            temp = tempM[:, int(x)]
            temp = temp[temp != 0]
            bottomList.append([x, temp.max()])

        line = np.array(bottomList, dtype=float)
    if line.size > 0:
        #method1
        slopend=(line[-1,1]-line[0,1])/(line[-1,0]-line[0,0])
        slop=(line[1:,1]-line[:-1,1])/((line[1:,0]-line[:-1,0])+0.0001)
        dis=slop-slopend
        std = np.std(dis)
        if std>thresh:
            return 0,std

    return 1,0
        # method2
        # std= np.std(slop)

  

if __name__ == '__main__':
    filesPath = os.listdir(main_path)
    threshstd=0.025

    files = tqdm(filesPath)
    for file in files:
        absolute_file_path = os.path.join(main_path, file)
        if '.bmp' in absolute_file_path.lower():
            result,std=calccurl(absolute_file_path,threshstd)
            if not result:
                print(absolute_file_path+"-图片弯曲:", std)
#结果
[00:00<00:01, 44.18it/s]D:\Handletiling\src\NG_org_20230602103409544.bmp-图片弯曲: 0.0334415572613885
[00:00<00:01, 44.24it/s]D:\Handletiling\src\NG_org_20230602103410530.bmp-图片弯曲: 0.037498851806574245
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值