You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

齿轮图像缺陷检测:如何在原图上高亮显示齿部缺陷?

齿轮齿部缺陷高亮显示实现方案

问题背景

我正在开展一个齿轮图像检测项目,需判定齿轮图像为OK(合格)或NOK(不合格),判定依据是齿部的最小像素缺陷尺寸。目前已完成以下开发:定位齿轮中心,绘制半径为「齿轮半径-缺陷像素值」的圆,提取齿部区域并通过计数齿部轮廓(标准齿数为19)判定OK/NOK。现有问题:需要在原始齿轮图像上高亮显示齿部缺陷,但不知如何实现。

解决方案

要实现齿部缺陷高亮,核心思路是提取齿部缺陷区域的掩码,再将缺陷轮廓映射回原始图像并标记。以下是修改后的完整代码,关键步骤已添加注释:

import math
import cv2

rozmer_kolecka = 12.8  # 齿轮直径(毫米)
velikost_defektu = 0.25  # 最小缺陷尺寸(毫米)

def detect_defects(img):
    # 保留原始图像副本用于最终高亮(避免中间绘图操作干扰)
    original_img = img.copy()
    
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    blur = cv2.GaussianBlur(gray, (5, 5), cv2.BORDER_DEFAULT)
    ret, thresh = cv2.threshold(blur, 200, 255, cv2.THRESH_BINARY_INV)
    
    contours, hierarchies = cv2.findContours(thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
    cx = []
    cy = []

    for c in contours:
        M = cv2.moments(c)
        if M['m00'] != 0:
            cx.append(int(M['m10']/M['m00']))
            cy.append(int(M['m01']/M['m00']))

    hledana_souradnice_x = None
    for i in range(len(cx)):
        cx_hledane = cx[i]
        cy_hledane = cy[i]
        for k in range(len(cx)):
            if (i != k) and ((cx_hledane == cx[k]) or ((cx_hledane - 1) == cx[k]) or ((cx_hledane - 2) == cx[k]) or ((cx_hledane +1) == cx[k]) or ((cx_hledane + 2) == cx[k])):
                if ((cy_hledane == cy[k]) or ((cy_hledane - 1) == cy[k]) or ((cy_hledane - 2) == cy[k]) or ((cy_hledane + 1) == cy[k]) or ((cy_hledane + 2) == cy[k])):
                    hledana_souradnice_x = cx_hledane
                    break
        if hledana_souradnice_x is not None:
            break

    kontura = None
    for i in range(len(contours)):
        M = cv2.moments(contours[i])
        if M['m00'] != 0:
            if hledana_souradnice_x == int(M['m10']/M['m00']):
                kontura = contours[i]
                break

    M = cv2.moments(kontura)
    if M['m00'] != 0:
        cx = int(M['m10']/M['m00'])  # 齿轮中心X坐标
        cy = int(M['m01']/M['m00'])  # 齿轮中心Y坐标
        cv2.drawContours(img, [kontura], -1, (0, 255, 0), 2)
        x, y, w, h = cv2.boundingRect(kontura)
    cv2.imwrite("ObrysOzubenehoKolecka.jpg", img)

    polomer_kolecka_px = math.ceil(w/2)  # 齿轮半径(像素)
    pomer = polomer_kolecka_px / (rozmer_kolecka / 2)  # 像素/毫米比例

    img = cv2.circle(img, (cx, cy), polomer_kolecka_px - math.ceil(velikost_defektu * pomer) , (0, 0, 255), 1)
    cv2.imwrite("Kruznice_Vada.jpg", img)

    # 生成齿部区域掩码:涂黑内部,仅保留齿部
    zoubky = cv2.circle(thresh.copy() ,(int(cx),int(cy)), polomer_kolecka_px - math.ceil(velikost_defektu * pomer), 0, -1)
    cv2.imwrite("ZubyOzubenehoKolecka.jpg", zoubky)

    # 计算缺陷掩码:原始阈值图像减去齿部掩码,得到缺陷区域
    defect_mask = cv2.subtract(thresh, zoubky)
    cv2.imwrite("Defect_Mask.jpg", defect_mask)

    vyrez = zoubky[cy - 150:cy + 150, cx - 150:cx + 150]
    cv2.imwrite("VyrezOzubenehoKolecka.jpg", vyrez)
    (cnt, hierarchy) = cv2.findContours(vyrez, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

    # 提取缺陷轮廓并在原始图像上高亮
    defect_contours, _ = cv2.findContours(defect_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    for dc in defect_contours:
        # 将裁剪区域的坐标映射回原始图像坐标
        dc[:, :, 0] += cx - 150
        dc[:, :, 1] += cy - 150
        # 用红色填充缺陷区域(也可改用drawContours的thickness=2绘制边框)
        cv2.drawContours(original_img, [dc], -1, (0, 0, 255), thickness=cv2.FILLED)
    
    # 保存带有缺陷高亮的图像
    cv2.imwrite("Defect_Highlighted.jpg", original_img)

    if(len(cnt) < 19):
        print("NOK")
        return False
    else:
        print("OK")
        return True

obrazek = cv2.imread('Obrazky\\NOK.jpg')
detect_defects(obrazek)

关键修改说明

  1. 保留原始图像副本:创建original_img避免中间绘图操作对最终高亮效果的干扰。
  2. 生成缺陷掩码:通过cv2.subtract(thresh, zoubky)得到齿部缺陷的掩码区域——原始阈值图像保留了所有明暗差异,齿部掩码仅保留正常齿部,相减后剩下的就是缺陷区域。
  3. 映射缺陷坐标:将裁剪区域内的缺陷轮廓坐标转换为原始图像的全局坐标,确保高亮位置准确。
  4. 高亮缺陷:使用红色填充缺陷区域(或绘制边框),在原始图像上直观展示缺陷位置。

内容的提问来源于stack exchange,提问作者paradox98

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 17:08:12