重生之我成为模型 番外 · 饲养员厨房下——大厨古法餐

85 阅读11分钟

系列: 上篇 成文/番外-饲养员厨房-上|标准简餐


上篇只是介绍了我做简餐的水平:把题面备好,按批端给深度考生,最终让模型给我干活。

但真正的艺术家往往坚持手搓。就算我自己单打独斗,也是很有水平的。
本篇就是介绍一下我的看家本领——滤波、边缘、轮廓、阈值这些工艺手法。有时直接交卷,有时帮人写出 mask / 轮廓;不是深度学习专用配菜。

本篇可以配合 LearnOpenCV · Getting Started with OpenCV 一起食用——那边按读图、几何、滤波、阈值、边缘、轮廓一路拆;这边讲这些手法在工程师灶台上怎么用、和深度考生怎么分家。


0. 澄清误会:三条路,别混

路在干啥例子
A · 备餐给深度模型把图变成考生能吃的张量(几何+数值)resize/crop、ToTensor、Normalize —— 上篇
B · 古典灶台直接出菜不用深度模型,传统法直接交卷海天:阈值/形态学 → mask 就是答案
C · 帮人出/核答案辅助标注、伪标签、质检可视化边缘帮忙描轮廓;阈值出粗糙 mask 再人工改

所以:

  • 不全是「训练数据的一部分」——很多时候古典法自己就是考生。
  • 可以是「制作答案」——B、C 常这样;A 主要是做题面。
  • 喂 AlexNet 认 ImageNet 时:主路径是 A;滤波边缘不是必经主菜。

核心还是那句:工程师选择何时手工、何时让模型打工。


1. 滤波 / 模糊:先清理案板

古法大餐第一步,往往不是直接切菜——先清理案板:抖掉不该在台上的东西,只留下这次要用的食材和工具。
滤波 / 模糊干的就是这事:去噪、抹掉多余细节,让后面的边缘、阈值少踩坑。它常常是流水线开头,不是整道菜本身。

用一个小矩阵(卷积核)在图上滑动,每个像素用邻域算出新值。
和深度考生体内那种「可学习的核」像,但这边核是人定死的——不靠 loss 反传改。

常见三招(邻域多半是 3×3 / 5×5 这类小窗):

邻域怎么算新像素kernel 长什么样去什么噪特点
均值算术平均全 1,再归一化一般随机噪快,边缘糊
高斯加权平均(中心权重大)中间大、边上小(钟形)高斯噪Canny 前常用
中值排序取中间值不用这种卷积核写法椒盐噪孤立黑白点压得住

均值、高斯:小窗滑过去,用核里的权重加权求和 → 典型卷积核。
中值:还是在 3×3 / 5×5 里动手,但把邻域像素排个序,取中间那个当新像素——不是「乘核再加总」那一套,所以一般不说它是卷积核。

清完案板,不等于大餐出锅——更不等于「深度预处理完成」。后面边缘、轮廓、阈值,才是古法流水线往下走。


2. 边缘:进入雕刻状态

案板清完,下一刀不是染色——是雕刻。

边缘这一步,开头先转灰度。不是不关心颜色,是这时候脑子里要的不是「多鲜艳」,而是最终会留下的形状:墙和门的交界、海和天的接缝、物件轮廓该落在哪。
彩色三通道吵来吵去,不好统一问「这里亮暗变没变」;灰度每个像素一个亮度,只问坡有多陡。

第一个概念:梯度

把一行灰度像素想成一串数字:

…  100  102  105  200  198  196  …
              ↑这里从 ~105 跳到 200

梯度 ≈ 亮度变化有多猛(坡有多陡)。
平坦≈0,不像边;猛跳→有可能是边。还不是「一定是边」——后面还要筛、还要连。

2D 图上要看两个方向:

在比什么
Gx左右亮暗差 → 对竖边敏感
Gy上下亮暗差 → 对横边敏感

合起来是向量 (Gx, Gy):往哪变最猛、有多猛。

Sobel:先横着刨一刀,再竖着刨一刀

Sobel 就是用固定核把 Gx、Gy 算出来。记住两样:

  1. xy 方向上的梯度(分开看 / 分开 imshow 都很有戏)
  2. 梯度幅值 √(Gx² + Gy²) → 不管横竖,只要亮暗差大就亮
gx = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=3)
gy = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3)
mag = cv2.magnitude(gx, gy)   # 幅值;这才是「边有多强」那张热力图

坑一句:OpenCV 里若 dx=1, dy=1 同时开,那是混合二阶导数,不是上面这个幅值。要「边有多强」,用幅值,别混。

Sobel 像粗坯:边在哪大概看见了,但常常又粗又糊——真边在图上往往占好几像素宽,过渡带里幅值都偏高。要更干净的线,轮到 Canny。

Canny:四步精修(雕刻真正开始讲究)

Canny 比 Sobel 麻烦,但可以记成四步流水线:

① 降噪(高斯) → ② 强度梯度 → ③ 非极大抑制 → ④ 滞后阈值

① 降噪
用的就是上一节案板上的高斯模糊。噪点是小尖峰,不糊一下,梯度图会到处冒假边。

② 强度梯度
先把三个名字分清——后面 NMS 全靠它们:

名字是什么直觉
梯度(向量)(Gx, Gy)往哪变最猛 + 有多猛
梯度幅值√(Gx² + Gy²)边有多强(和 Sobel 合成图一路货)
梯度方向atan2(Gy, Gx)最陡的上坡方向

幅值大 → 像边;方向 → 坡往哪升,第③步要用。
Canny ② 的幅值公式和 Sobel 一样;它多算方向,还往下做 ③④。

③ 非极大抑制(NMS)——只留脊线,不留山坡

问题:Sobel 热力图边又粗又糊。
办法:对每个像素,用自己的 Gx、Gy 算出方向,把角度归到最近的 0° / 45° / 90° / 135°,只跟「梯度方向上那一对邻居」比幅值——

  • 当前 ≥ 两个邻居 → 保留(局部极大,坡顶)
  • 否则 → 幅值置 0

人话:同一条边上,只留最陡那一线,胖边削成细线。

④ 滞后阈值(Hysteresis)——人类可拧的两颗旋钮

前面多半是算法算死的;这里你加两个阈值,决定「多严才算边」:

幅值名称怎么处理
≥ 高阈值 T_high强边肯定保留
T_low ~ T_high弱边只有挨着强边才保留(连边)
< 低阈值 T_low太弱直接丢掉

强边是主刀痕;弱边是不是跟着留下来,看它有没有搭上主刀痕——孤零零的毛刺,滚蛋。


雕完一圈,手里常常是一张边线图——中间结果,还不叫交卷。
后面轮廓把它收成封闭形状;分割、可视化、帮人描答案,都可能从这儿接着走。深度考生认 ImageNet?主路径照样可以不吃这一步。


3. 轮廓与形状:择菜,把主角抠出来

边散着,还不叫物件。轮廓这一步,其实像择菜:把可食用的主角抠出来,杂叶背景先搁一边。

经常听「背景」「前景」,我也是一下没反应过来。嘿嘿。
人话:前景 = 这一步你关心、要留下的;背景 = 不要的。谁算前景不是图自带的,是任务定的——红球、蓝天、手机外框,都可以是前景。

这回多半还是先变灰度,依旧先不看颜色。这边可以收一句:

找边缘、追轮廓时,常常用灰度更好分割——问的是亮暗结构,不是「多鲜艳」。

先有二值图,才有轮廓可追

findContours 吃的是二值图(白/黑)。二值从哪来,轮廓意味就不一样:

来源二值图长什么样轮廓意味
threshold / Otsu物体整块白、背景黑物体的 外边界(区域)
Canny边线是白、其余黑边缘线(通常约 1 像素宽)

Canny 那路的高低阈值,上一节滞后阈值讲过——人拧两颗旋钮。
threshold 那路的砍线,下一节形态学那边还会展开。
两条路不是「必须先阈再 Canny 再轮廓」,常是二选一或组合。

二值图质量很重要:糊成一片或碎成椒盐,后面 findContours / drawContours 都会跟着倒霉。

找轮廓、画轮廓

OpenCV 里主菜就两口:findContours 找,drawContours 画。

压缩方式差在「点留多少」:

模式人话
CHAIN_APPROX_NONE边界上点几乎都留着,密
CHAIN_APPROX_SIMPLE直线段压成端点,点少一点,常用够了

还有一层容易忘:轮廓有层级。手机外框是一圈;摄像头开孔又是里面一圈——外轮廓套内轮廓,不是只有一条线。

轮廓收成封闭形状之后,可以量面积、周长、外接矩形,甚至粗分「这坨大概像啥」。对我来说常干两件事:

  • B 路:形状本身就是要交的答案(或答案的一部分)
  • C 路:帮标注员描一圈,人工再改

4. 阈值与形态学:少许调味,再下锅定型

阈值:一笔带过

前面边缘里的高低阈值、轮廓前的二值砍线,其实都碰过「阈值」这味调料了。这边不展开成专章——只要记住:它是常用的人工干预手法,按真实数据可以不断拧。

像老师傅嘴里的「少许」:菜谱写得含糊,干多了你自己会总结——这道菜大概几勺。
砍高了,主角缺一块;砍低了,背景糊进盘里。产出常常是 mask:哪里是目标,哪里不是。

形态学:油炸变大,炒制缩小

二值 mask 往往还不能直接上桌——毛刺、小洞、断边。形态学就是下锅定型:不断控制形状,最后才是要的样子。

这里不用小刀精雕(那是边缘的活)。膨胀、腐蚀、开、闭,更像整块食材在锅里胖瘦:

手法锅感图上大概在干啥
膨胀 dilation油炸——外边焦、体积胀大白区往外扩,小洞容易补上,断边容易连上
腐蚀 erosion炒制收汁——缩水变紧白区往里收,小毛刺容易烧掉
开运算 open先缩再胀(先腐蚀后膨胀)去小白点噪,外形大致还在
闭运算 close先胀再缩(先膨胀后腐蚀)补小黑洞,外形大致还在

开闭是组合拳,不是又两把小刀。分割任务里,阈值 + 形态学出场率极高:mask 从「勉强能看」变成「能交差」。
有时后面还接染色、量尺寸、数个数——但核心答案往往已经是那张 mask。


5. 海天小高潮:古典法直接出 mask = 答案

说个我自己灶台上干过的活——视频流里分天空、找海天线。

大致流水线:

视频帧
  → HSV 采点(再补蓝天点,扩大包络)
  → inRange 得 sky mask
  → 形态学修边
  → 按算法向上扫 → 海天线
  → 后处理:仅在 sky mask 内染成好天气的蓝

为啥用 HSV 不硬刚 RGB?蓝天在 RGB 里曝光一变就漂;HSV 里 H 相对稳住「是什么蓝」,更好画包围盒。
采点 + 补点 = 把「天」的颜色范围圈住;inRange 吐出的 mask 就是答案的骨架——不是拿去喂 AlexNet 当口粮。

两阶段别混:前面圈天空;最后染蓝是在已知 mask 里改颜色。

这就是 B 路:深度考生根本没上场。我自己是考生,古典灶台直接交卷。

完整走读见掘金前文:标题待填。


6. 和深度考生的关系

别误会:写完古法大餐,不是说深度考生从此失业。

灶台上其实常搭伙。我先用阈值搓一版粗糙 mask,当伪标签丢给分割模型练手——他负责往后抬精度,我负责先有个能吃的坯。同一道题,我古典交一版、他深度交一版,验收时两盘并排端,谁糊谁清楚。边线、阈值图也可以当质检灯:模型懵的时候,人眼先看见「他卡在哪道工序」。

但有一件事必须说死——

喂他家那位认一千类、走 ImageNet 那条主路时,滤波、边缘、轮廓不是必经配菜。上篇那套标准简餐:几何切配 + ToTensor + Normalize,就够进门。你在 OpenCV 教程里学过的工艺,默认不要翻译成「深度学习预处理清单」;那是把大厨刀法,误认成简餐流水线上的必选步骤。

何时手搓、何时让模型打工——菜单权在饲养员,不在考生。


7. 收束

下篇厨房 = 对照班灶台。
有时我们自己就是考生。

三条路再念一遍:备题面 / 古典交卷 / 辅助出答案——勿混。
核心不是考生有多神,是工程师选择何时手工、何时让模型打工。

正文三部讲清「模型打工时发生了什么」。
厨房上下篇把镜头扳回我:我为什么养他、我自己还能怎么做。

厨房上下篇到这儿收工。下一篇番外随缘更新——也许是模型家族聚会,也许是别的灶台。

上篇:成文/番外-饲养员厨房-上|饲养员厨房(上):标准简餐