明白,你要的是手撕面试版:少用库、少模板、能在白板/纸上快速写出的那种。给你三段“面试好写”的版本(灰度、u8、边界用clamp复制)。你背住这三段就够了。
1) 二维卷积(通用 K×K,浮点核)
// 手撕版二维卷积(u8灰度,边界clamp)
// src/dst: 行优先数组,大小 h*w
inline int clampi(int v, int lo, int hi){ return v<lo?lo:(v>hi?hi:v); }
void conv2d(const unsigned char* src, int h, int w,
const float* k, int ksize, unsigned char* dst)
{
int r = ksize/2;
for (int y=0; y<h; ++y){
for (int x=0; x<w; ++x){
float acc = 0.f;
for (int dy=-r; dy<=r; ++dy){
int yy = clampi(y+dy, 0, h-1);
for (int dx=-r; dx<=r; ++dx){
int xx = clampi(x+dx, 0, w-1);
float kv = k[(dy+r)*ksize + (dx+r)];
acc += kv * src[yy*w + xx];
}
}
int v = (int)(acc + 0.5f);
if (v<0) v=0; if (v>255) v=255;
dst[y*w + x] = (unsigned char)v;
}
}
}
口述要点:双重像素循环 + 双重核循环;边界 clamp;最后饱和到
[0,255]。高斯卷积可用可分离优化(先横后竖)。
2) 均值滤波(3×3,整型好写好记)
// 手撕版 3x3 均值滤波(u8灰度,边界clamp)
inline int clampi(int v, int lo, int hi);
void mean3x3(const unsigned char* src, int h, int w, unsigned char* dst)
{
for (int y=0; y<h; ++y){
for (int x=0; x<w; ++x){
int sum = 0;
for (int dy=-1; dy<=1; ++dy){
int yy = clampi(y+dy, 0, h-1);
for (int dx=-1; dx<=1; ++dx){
int xx = clampi(x+dx, 0, w-1);
sum += src[yy*w + xx];
}
}
dst[y*w + x] = (unsigned char)((sum + 4) / 9); // 四舍五入
}
}
}
口述要点:9个像素求和/9;(sum+4)/9 做四舍五入;更快可用“积分图”O(1)求和。
3) 中值滤波(3×3,直方图法,面试最好写)
// 手撕版 3x3 中值滤波(u8灰度,直方图找第5个)
// 优点:不用排序API,纯 for 循环好写
inline int clampi(int v, int lo, int hi);
void median3x3(const unsigned char* src, int h, int w, unsigned char* dst)
{
int hist[256]; // 临时直方图
for (int y=0; y<h; ++y){
for (int x=0; x<w; ++x){
// 清零直方图
for (int i=0;i<256;++i) hist[i]=0;
// 收集 3x3
for (int dy=-1; dy<=1; ++dy){
int yy = clampi(y+dy, 0, h-1);
for (int dx=-1; dx<=1; ++dx){
int xx = clampi(x+dx, 0, w-1);
++hist[src[yy*w + xx]];
}
}
// 找第5个(0..8 的中位数索引 = 4)
int need = 4, cumsum = 0, med = 0;
for (int v=0; v<256; ++v){
cumsum += hist[v];
if (cumsum > need){ med = v; break; }
}
dst[y*w + x] = (unsigned char)med;
}
}
}
口述要点:3×3 共9个像素,用 256 桶计数,找到累计数 > 4 的强度即中值;抗椒盐,但比均值更慢。
彩色/ROI/可分离怎么说?
- 彩色图:对每个通道(B/G/R)各跑一次;或把指针按
chan偏移处理。 - ROI:把
(x0,y0,w,h)的区域当成内层循环范围;边界 clamp 在 ROI 内或全图内都能说通。 - 可分离核:高斯可分离为
1×K+K×1两次一维卷积,把 O(K²) 降到 O(2K)。
面试 20 秒口述模板
- “二维卷积:像素双循环 + 核双循环,边界 clamp,累加后饱和到 0..255;高斯我会用可分离加速。”
- “均值 3×3:9点求和/9,(sum+4)/9 四舍五入;大核我会用积分图 O(1)。”
- “中值 3×3:建 256 直方图找第5个最小的值,抗椒盐;更大窗口可用滑动直方图做加速。”
需要我再给你可分离高斯的手撕版(先横后竖 1D 卷积)或支持任意奇数核的中值(滑动直方图)吗?
浙公网安备 33010602011771号