Files

101 lines
4.4 KiB
Python
Raw Permalink Normal View History

2025-10-21 14:11:52 +08:00
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()