我最初接触计算机视觉那会儿,最发愁的事情不是看不懂算法公式,而是不知道从哪里开始。打开一篇文章全是“金字塔”“光流”“HOG”这些词,每个都认识,连在一起就不知道谁是谁。后来在几个实际项目里磨了几年,从智能车赛道线提取做到工业缺陷检测,从OpenCV传统方法切到YOLO系列做目标检测,才慢慢理出一条清晰的主线。
这篇“计算机视觉图像处理常用方法汇总”,就是想把这条主线完整串一遍:从最底层的像素级图像处理,到特征工程,再到深度学习方法,最后落到工程工具选型。不管你是刚入门的学生,还是已经会用一点OpenCV但总觉得不成体系的工程师,都能从中找到一条适合自己的技术路线。我会把每个方法背后的“为什么”也讲清楚,因为只抄代码不搞懂原理,换一个场景就废了。
1. 计算机视觉与图像处理:先把概念边界理清楚
1.1 图像处理和计算机视觉到底是不是一回事
很多人把图像处理和计算机视觉混着用,但严格来说,两者是有层次的。图像处理更偏底层,输入是图像,输出通常还是图像,比如去噪、锐化、灰度变换、形态学处理,目的是改善图像的“质量”或者“表现形式”,并不关心图里到底是什么东西。
计算机视觉则更高一层,输入可以是图像,但输出往往是语义信息——这个图里有没有人、人在什么位置、病灶区域在哪儿、车道线怎么走。到了这个阶段,算法已经不仅仅在“处理像素”,而是在“理解内容”。
但在实际工程里,这两层是深度耦合的。比如做遥感图像分析,你先要用图像处理的手段做辐射校正、几何校正、图像融合,然后才能做地物分类和目标识别。又比如做智能车视觉,第一步往往是灰度化、二值化、去噪,这些是图像处理;再往后提取边界、计算中线、判断弯道方向,就已经进入计算机视觉的范畴了。
所以回答“计算机视觉与图像处理有哪些方法”这个问题,不能只讲深度学习那一套,也不能只讲滤波二值化那一套,而是要把从“像素到语义”整个链条上的方法都覆盖到,才能真正用于实战。
1.2 常用方法的整体版图
我习惯把常用方法分成四个层次,每个层次解决不同的问题:
| 层次 | 典型方法 | 解决什么问题 |
|---|---|---|
| 底层像素处理 | 灰度变换、直方图均衡、各种滤波、形态学 | 改善图像质量、去除干扰 |
| 特征提取与分割 | 边缘检测、阈值分割、连通域、颜色空间、关键点特征 | 把像素压缩成有意义的结构或特征 |
| 传统机器学习 | HOG+SVM、随机森林、聚类 | 在手工特征上做分类与识别 |
| 深度学习 | CNN分类、目标检测、语义分割 | 端到端学习特征并完成高层视觉任务 |
| 工程化与硬件化 | OpenCV优化、ISP算法、FPGA加速 | 把算法稳定高效地跑起来 |
这四个层次不是互相替代的关系,而是叠加关系。哪怕是2025年了,做工业视觉项目,传统图像处理依然是主力,深度学习很多时候只是用来补传统方法搞不定的那部分。
2. 传统图像处理方法的基石:预处理、滤波与形态学
2.1 图像增强与预处理:一切算法的基础
拿到一张图,第一件事永远不是急着上模型,而是先看图像质量。光照不均匀、对比度太低、存在噪声,这些问题如果不处理,后面做分割、做特征匹配都会翻车。
最常用的增强手段是灰度化和直方图均衡化。灰度化就是把三通道的彩色图变成一个通道的亮度图,公式是加权平均:
gray = 0.299*R + 0.587*G + 0.114*B这个权重不是拍脑袋定的,而是根据人眼对不同颜色的敏感度来的。绿色权重最高,因为人眼对绿色最敏感,蓝色最不敏感。
直方图均衡化是另一个我几乎每个项目都会试一下的操作。它的本质是用累积分布函数对灰度值做重映射,让原本集中在很小灰度区间的像素分布拉开。举个例子,一张阴天拍的户外照片,灰度值全挤在60到90之间,人眼看就是灰蒙蒙一片。均衡化之后,灰度范围会被拉到接近0到255,对比度会肉眼可见地提升。
在OpenCV里就两行代码:
import cv2 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) eq = cv2.equalizeHist(gray)不过要注意,直方图均衡化在光照本身就不均匀的场景下反而容易放大局部过曝。这时候我更建议用CLAHE(受限自适应直方图均衡化),它把图像分成小块分别均衡,再用双线性插值拼回去,同时限制对比度增幅,效果比全局均衡稳得多。用在工业检测的复杂光照场景里,比盲目全局均衡靠谱。
2.2 滤波去噪:在平滑与保留细节之间找平衡
滤波是图像处理里的重头戏,但很多新手一上来就乱选。均值滤波、高斯滤波、中值滤波、双边滤波,效果差很多,适用场景也完全不同。
| 滤波方式 | 原理 | 优势 | 劣势 | 典型场景 |
|---|---|---|---|---|
| 均值滤波 | 邻域均值替换中心像素 | 简单快速 | 模糊边缘和细节 | 快速预览、简单降噪 |
| 高斯滤波 | 按高斯权重加权邻域 | 平滑自然、去高斯噪声好 | 仍会模糊边缘 | 边缘检测前的预处理 |
| 中值滤波 | 取邻域中值替换中心像素 | 对椒盐噪声极有效 | 计算稍慢 | 去除孤立的黑白噪点 |
| 双边滤波 | 空间距离+灰度差双重权重 | 去噪同时保边 | 参数敏感、速度较慢 | 保边平滑、美颜磨皮 |
这里我想重点说下高斯滤波的sigma选择。很多人直接用默认参数,但sigma决定了平滑程度。经验上,sigma和核大小有个常用换算关系:
sigma = 0.3 * ((ksize - 1) * 0.5 - 1) + 0.8如果你手工指定核大小为5,那么sigma大约取1.1左右比较合理。核太大了,小目标的边缘会被平滑掉;核太小,噪声又压不下去。
还有个大坑是滤波对边缘的影响。无论做Canny边缘检测还是图像分割,如果先用大核高斯滤波,细节边缘会丢失。我通常的策略是:先降噪,但降噪强度尽量保守,后续用形态学操作来恢复或过滤,而不是暴力加大滤镜核。
2.3 形态学操作:膨胀、腐蚀与组合操作
形态学操作的基础是膨胀和腐蚀。膨胀是让亮区域变大,腐蚀是让亮区域变小。它们都依赖一个结构元素,也就是一个小的二值模板,比如3x3的矩形、椭圆、十字形。
膨胀的原理是,只要结构元素范围内有一个像素是1,输出就是1;腐蚀相反,结构元素范围内必须全是1,输出才是1。可以理解为,膨胀是“扩张领地”,腐蚀是“收缩边界”。
实际操作中很少单独用膨胀或腐蚀,而是一起搭配成开运算和闭运算。开运算是先腐蚀后膨胀,用于去除小白点和小毛刺,同时尽量保持主体大小不变。闭运算是先膨胀后腐蚀,用于填充内部小孔和缝隙。我做过一个PCB焊点缺陷检测,焊点内部的微小气泡在图像上就是黑色小孔,一个闭运算就能很好地把孔洞填平,再用开运算清掉背景杂质,效果立竿见影。
OpenCV里直接调用:
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)) opening = cv2.morphologyEx(bin_img, cv2.MORPH_OPEN, kernel) closing = cv2.morphologyEx(bin_img, cv2.MORPH_CLOSE, kernel)结构元素的选择有个小窍门:想保留目标形状就用椭圆结构元素,它比矩形更平滑;追求速度和对角方向的细致处理,可以用十字形;纯矩形速度快,但容易把圆形目标搞成方角。对于实时系统,我一般先用矩形,能跑通再换椭圆看效果差异。
形态学梯度(膨胀减腐蚀)还能得到目标轮廓,在某些场景比Canny边缘检测更稳定,因为形态学基于区域而不是梯度,对噪声的鲁棒性更好。
3. 边缘检测、分割与关键点特征:让算法“看到”内容
3.1 边缘检测:从Sobel到Canny的完整演进
边缘检测的本质是找图像灰度变化剧烈的地方,数学上就是梯度。Sobel算子用两个3x3核分别计算水平梯度和垂直梯度,速度快,适合实时场景,但对噪声敏感。Scharr是Sobel的加强版,权重更大,对边缘方向更敏感。
实际项目里最常用的还是Canny边缘检测,因为它把边缘检测做成了一个完整流程:先用高斯滤波平滑,再用Sobel算梯度,然后非极大值抑制把梯度方向上的非最大点去掉,最后用双阈值检测和滞后连接把弱边缘连起来。
Canny的两个阈值非常关键。高阈值决定了哪些像素一定是边缘,低阈值决定了哪些弱边缘可以被保留连接。经验比例是1:2或1:3,比如(50, 150)。如果检测出来的边缘断断续续,说明低阈值太高了,可以降到30甚至20;如果边缘太多太杂,说明阈值整体偏低,需要抬高高阈值。
OpenCV里这样调:
edges = cv2.Canny(cv2.GaussianBlur(gray, (3, 3), 0), 50, 150)我的习惯是先不加高斯滤波,直接用Canny,如果噪声导致伪边缘太多,再在外部加滤波。因为Canny内部本来就自带高斯,外部再加一层,边缘可能会移位,影响后续定位精度。
3.2 图像分割方法:阈值、区域与遥感中的集合运算
分割是图像处理里最难也最实用的一块。最基础的是阈值分割,把灰度大于阈值的置为255,小于的置为0。但固定阈值最怕光照变化,同一个阈值在上午能用,下午就废了。
Otsu大津法就是为了解决这个问题的经典方法。它的思想是遍历所有灰度级别,找到一个阈值,使得分割后前景和背景的类间方差最大。这个阈值不需要人手动设置,代码里传入一个标志就行:
_, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)如果光照在图像上不均匀,比如中间亮四周暗,全局阈值再智能也没戏。这时候要用自适应阈值,它会在每个像素周围取一个局部窗口,用窗口内的均值或高斯加权和减去一个常数C作为该点的阈值。OpenCV里写法是:
adapt_bin = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)窗口大小和常数C很看经验。窗口通常取奇数,对文字类小目标取11到15比较合适;C值越大,分割出的白色区域越小。真实项目里我经常把Otsu和自适应阈值都跑一遍,再根据业务场景选一个。
顺带说一个和遥感图像处理强相关的知识点:集合运算。两幅经过配准的遥感图像之间做交、并、差、异或,可以快速提取变化区域。差运算直接相减,就能找到地物发生变化的位置;异或运算则能找出“要么变了、要么消失”的像素集合,在土地变化监测场景里很实用。这和普通的代数运算是两回事,代数运算是对每个像素做数值计算,集合运算是对二值图像做逻辑操作。
3.3 关键点特征:SIFT、SURF、ORB都是干什么的
当我们需要匹配两幅图,比如图像拼接、物体识别,单纯比较整幅图像灰度是行不通的。关键点特征就是为了解决“找到两幅图中同一个位置”的问题。
SIFT(尺度不变特征变换)是这一领域的里程碑,它通过构建高斯金字塔找尺度空间极值点,再为每个关键点计算128维描述子,对旋转、尺度、光照变化都有很强的鲁棒性。但它有两个问题:计算量偏大,早年还有专利限制,在商业项目里用起来不痛快。
SURF是SIFT的加速版,用盒式滤波和Hessian矩阵近似,速度提升明显,但精度略逊。ORB则是目前工程里更常用的选择,它结合了FAST角点检测和BRIEF描述子,速度非常快,而且开源无专利限制,在嵌入式、移动端场景里是首选。
特征匹配的时候,暴力匹配(BFMatcher)适合特征点较少的场景,FLANN适合大规模匹配。匹配完千万别直接信结果,一定要用RANSAC(随机抽样一致)剔除误匹配,再计算单应性矩阵。不剔除误匹配直接做图像拼接,你会得到一张完全碎掉的图。
我做过一个证件扫描App,就是靠ORB特征匹配加RANSAC做文档边缘提取,最后做透视变换矫正,在手机上能跑到实时,效果很稳。
4. 深度学习时代的图像处理方法:为什么CNN能统治视觉
4.1 为什么图像处理用CNN而不是前馈神经网络
这个疑问背后的原理,建议理解到位。前馈神经网络(FNN)也叫全连接网络,它把图像展平成一长串像素值作为输入。一张224x224的彩色图像,展平后就有15万个输入节点,第一个隐藏层哪怕只有512个神经元,权值数量就是7500万级别。这还只是一个层,参数爆炸到没法训练,而且模型对像素之间的“空间关系”完全没有概念。
CNN则完全不同。它的核心思路是局部感受野和权值共享。卷积核只对输入的一个局部区域做加权求和,这就是局部感受野,对应图像里“相邻像素构成有意义结构”的先验;同一个卷积核在整个图像上滑动,同一组权重被反复使用,这就是权值共享,参数量骤降。
用生活类比来说,全连接网络相当于每个员工都要向全公司的每个人汇报一次工作情况,信息冗余且量大;CNN则让每个小组只向自己的上级汇报,而且全公司都沿用同一套汇报模板。效率天差地别。
另外,CNN的卷积操作天然具有平移等变性:物体在图像里挪了几个像素,特征图里的响应也会相应挪几个像素,这让模型对位置不那么敏感。这一点对于目标检测和物体识别至关重要。
4.2 CNN核心组件:卷积、池化、激活函数
卷积层的输出尺寸计算公式是每个做视觉的都应该烂熟于心的:
out = floor((W - K + 2P) / S) + 1其中W是输入尺寸,K是卷积核尺寸,P是padding填充数,S是步长。比如输入224x224,卷积核3x3,padding=1,stride=1,输出尺寸还是224x224,这就是常见的“same”填充方式;如果stride=2,输出尺寸就减半,常用来下采样。
池化层的作用是降维和扩大感受野。最大池化取窗口最大值,对边缘和纹理响应更敏感,在实践中更常用;平均池化取均值,能保留更多背景信息但容易把强响应平滑掉。做分类任务时,最后一层常常用全局平均池化,直接对最后一张特征图取平均,效果比拉平再接全连接层更稳,也几乎不过拟合。
激活函数在经典网络里一秒想到的就是ReLU,公式是max(0, x)。它计算简单,还能缓解梯度消失。但ReLU在负区间恒等于0会让部分神经元“死掉”,所以后来的LeakyReLU、GELU才逐渐流行。我现在用到的Transformer类模型喜欢GELU,但传统CNN网络里ReLU依然是性价比最高的选择。
这里的重点不是记住每个层叫什么,而是要理解:CNN是靠堆叠卷积、池化、激活、归一化,逐步从像素提取出边缘、纹理、部件、物体这样层级化的特征。这也是它比手工特征强大的根本原因。
4.3 经典网络结构与任务选型
视觉任务大体可以分为三类:图像分类、目标检测、语义分割。每个任务都有相对标准的网络演进路径。
分类任务绕不开ResNet。ResNet引入残差连接,把输入直接跨层加到输出上,解决了深层网络“退化”的问题——网络加深后训练误差反而上升。它的基本思想是让浅层网络能通过网络自身学习到恒等映射,这样深层网络至少不比浅层差。现在做分类,ResNet50、ResNet101依然是预训练模型的主流骨架。
目标检测有两派。两阶段代表作Faster R-CNN,先提候选区域再精分类,精度高但速度慢,适合对实时性要求不高的场景。单阶段代表作YOLO和SSD,直接回归边界框和类别,速度极快。目前YOLO系列生态已经非常完善,不管做交通检测、工业缺陷还是安防监控,我都会先试YOLO,因为它兼顾精度和速度,且部署工具链成熟。
语义分割方面,FCN是开山之作,用卷积层替代全连接层实现像素级分类;UNet则在编码-解码结构上加了跳跃连接,把浅层空间信息和深层语义信息融合,在小样本医学图像分割和遥感分割任务上表现极好,是我在项目中最常用的分割模型。
做实际项目时,我的建议是:第一优先级用预训练权重做迁移学习。比如做表面缺陷检测,不用从零训练,加载ImageNet预训练的ResNet或YOLO权重,再在自己的数据上微调,训练速度快且不容易过拟合。第二优先级是数据增强。随机翻转、随机裁剪、颜色抖动这些手段,能在样本不足时让模型泛化能力大幅提升。别在数据集只有几百张的时候就急着上复杂网络结构,先把基础的流程跑通,效果往往比你在网上各种抄模块改结构要好。
5. 工具选型与工程落地:OpenCV、MATLAB、ISP与FPGA
5.1 OpenCV:日常图像处理项目的默认起点
OpenCV是目前最主流的开源计算机视觉库,C++、Python、Java等接口都有。它的模块划分很清晰:core管数据结构,imgproc管图像处理算法,highgui和imgcodecs管显示和读写,features2d管特征提取与匹配,objdetect管目标检测,dnn管深度学习推理。
日常项目里,我基本都是先用Python快速验证算法流程,再根据性能要求用C++或Cuda重写关键模块。OpenCV最大的价值不只是封装了算法,而是它把很多底层的坑都填了。比如图像读进来是NumPy数组,形状是(height, width, channels),通道顺序是BGR而不是RGB——这一点新手基本都会踩一次。你用matplotlib显示OpenCV读出来的图,发现红色和蓝色反了,就是这个原因。
另外OpenCV的imread如果路径不对,并不会抛出异常,而是返回None。如果你直接拿None去做cvtColor,保底是崩溃,最怕的是在某个角落莫名其妙算出一堆错误结果。我习惯每读一张图都检查一下:
img = cv2.imread(path) if img is None: raise FileNotFoundError(f"Failed to load image: {path}")这种检查写久了会变成肌肉记忆,但能省掉很多排查时间。
OpenCV的dnn模块值得单独说。它可以直接加载训练好的Caffe、TensorFlow、ONNX模型,不需要依赖PyTorch或TensorFlow就能跑推理。在做嵌入式部署或快速验证模型效果时,这个模块非常好用。几年前我在老款工控机上跑YOLOv3,就是靠OpenCV dnn把FPS提升到了可用的程度。
5.2 MATLAB:算法验证与课程项目的好帮手
MATLAB的Image Processing Toolbox语法极其接近数学表达,写起算法来比C++顺手很多。很多本科生、研究生做图像处理大作业首选MATLAB,因为不需要管理内存,矩阵运算天然高效,还带一个非常直观的Image Viewer和Image Segmenter工具箱。
从工程角度看,MATLAB的坑在于部署和License。你写好的.m脚本想要集成到生产环境里,要么用MATLAB Compiler打包,要么改用Coder生成C++代码,过程并不轻松。所以在工业界,MATLAB更多用于科研验证、算法仿真、快速出实验结果,真正的产线落地还是OpenCV或其他语言方案。
我遇到过很多做“MATLAB图像处理大作业”的同学,最大的问题不是写不出代码,而是把图像数据格式搞混了。MATLAB里图像矩阵默认是double,像素范围0到1;读入uint8时也会给你转成double数组。如果你直接当0到255去送进某个函数,就会出现“图片全黑”这种让人怀疑人生的问题。记住一条:在MATLAB里处理图像,先看class函数返回的图像类型,再决定怎么归一化。
5.3 ISP与FPGA:硬件视角下的图像处理
ISP(图像信号处理器)是摄像头成像链路上的专用硬件单元。从Sensor读出的RAW图,到最终你看到的YUV或RGB图,中间要经过一系列处理:黑电平校正、镜头阴影校正、坏点校正、去马赛克、白平衡、颜色校正、Gamma校正、降噪、边缘增强等。这些步骤本质上全是图像处理算法,只是做在硬件里,实时跑在每帧画面上。
做手机拍照、安防相机、车载摄像头的人,很多工作就是调ISP参数。你可以把ISP理解成“相机的美颜流水线”:Sensor给了原始素材,ISP负责把素材调成观感最好的成品。如果想做底层画质优化或者自动驾驶视觉感知,ISP的基本流程一定要懂,因为很多视觉算法输入的就是ISP输出后的图,ISP参数调得不好,后续算法的输入质量就受影响。
FPGA则是另一个硬件化方向,适合对极致实时性和低延迟有刚需的场景,比如高速工业线阵相机检测、无人车视觉前处理。FPGA的优势是并行计算,比如一个3x3中值滤波,在CPU上要逐个像素循环,在FPGA上可以用Line Buffer实现每行数据流水式处理,几乎一个时钟周期出一个结果。
我在FPGA项目里做图像处理时的经验:算法设计阶段就要考虑定点化问题。因为在FPGA上做浮点运算开销很大,一般先把系数放大成整数,运算完再移位移回来。比如高斯核权重0.1、0.2、0.4,放大10倍变成1、2、4,最后结果除以10,精度损失很小,速度却快得多。另外,DDR带宽是最大瓶颈,坚持“能不做全局图像操作就不做”的原则,尽量让数据流起来,避免反复搬运大图。
6. 常见问题与排查技巧实录
6.1 图像偏暗、偏色、对比度差怎么办
这通常是ISP阶段或者预处理阶段的问题。先看直方图,如果灰度值整体压缩在一个小范围,优先做直方图均衡化或CLAHE。偏色问题优先检查白平衡,常用方法是灰度世界假设:假设整幅图像的平均颜色接近灰色,然后把RGB三个通道的均值调整到相等。这个方法简单粗暴,在很多普通偏色场景下够用。
如果图像在特定区域有明显阴影,可以试试用背景减除或形态学顶帽操作。顶帽运算是原图减开运算结果,能提取出暗背景下的亮目标,对指纹识别、血管提取一类的场景特别有效。
6.2 阈值分割结果总是不稳定
阈值不稳定的根源通常是光照变化。固定阈值只能用在受控光照环境中,比如封闭的检测工位。其他场景,请优先选择Otsu或者自适应阈值。如果分割出来的区域有大量小孔和毛刺,那就按顺序做一次闭运算再开运算。如果区域边缘不光滑,再用一次形态学腐蚀或膨胀调整尺寸。
这里有个我反复踩过的坑:Otsu对直方图呈“双峰”分布的图像效果最好,但如果前景目标占图像面积很小,比如一张图里只有一个极小缺陷,Otsu的阈值往往偏向背景,导致小目标直接消失。遇到这种情况,我会改用局部阈值或先通过图像差分放大缺陷区域,再做阈值分割。
6.3 深度学习训练不收敛或者严重过拟合
先观察训练集和验证集的loss曲线。如果两者都降不下去,说明模型容量不足、学习率设置有问题,或者数据预处理有问题。学习率过大,loss会发散射乱;学习率过小,loss下降极慢。经验上先设1e-3或1e-4,训练过程中用余弦退火或ReduceLROnPlateau动态调整。
如果训练loss降得很低,验证loss却飙升,就是过拟合。解决思路按优先级排列:加数据增强、加Dropout或权重衰减、减小模型复杂度、用预训练模型。很多人一上来就收集更多数据,但其实在小数据集上,强有力的数据增强往往比多收集一倍样本更有效。
另外一个容易被忽略的坑:类别不平衡。如果缺陷样本占5%,正常样本占95%,直接训练模型会倾向于把一切都判为正常。解决方法是加权损失函数,或者用Focal Loss;再不行就做采样,把正样本复制几份,至少让训练时正负样本比例不要那么悬殊。
6.4 算法在低算力设备上跑不动
这里没有银弹,只有组合优化。第一步是缩小输入分辨率,很多时候1080p降到720p,精度损失不大,速度翻倍。第二步是裁ROI,只对感兴趣的区域做复杂处理,比如智能车只处理远端视野,不做全图扫描。第三步是数据降精度,OpenCV的normalize和convertTo可以把浮点图转成uint8,计算量立刻少一大截。第四步是模型层面,用YOLO-tiny、MobileNet这类轻量化模型,或者在训练后做INT8量化。
我做嵌入式视觉时的经验是:先画一遍完整的数据流图,看哪些中间结果可以省掉,哪些运算可以合并,最后再考虑硬件加速。很多性能问题不是算法本身慢,而是数据反复转格式、反复拷贝造成的,大刀阔斧砍掉这些浪费,性能往往能提升一到两倍。
6.5 常见问题速查表
| 问题现象 | 可能原因 | 优先处理方式 |
|---|---|---|
| 图像泛白 | Gamma过高、白平衡偏亮 | 调整Gamma、降低曝光 |
| 图像发暗 | 曝光不足、伽马偏低 | 直方图均衡、提亮Gamma |
| 边缘断裂 | Canny低阈值过高 | 降低低阈值到30-40 |
| 边缘噪声过多 | 图像噪声大或高阈值偏低 | 先高斯滤波,提高高阈值 |
| 分割区域有小孔 | 阈值过分割 | 执行闭运算 |
| 目标被分割成两半 | 阈值欠分割或光照不均 | 开运算、采用自适应阈值 |
| 模型严重过拟合 | 数据量少或模型过大 | 数据增强、加正则项 |
| 模型收敛极慢 | 学习率过低 | 调高学习率或换优化器 |
| 嵌入式推理慢 | 输入过大、未量化 | 缩分辨率、INT8量化 |
最后分享一点个人经验
做了这么多年图像处理,我最大的体会是:千万不要把方法和工具当成目的。很多人学了OpenCV里几十种滤波,却不知道该在什么场景下用哪个;也有人一上来就上深度学习,连最基本的白平衡和对比度问题都修不好。正确的路径,是先用手头最简单的工具把整个流程跑通,再在问题卡壳的地方用更复杂的方法去补。
我刚入行那段时间,最喜欢做的一件事就是把同样的图像用十几种方法轮流处理一遍,看输出有什么差别。现在回想起来,那段“瞎折腾”反而是最宝贵的经验积累,因为只有亲手看到同一张图在不同处理流程下的变化,才能真正理解算法的脾气。图像处理没有万能配方,每一个参数、每一个操作都需要针对实际数据去调。这套方法体系,你用久了,也会形成自己的感觉。