封面图片:《英雄联盟》角色------黑默丁格,来自皮城的大发明家,始终热爱科学和发明
前言
最近在开发一款基于OpenCV的螺母尺寸测量系统,作为我的毕业设计,说人话就是:教计算机认识螺母,并且get"我的眼睛就是尺"技能,通过摄像头拍摄螺母图像,就能测量出尺寸参数;希望给对机器视觉感兴趣的技术爱好者们提供一些帮助
初步效果示意图,可检测出多数螺母尺寸
目前已实现基础功能,但还存在诸多待改进之处,本文主要分享软件部分的核心实现思路,后续将推出代码详解篇;为控制篇幅,Python环境配置等基础内容暂不涉及,若有需要可在评论区留言
代码结构
markdown
螺母测量系统
│
├── config.py # 参数配置文件
├── image_processor.py # 图像处理模块
├── nut_analyzer.py # 螺母分析模块
├── utils.py # 工具函数模块
└── main.py # 主程序入口
1.配置文件(config.py)
这个文件就像系统的"控制面板",集中存放所有可调节参数。当需要调整检测灵敏度时,只需修改这里的数值,无需改动其他代码
python
class Config: #定义了一个叫Config的类
# 图像预处理参数
GAUSSIAN_KSIZE = (7, 7) # 高斯模糊核大小,7x7 内核用于降噪
CANNY_THRESH1 = 10 # Canny 边缘检测低阈值,控制边缘敏感度
CANNY_THRESH2 = 80 # Canny 边缘检测高阈值,连接边缘
# 轮廓筛选参数
MIN_AREA = 1000 # 最小轮廓面积,过滤小噪声
MAX_AREA = 10000 # 最大轮廓面积,过滤过大物体
# 标定参数(需根据实际标定结果修改)
PIXELS_PER_MM = 15.5 # 每毫米像素数(通过标定板计算)
2.图像处理模块(image_processor.py)
这个模块就像"流水线工人",负责:
- 把彩色图转成灰度图(方便处理)
- 用"模糊滤镜"消除图像噪点
- 用"边缘检测"找出物体边界
- 通过"修补操作"闭合小裂缝
- 最后用"轮廓追踪"画出零件形状
python
import cv2 #导入一个叫OpenCV的库
from config import Config #从config.py文件里导入Config类
class ImageProcessor:
@staticmethod #静态方法,不用创建实例便可直接使用类
def preprocess(image): #定义了一个名为"preprocess"的方法,类中的函数称为方法
"""图像预处理流水线"""
# 转换为灰度图
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) #颜色空间转换函数,参数1是需要转换的图片,参数2是转换成何种格式。
# 高斯模糊降噪
blurred = cv2.GaussianBlur(gray, Config.GAUSSIAN_KSIZE, 0) #高斯核大小为5x5,X轴方向上的高斯核的标准差为0
# Canny边缘检测
edges = cv2.Canny(blurred, Config.CANNY_THRESH1, Config.CANNY_THRESH2) #输入图像,低阈值,高阈值
# 形态学操作(闭合小孔)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3)) #创建一个3X3的矩形结构元素
closed = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel) #对edges在3X3的矩形结构元素里使用闭运算
return closed
@staticmethod
def find_contours(processed_image):
"""轮廓检测方法"""
contours, _ = cv2.findContours( #contours是返回的轮廓列表,_ 是另一个返回值,但在这里不使用。
processed_image, #该参数表示输入的图像
cv2.RETR_EXTERNAL, #参数 mode 决定了轮廓的提取方式,这里是只检测外轮廓
cv2.CHAIN_APPROX_SIMPLE #参数 method 决定了如何表达轮廓,这里是压缩水平方向、垂直方向、对角线方向的元素,只保留该方向的终点坐标
)
return contours
3.螺母分析模块(nut_analyzer.py)
这个模块就像"质检员",负责:
- 筛掉太小的杂乱轮廓(比如螺丝、划痕)
- 用几何方法计算:
- 画最小包围圆测直径
- 画最小矩形测长宽
- 把像素尺寸转换成实际毫米单位
python
import cv2
import numpy as np
from config import Config
class NutAnalyzer:
@staticmethod
def filter_contours(contours):
"""筛选有效螺母轮廓"""
valid_contours = []
for cnt in contours:
area = cv2.contourArea(cnt) # 计算轮廓面积
if Config.MIN_AREA < area < Config.MAX_AREA: # 筛选面积在范围内的轮廓
valid_contours.append(cnt)
return valid_contours
@staticmethod
def calculate_dimensions(contour):
"""计算螺母尺寸"""
# 找最小外接圆,计算出中心点坐标、半径
(x, y), radius = cv2.minEnclosingCircle(contour)
# 找最小面积矩形,获取宽高
rect = cv2.minAreaRect(contour)
(w, h) = rect[1] # 提取矩形宽高
distance_across_flats_pixels = min(w,h) #取最小面积矩形的较小边长作为跨平距离
# 转换实际尺寸(毫米)
diameter_mm = distance_across_flats_pixels / Config.PIXELS_PER_MM
width_mm = w / Config.PIXELS_PER_MM
height_mm = h / Config.PIXELS_PER_MM
#将直径、宽度和高度的数值四舍五入到小数点后两位
return {
"diameter": round(diameter_mm, 2),
"width": round(width_mm, 2),
"height": round(height_mm, 2)
}
4.工具模块(utils.py)
这个模块就像"报告生成器",把检测结果用绿色框线标出,并在图片上显示测量数值。
python
import cv2
def draw_measurements(image, contours, dimensions):
"""可视化标注工具"""
for cnt, dim in zip(contours, dimensions): #遍历每个轮廓和对应的尺寸。
# 使用 cv2.drawContours绘制轮廓,颜色为绿色,线宽为2。
cv2.drawContours(image, [cnt], 0, (0, 255, 0), 2)
# 标注文字,显示该轮廓的直径信息
text = f"across_flats:{dim['diameter']}mm"
x, y, _, _ = cv2.boundingRect(cnt) #通过 cv2.boundingRect获取轮廓的边界框,用于确定文本的放置位置
cv2.putText(image, text, (x, y-10), #使用 cv2.putText 在图像上添加直径文本,文本颜色为红色,字体大小为0.7,线宽为2。
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
return image #返回绘制完标注的图像。
5.主程序(main.py)
主程序像"工厂老板",按步骤指挥各个模块运作:
- 进货(读取图片)
- 粗加工(对图片进行预处理)
- 精加工(找螺母轮廓)
- 质量筛检(过滤不合格的轮廓)
- 测量尺寸
- 打标签(可视化)
- 出货(显示结果)
python
import cv2 #导入OpenCV库
from image_processor import ImageProcessor #从"image_processor"库中导入ImageProcessor类
from nut_analyzer import NutAnalyzer #从"nut_analyzer"库中导入NutAnalyzer类
from utils import draw_measurements #从"utils"库中导入draw_measurements函数
def main(): #定义main函数
# 1. 读取输入
image = cv2.imread("Nut.jpg") #读取全称为"Nut.jpg"的图像
# 2. 图像预处理
processed = ImageProcessor.preprocess(image) #调用ImageProcessor类里的preprocess()方法
# 3. 轮廓检测
contours = ImageProcessor.find_contours(processed) #调用ImageProcessor类里的find_contours()方法
# 4. 筛选螺母轮廓
valid_contours = NutAnalyzer.filter_contours(contours) #调用NutAnalyzer类里的filter_contours()方法
# 5. 尺寸计算
dimensions = [NutAnalyzer.calculate_dimensions(cnt) #调用NutAnalyzer类里的calculate_dimensions()方法
for cnt in valid_contours]
# 6. 可视化结果
result_image = draw_measurements(image.copy(), valid_contours, dimensions) #调用utils.py里的draw_measurements()函数
# 7. 显示输出
cv2.imshow("Measurement Result", result_image) #给窗口命名为"Measurement Result"并显示图像
if __name__ == "__main__":
main() # 相当于启动"检测流水线"的开关
系统工作原理示意图
可优化细节
- 图片中9个螺母只能识别出7个
- 无法在图像中显示中文注释
- 没有区分圆形螺母和六角螺母
- 目前只能显示六角螺母的跨平距离,可以再加上对角直径、孔直径等参数
- 可以尝试用函数进行动态调参
cv2.createTrackbar
本项目的完整代码库后续会在GitHub上开源(地址将会发到评论区),欢迎各位技术爱好者在评论区留言,共同探讨改进方案;下期将深入解析代码以及OpenCV库,敬请期待!