import cv2 import numpy as np # 读取图像(以灰度模式加载) # 作用:将 '1.jpg' 图像读入内存,转换为单通道灰度图,便于后续图像处理 # 注意:如果路径错误或文件不存在,image 将为 None,导致后续报错 image = cv2.imread('1.jpg', cv2.IMREAD_GRAYSCALE) # 检查图像是否成功加载 if image is None: raise FileNotFoundError("无法读取图像,请检查文件路径是否正确:'1.jpg'") # 均值滤波,滤波核大小为7x7 # 作用:对图像进行平滑处理,去除高频噪声(如随机噪点) # 原理:用每个像素周围7x7邻域的平均值替换该像素值,使图像更“柔和” blurred = cv2.blur(image, (7, 7)) # 使用局部自适应阈值进行图像分割 # 作用:将图像二值化,突出比局部背景更暗的区域(如划痕、凹坑等缺陷) # 参数说明: # - cv2.ADAPTIVE_THRESH_MEAN_C:阈值基于局部邻域的平均值 # - 11:邻域大小(奇数),决定局部范围 # - 2:从均值中减去的常数,用于微调灵敏度 # - cv2.THRESH_BINARY_INV:反转结果,缺陷区域为白色(255),背景为黑色(0) thresholded = cv2.adaptiveThreshold( blurred, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, 11, 2 ) # 查找图像中的轮廓 # 作用:检测二值图像中所有连通的白色区域(即潜在缺陷) # 返回值: # - contours: 所有轮廓的坐标点列表 # - _ : 轮廓的层级关系(此处不需要) # 方法选择: # - cv2.RETR_LIST:提取所有轮廓,不建立层级 # - cv2.CHAIN_APPROX_SIMPLE:压缩水平/垂直/对角线方向的轮廓点,节省内存 contours, _ = cv2.findContours(thresholded, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) # 创建一个彩色图像用于结果显示 # 作用:将原始灰度图转换为BGR三通道图像,以便用不同颜色绘制检测结果 output_image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR) # 对每个检测到的轮廓进行面积筛选 # 作用:过滤掉太小(可能是噪声)或太大(可能是背景干扰)的区域 # 设置面积阈值范围:250 ~ 1000 像素 min_area, max_area = 250, 1000 for contour in contours: area = cv2.contourArea(contour) # 计算轮廓包围的面积 if min_area < area < max_area: # 绘制符合条件的轮廓 # 颜色:绿色 (0, 255, 0),线宽:2 cv2.drawContours(output_image, [contour], -1, (0, 255, 0), 2) # 形态学膨胀操作 # 作用:扩大二值图像中的白色区域,连接邻近的断裂缺陷(如断开的划痕) # 结构元素:椭圆形(模拟圆形),大小为7x7 # iterations=1:执行一次膨胀 kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7, 7)) dilated = cv2.dilate(thresholded, kernel, iterations=1) # 骨架化处理(细化为单像素宽的中心线) # 作用:将膨胀后的缺陷区域“细线化”,便于分析划痕的路径和长度 # 注意:OpenCV 无内置骨架化函数,这里使用经典的Zhang-Suen细化算法简化版 def thinning(img): skel = np.zeros(img.shape, np.uint8) # 存储骨架结果 size = np.size(img) element = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3)) # 3x3十字结构元 done = False while not done: # 重复执行:腐蚀 → 膨胀 → 差分 → 累加到骨架 eroded = cv2.erode(img, element) # 腐蚀:缩小区域 temp = cv2.dilate(eroded, element) # 膨胀回来 temp = cv2.subtract(img, temp) # 得到最外层轮廓(即“剥皮”一层) skel = cv2.bitwise_or(skel, temp) # 累加到骨架图像 img = eroded.copy() # 更新图像为腐蚀后的结果 # 当图像完全变黑(无非零像素)时停止 zeros = size - cv2.countNonZero(img) if zeros == size: done = True return skel # 执行骨架化 skeleton = thinning(dilated) # 显示所有中间结果和最终检测图 # 作用:可视化每一步的处理效果,便于调试和分析 cv2.imshow("Original Image", image) # 原始灰度图 cv2.imshow("Thresholded Image", thresholded) # 自适应阈值分割结果 cv2.imshow("Dilated Image", dilated) # 膨胀后结果 cv2.imshow("Skeletonized Image", skeleton) # 骨架化结果(细线) cv2.imshow("Detected Regions", output_image) # 最终检测结果(绿色轮廓) # 等待按键后关闭所有窗口 cv2.waitKey(0) cv2.destroyAllWindows()