1. 基于OpenCV的划痕检测基础
任务目标
使用OpenCV对金属表面图像中的划痕进行检测,输出划痕的像素位置(最小外接矩形中心)与长度(像素单位),并在图像上可视化标注检测结果。
环境依赖
Python 3.8+,OpenCV 4.5+,NumPy。安装命令:pip install opencv-python numpy
实现思路
划痕在金属表面通常表现为低灰度值的细长暗线。本案例采用以下处理链路:灰度化 → 高斯模糊降噪 → 自适应阈值提取暗部区域 → 形态学闭运算连接断裂线段 → 查找轮廓 → 按面积与长宽比过滤非划痕噪声 → 输出并标注结果。
关键完整代码
import cv2
import numpy as np
def detect_scratch(image_path):
# 读取图像
img = cv2.imread(image_path)
if img is None:
raise ValueError("无法读取图像,请检查路径")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 高斯模糊抑制噪声
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
# 自适应阈值提取暗色划痕区域(划痕比背景暗)
thresh = cv2.adaptiveThreshold(
blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY_INV, 11, 2
)
# 形态学闭运算连接断裂的划痕线段
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 3))
closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=2)
# 查找轮廓
contours, _ = cv2.findContours(closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
results = []
for cnt in contours:
area = cv2.contourArea(cnt)
if area < 30: # 过滤极小噪声
continue
# 最小外接矩形
rect = cv2.minAreaRect(cnt)
(cx, cy), (w, h), angle = rect
length = max(w, h) # 划痕长度取矩形长边
# 长宽比过滤:划痕应为细长形状
if length < 10 or min(w, h) == 0:
continue
aspect_ratio = length / min(w, h)
if aspect_ratio < 2.0: # 非细长形状视为非划痕
continue
# 绘制检测结果
box = cv2.boxPoints(rect)
box = np.int0(box)
cv2.drawContours(img, [box], 0, (0, 0, 255), 2)
cv2.circle(img, (int(cx), int(cy)), 3, (0, 255, 0), -1)
results.append({
"center": (round(cx, 1), round(cy, 1)),
"length_px": round(length, 1),
"angle_deg": round(angle, 1)
})
return img, results
if __name__ == "__main__":
# 使用示例(替换为实际图像路径)
img_out, scratches = detect_scratch("metal_scratch.jpg")
print(f"检测到 {len(scratches)} 条划痕:")
for i, s in enumerate(scratches):
print(f" 划痕{i+1}: 中心位置{s['center']}, 长度{s['length_px']}px, 角度{s['angle_deg']}°")
cv2.imwrite("scratch_result.jpg", img_out)
print("结果图像已保存为 scratch_result.jpg")
运行与验证
- 准备一张包含划痕的金属表面图像(建议亮背景、暗划痕),命名为
metal_scratch.jpg放在脚本同目录。 - 运行脚本:
python scratch_detection.py - 观察终端输出:应打印每条划痕的中心坐标与像素长度。
- 打开生成的
scratch_result.jpg:划痕被红色矩形框标注,中心点有绿色圆点标记。
通过判定标准:图像中肉眼可见的划痕均被红色框包围,且每个框内包含一条完整划痕;终端输出的划痕数量与图像中划痕数量一致;长度数值与图像中划痕的像素尺度相符(可用图像编辑软件测量对比)。
常见问题
- 检测不到划痕:若划痕过浅,可降低自适应阈值参数
blockSize(如从11改为7)或增大C值(从2改为3);若划痕断裂严重,增大闭运算迭代次数或kernel尺寸。 - 误检过多:提高面积阈值(30→50)或长宽比阈值(2.0→3.0)。
- 划痕为亮色:若划痕比背景亮,将
THRESH_BINARY_INV改为THRESH_BINARY。
上图展示了检测效果示意:红色矩形为划痕的最小外接框,绿色圆点标记划痕中心位置。实际输出坐标与长度以终端打印数值为准。