我在 BGR 图像格式上实现了 3x3 模糊滤镜。
重要提示:
- 在对 BRG(或 RGB)格式的图像进行过滤时,必须单独过滤每个颜色通道。
- 在执行过滤器(使用卷积)时,重要的是不使用“就地”计算 - 避免源被目标元素覆盖。
- 乘以 (1/9) 比除以 9 更有效。
- 在整数转换前添加 0.5 可用于舍入正值。
- 通过扩展、缩放和移位执行 (1/9) 缩放的定点实现。示例:avg = (sum*scale + rounding) >> 15; [当比例 = (1/9)*2^15]。
我假设内存中的像素顺序是 b,g,r,b,g,r...(b 在字节 0 中)。
过滤BRG(或RGB)格式的图像时,必须分别过滤每个颜色通道!
分色说明:
bgrbgrbgr
bgrbgrbgr
bgrbgrbgr
分开到:
bbb ggg rrr
bbb ggg rrr
bbb ggg rrr
模糊滤镜内核是:
1/9、1/9、1/9
1/9、1/9、1/9
1/9、1/9、1/9
如前所述,过滤器应分别应用于蓝色、绿色和红色。
您可以将每个 3x3 像素相加,然后将结果除以 9(或者最好像您一样乘以 1/9)。
我使用了乘以 1/9 的定点实现,而不是转换为浮点数。
定点实现用于提高性能(这里不是那么重要,因为代码没有优化)。
我习惯于演示该技术...
我使用了一些代码重复,以强调 RGB 颜色分离。
我还处理了图像边界(使用对称镜像)。
这是我的代码:
//Filter image I with filter kernel:
// 1/9 1/9 1/9
// 1/9 1/9 1/9
// 1/9 1/9 1/9
//I - Input image in pixel ordered BGR format
//image_width - Number of columns of I
//image_height - Number of rows of I
//J - Destination "smoothed" image in BGR format.
//I and J is pixel ordered BGR color format (size in bytes is image_width*image_height*3):
//BRGBRGBRGBRGBR
//BRGBRGBRGBRGBR
//BRGBRGBRGBRGBR
//BRGBRGBRGBRGBR
//
//Limitations:
//I and J must be two separate arrays (in place computation is not supported).
void BgrSmoothing(const unsigned char I[],
int image_width,
int image_height,
unsigned char J[])
{
const int scale = (int)((1.0/9.0)*(1 << 15) + 0.5); //1/9 expanded by 2^15 (add 0.5 for rounding).
const int rounding_ofs = (1 << 14); //0.5 expanded by 2^14
int x, y;
const unsigned char *I0; //Points beginning of row y-1 (in source image I).
const unsigned char *I1; //Points beginning of row y (in source image I).
const unsigned char *I2; //Points beginning of row y+1 (in source image I).
int x0, x1, x2; //x0 - pixel to the left of x1, x1 - center, x2 - pixel to the right of x1
unsigned char *J1; //Points beginning of row y (in destination image J).
//3x3 source blue pixels, 3x3 source green pixels, 3x3 source red pixels.
unsigned char b00, b01, b02, g00, g01, g02, r00, r01, r02;
unsigned char b10, b11, b12, g10, g11, g12, r10, r11, r12;
unsigned char b20, b21, b22, g20, g21, g22, r20, r21, r22;
unsigned char b, g, r; //Destination blue, green and red pixels.
for (y = 0; y < image_height; y++)
{
if (y == 0)
I0 = I; //Handle first row: use row 0 instead of row -1 (row -1 exceeds image bounds).
else
I0 = &I[(y-1)*image_width*3]; //Pointer to beginning of source row above row y in image I.
I1 = &I[y*image_width*3]; //Pointer to beginning of source row y in image I.
if (y == image_height-1)
I2 = &I[y*image_width*3]; //Handle last row: use row image_height-1 instead of row image_height (row image_height exceeds image bounds).
else
I2 = &I[(y+1)*image_width*3]; //Pointer to beginning of source row below row y in image I.
J1 = &J[y*image_width*3]; //Pointer to beginning of destination row in image J.
//Handle first pixel:
for (x = 0; x < image_width; x++)
{
//Multiply x by 3, to convert pixel index to byte index (in BGR forst each pixel is 3 bytes).
x0 = (x == 0) ? (0) : (x-1)*3; //Handle x0 coordinate of first pixel in the row.
x1 = x*3;
x2 = (x == image_width-1) ? (image_width-1)*3 : (x+1)*3; //Handle x2 coordinate of last pixel in the row.
//Load 3x3 blue pixels:
b00 = I0[x0]; b01 = I0[x1], b02 = I0[x2];
b10 = I1[x0]; b11 = I1[x1], b12 = I1[x2];
b20 = I2[x0]; b21 = I2[x1], b22 = I2[x2];
//Load 3x3 green pixels:
g00 = I0[x0+1]; g01 = I0[x1+1], g02 = I0[x2+1];
g10 = I1[x0+1]; g11 = I1[x1+1], g12 = I1[x2+1];
g20 = I2[x0+1]; g21 = I2[x1+1], g22 = I2[x2+1];
//Load 3x3 red pixels:
r00 = I0[x0+2]; r01 = I0[x1+2], r02 = I0[x2+2];
r10 = I1[x0+2]; r11 = I1[x1+2], r12 = I1[x2+2];
r20 = I2[x0+2]; r21 = I2[x1+2], r22 = I2[x2+2];
//Sum all 9 blue elements, all 9 green elements and all 9 red elements (convert to int to avoid overflow).
int sum_b = (int)b00+(int)b01+(int)b02+(int)b10+(int)b11+(int)b12+(int)b20+(int)b21+(int)b22;
int sum_g = (int)g00+(int)g01+(int)g02+(int)g10+(int)g11+(int)g12+(int)g20+(int)g21+(int)g22;
int sum_r = (int)r00+(int)r01+(int)r02+(int)r10+(int)r11+(int)r12+(int)r20+(int)r21+(int)r22;
//b = round(sum_b*(1/9)).
//Because b i positive round(b) = floor(b+0.5).
//Use following computation instead: b = floor((sum_b*(1.0/9.0)*2^15 + 2^14) / 2^15)
b = (unsigned char)((sum_b*scale + rounding_ofs) >> 15); //Destination blue pixel.
g = (unsigned char)((sum_g*scale + rounding_ofs) >> 15); //Destination green pixel.
r = (unsigned char)((sum_r*scale + rounding_ofs) >> 15); //Destination red pixel.
//Store b,g,r elements to destination row J1.
J1[x1] = b;
J1[x1+1] = g;
J1[x1+2] = r;
}
}
}
输入图片:
输出图片: