项目:opencv01(C# / .NET 8 / OpenCvSharp4) 仓库:https://github.com/keterforcpp/OpenCVLearn.git 本文件是整个学习工程的"教学契约"——任何 AI 或教程提供者接手时,按本文件执行。
-
学过 C/C++、;C# 普通水平(语法方面不是特别熟悉,特别是新特性)
-
偏好:代码简洁不过度复杂、注释详尽(中文)、理论必须结合可运行的演示代码
-
学习方式:每课一个可运行的 Program.cs,新代码覆盖旧代码,靠 git 历史回溯
-
学习风格:会主动追问底层原理(如"卷积为什么代表模糊""为什么叫求导"),喜欢数字实例和对照实验,不接受含糊其辞
-
代码结构:
-
单文件
Program.cs,顶部用注释块写明"第 X 课:标题 + 理论核心" -
分节编号(---------- 1. xxx ----------),每节先注释后代码
-
文件末尾附"本课小结"注释(5 条左右要点)
-
读取图片后必须有
src.Empty()健壮性检查 -
逐像素循环必须缓存
Height/Width到局部变量(P/Invoke 性能坑) -
编译尽量 0 警告 0 错误(
dotnet build --nologo -v q验证)
-
-
教学方式:
-
理论 → 手写实现(简单的原理如果实现过于复杂就不需要)(理解原理)→ 内置 API(工程用法)→ 对照实验,四段式
-
关键概念用具体数字举例(如像素值序列演示差分),不用抽象描述
-
每课设计 1~2 个"参数实验"(如 Canny 高低阈值对比),让学习者亲手感受调参
-
常见坑要显式指出(byte 溢出、BGR 顺序、new Mat 不清零、At 的 T 必须匹配 MatType 等)
-
老知识在新课中回收利用(如 Sobel 出现在 Canny 课),建立知识网络
-
-
Git 规范:
-
每课完成即提交,提交信息格式:
第X课教学:课程标题 -
推送由学习者本人操作(AI 只提交本地)
-
教学图片不上传(.gitignore 已配置 *.jpg 等),只上传 .cs/.csproj/.sln/.gitignore
-
| 课 | 主题 | 核心内容 | 提交 |
|---|---|---|---|
| 1 | 图像的本质——像素、通道与灰度化 | Mat 与像素访问 At<T>、BGR 通道、灰度化公式 0.299R+0.587G+0.114B、手写灰度化 vs CvtColor、byte 溢出截断 |
529af8d |
| 2 | 滤波与卷积 | 卷积=滑窗加权求和、手写 3x3 均值滤波、Blur/GaussianBlur、锐化核(负权重)、椒盐噪声实验(均值 vs 中值)、Filter2D 自定义核 | ecef642 |
| 3 | 边缘检测——梯度、Sobel 与 Canny | 手写水平/竖直差分、Sobel(差分×平滑的可分离设计)、Laplacian(二阶导/过零点)、手写过零点检测(符号翻转+幅度门槛30)、Canny 四步流水线(高斯/Sobel/NMS/双阈值滞后) | 352007e |
| 4 | 二值化与形态学操作 | 固定阈值 vs Otsu 自动阈值、结构元素、手写腐蚀、Erode/Dilate、开闭运算(开=去白噪点,闭=填黑洞)、形态学梯度(Dilate-Erode) | f0ab883 |
| 5 | 轮廓提取与物体计数 | 完整流水线:灰度→Otsu→开闭清理→FindContoursAsArray→面积过滤→计数;DrawContours/BoundingRect/PutText 可视化;BinaryInv 反转(目标为暗色时) | 4fc38e3 |
| 6 | 直方图与均衡化 | 手写计票直方图 vs CalcHist(上界 256 开区间)、直方图诊断(双峰→Otsu 可切,单峰/宽峰→必失败,第八课伏笔)、手写 CDF 重映射 + LUT vs EqualizeHist、均衡化后直方图"拉开而非平坦"、CLAHE 分块均衡 + clipLimit 限高(2.0 vs 6.0 参数实验) | d7bc488 |
| 7 | HSV 颜色空间与颜色分割 | BGR vs HSV(H 色相/S 饱和度/V 明度)、光照打击 V 不打击 H 的数字实例、手写 BGR→HSV 公式 vs CvtColor 对照、H 的 0~179 刻度坑与红色跨界两段 InRange + BitwiseOr、Cv2.InRange 三通道区间掩膜(手写对照验证)、S/V 门槛滤灰滤暗、mask 直接接第五课流水线计数、H 容差 ±10 vs ±30 参数实验 | 3cb84df |
| 8 | 自适应阈值与光照不均对策 | 人造乘性渐变光照图、全局 Otsu 失败现场(一刀切两端各错一次)、手写自适应阈值(积分图 O(1) 矩形和 + 邻域均值−C)vs AdaptiveThreshold(MeanC) 内部区域验证、GaussianC、blockSize 11/51/101 参数实验(小=碎、大=退化全局)、平场校正(大核模糊估光照→相除还原反射率→Otsu 复活)、GetArray/SetArray 整块像素搬运 | 91ecde3 |
| 9 | 距离变换与分水岭(粘连分割) | 合成粘连双圆图、老流水线计数=1 与腐蚀无解验证(第四课伏笔)、手写暴力距离变换(小图)vs DistanceTransform(L2) 对照、距离图=山峰/鞍部直觉、种子提取(相对阈值 maxDist×0.5)、markers 协议(0未知/1背景/≥2种子)与 DrawContours 填编号、Watershed 原地改写与边界-1、种子阈值 0.3/0.5/0.7 参数实验(种子质量=成败命门) | c942663 |
| 10 | 几何变换(缩放/旋转/仿射) | 反向映射思想(新图每格反问取色处→无洞无重叠)、仿射矩阵 2x3 统一平移/缩放/旋转与 WarpAffine、手写最近邻放大 vs Resize(Nearest) 验证、GetRotationMatrix2D、旋转扩画布(外接矩形+中心平移修正)、插值对比(最近邻锯齿 vs 双线性平滑)、二值图/标签图必须 Nearest(Linear 插出中间灰度污染 mask) | 0968357 |
| 11 | 霍夫变换(找直线与圆) | 参数空间投票思想(点共线→(θ,ρ)曲线共点→峰值=直线)、标准 HoughLines(无限长直线+垂足延伸画线)vs 概率 HoughLinesP(子集投票快+线段端点+minLineLength/maxLineGap)、手写"共线点ρ离散度扫描"验证投票心脏、HoughCircles(梯度定圆心再定半径的两步降维、minDist/param2 旋钮)、threshold 纯度-完整度权衡(同 Canny 双阈值族) | f98d1bf |
| 12 | 模板匹配基础 | 滑窗相似度=卷积近亲、结果图(相似度地图,峰值=模板位置)、手写 SQDIFF 暴力滑窗(缩小图)vs MatchTemplate 位置对照、三族方法对比(SqDiff 谷底/CCorr 怕亮/CCoeff 去均值最稳)、_NORMED 归一化跨图可比、CCoeffNormed 得分带(≥0.95 命中,第十四课 OK/NG 伏笔)、SubMat 视图须 Clone、MinMaxIdx 预分配数组坑 | 135e34b |
| 13 | 多目标定位与 NMS | 硬币图实战(yb.jpg+ybmb.png)、多尺度匹配(模板尺度不符时 0.5~1.5 逐档试)、贪心峰值提取(循环取最大→阈值判→邻域抹零)、手写纯数组 MinMaxIdx、IoU 交并比(交集/并集,目标检测通用货币)、标准 NMS 两段式(候选全收→按分降序→IoU>0.3 抑制)、MinMaxIdx 下标 [y,x] 与 Point(x,y) 相反的真 bug 修复(红绿双框自查定位)、阈值 0.5/0.65/0.8 纯度-完整度实验 | 7b409d6 |
| 14 | 模板匹配的边界与实战 | 得分=相关系数=去均值后夹角 cos 模型(线性调光 aI+b 免疫、反相=−1 负相关的数字验证)、半边阴影大跌(空间非线性,全局/局部分条乘法对照)、旋转双重伤害(画布黑角假伤+像素排布真伤)、圆形掩膜测纯旋转损伤(新版 OpenCV 才支持 CCoeffNormed+mask)、多角度模板库找回(来料歪 30° 得分 0.228→0.931)、首件良品裁标准模板、OK/NG 质检流水线(良品 1.0/划痕 0.868/反相 −0.22)、GATE 门槛=漏检-误杀旋钮(0.80 漏放/0.90 正确/0.97 严) | 7e285bd |
| 15 | 相机标定——教相机认识毫米(路线 D 开篇) | 针孔成像管线(世界点→R,t→÷Z→畸变→×K→像素,上一课 Proj 的逆运算)、fx=近大远小斜率/k1=边缘拉回量的数字实例、FindChessboardCorners+CornerSubPix 亚像素精化(平均修正 0.49px)、张正友标定法(平面棋盘 Z=0)、CalibrateCamera 盲猜参数、开卷对答案(fx 标出 799.74 vs 真值 800,误差 0.03%)、FixK3 的必要性(k3 与 k1/k2 强相关互相补偿漂移:不加 k1 标到 −0.21,加了回 −0.16)、重投影误差 RMS=官方考分(0.43px,54点×15图互相投票)、Undistort 畸变矫正(只去镜头畸变不改视角)+Absdiff 差值图=畸变场(中心暗边缘亮)、照片数量参数实验(N=1 正面照 fx 漂 5038/N=8 漂 5/N=15 归位,约束数量=钉死程度) | da1340d |
-
知识点:棋盘格标定、畸变矫正(去鱼眼)、像素→毫米换算、亚像素角点
-
素材模式:模拟相机"开卷考试"——
bin/Debug/net8.0/routeD_img/由已知参数的虚拟相机生成(15 张棋盘标定照 + object.png 测量工件照 + ground_truth.txt 真值:fx=800 cx=320 cy=240 k1=-0.15 k2=0.05,Z=400 测量平面,工件真值见第五节延伸讨论),标定/测量结果可与真值对比验证;生成脚本为一次性临时脚本未提交,素材丢失可按"第 15 课生成参数"重写(参数全部记录于 ground_truth.txt) -
已完成:第 15 课(针孔模型、CalibrateCamera、FixK3、重投影误差、Undistort)
-
待续:像素→毫米测量(object.png 的板长/孔径/孔距 vs 真值)、完整质检流水线(矫正→测量→判 OK/NG)
-
定位:真实测量(毫米而非像素);搭"拍照→矫正→测量→判 OK/NG"完整质检流水线;与工业相机 FFC 话题衔接
-
回收:第十课几何变换(畸变矫正=逐像素重映射)、第十一课霍夫(找棋盘格角点)
-
知识点:Harris/FAST 角点、ORB 描述子、BF/FLANN 匹配、单应矩阵、全景拼接
-
定位:传统视觉经典;概念(局部特征/描述子/RANSAC)是现代视觉通用语汇;但金属件纹理贫乏是其死穴,工业实操面窄,价值偏思想开拓
-
回收:第三课梯度(角点=梯度方向剧变)、第十课几何变换(单应=透视矩阵实战)
-
知识点:
VideoCapture逐帧处理、帧差法运动检测、背景建模 MOG2、KCF 目标跟踪 -
定位:前十一课算法在"每 33ms 一帧"约束下重演;与学习者实时音频采集背景思路相通(实时流处理)
-
知识点:棋盘格标定、畸变矫正(去鱼眼)、像素→毫米换算、亚像素角点
-
定位:真实测量(毫米而非像素);搭"拍照→矫正→测量→判 OK/NG"完整质检流水线;与工业相机 FFC 话题衔接
-
回收:第十课几何变换(畸变矫正=逐像素重映射)、第十一课霍夫(找棋盘格角点)
-
知识点:CNN 与第三课卷积的血脉联系、OpenCV DNN 模块加载 ONNX、跑 YOLO 目标检测推理
-
定位:手动调参 vs 学出来的核;只做推理门槛可控,深入需 Python 环境
-
回收:第三课伏笔(卷积核)、第五课 NMS(第十二课先修)
-
卷积是万能框架:模糊(加权求和)→ 锐化 → Sobel(差分×平滑)→ 形态学(取最值)→ CNN(机器学核)——每引入新算子都指出它在这个框架里的位置
-
宽类型计算、窄类型显示:8U 输入 → 16S/32F 中间运算 → ConvertScaleAbs 回 8U 显示,Sobel/Laplacian 均体现
-
线与面的双路线:边缘检测(第三课,产出线)vs 二值化+轮廓(第四五课,先有面再得线),在 FindContours 处会师——轮廓天然闭合,正是 Canny 追求的性质
-
相对阈值优于绝对阈值:面积过滤用"最大轮廓×5%"、Canny 双阈值比例 1:2~1:3
-
OpenCvSharp 特有的坑:P/Invoke 属性缓存、Mat 不清零(用 new Scalar(0) 打底)、At 类型必须匹配、saturate_cast 饱和转换(库内自动防溢出,手写循环需自理)
-
CNN 的卷积与传统卷积同源(第三课延伸讨论)→ 第十二课如走深度学习方向需回收
-
拉普拉斯过零点检测无官方 API,手写属正统做法(第三课)→ 第九课分水岭同为"手拼流水线"风格
-
全局二值化三大死穴:光照不均、粘连、阈值敏感(第五课实战发现)→ 第八、九课正面解决
-
TopHat/BlackHat 相减留差思想与 Gradient 同构(第四课延伸)→ 第九课距离变换峰值检测的伏笔
-
线性调光免疫/阴影大跌(第十四课 cos 模型实验)→ 路线 D 打光与相机 FFC 话题的衔接点
-
模拟相机"开卷考试"模式(第十五课):素材由已知参数的虚拟相机生成,真值藏于 ground_truth.txt——标定/测量的精度可与真值对比验证,真实拍摄做不到;后续测量课回收 object.png 的工件真值(板长 100mm/孔径 ⌀10/孔距 60/圆片 ⌀50)