齿轮图像缺陷检测:如何在原图上高亮显示齿部缺陷?
齿轮齿部缺陷高亮显示实现方案
问题背景
我正在开展一个齿轮图像检测项目,需判定齿轮图像为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)
关键修改说明
- 保留原始图像副本:创建
original_img避免中间绘图操作对最终高亮效果的干扰。 - 生成缺陷掩码:通过
cv2.subtract(thresh, zoubky)得到齿部缺陷的掩码区域——原始阈值图像保留了所有明暗差异,齿部掩码仅保留正常齿部,相减后剩下的就是缺陷区域。 - 映射缺陷坐标:将裁剪区域内的缺陷轮廓坐标转换为原始图像的全局坐标,确保高亮位置准确。
- 高亮缺陷:使用红色填充缺陷区域(或绘制边框),在原始图像上直观展示缺陷位置。
内容的提问来源于stack exchange,提问作者paradox98
相关产品推荐
相关产品推荐

