« WIN32下的窗口子类化点与直方图处理的小结 »

图像处理里的空间域滤波

图像处理里面比较基本的操作是在空间域的滤波处理。最常见的模糊啊锐化啊的都可以归于这类。其实质就是邻域间的组合运算,在shader技术上的乒乓也就差不多这个样子,而且操作纹理要更简捷。——ZwqXin.com

本文来源于 ZwqXin (http://www.zwqxin.com/), 转载请注明
      原文地址:http://www.zwqxin.com/archives/image-processing/image-process-spatial-domain-filter.html

比较直方图类那种“单点”操作,空间域滤波中的每个像素都得多少顾及一下邻里情况,因而依其关注面大小而出现了不同大小的“邻域”的定义。至于不同的空间域滤波对应不同类型的矩阵式,就是所谓的“滤波”(FILTER),或者说模板。简单的就是3*3大小的高斯平滑,中值平滑,一阶梯度锐化/边缘,二阶拉普拉斯锐化/边缘等等,还有实现各种不同效果的FILTER,可上网找找,其实运用都是差不多的,但是要得出一个“有价值”的FILTER,可不是随随便便就能行的。

在[基于亮度的图像二值化处理] 里对8BIT,16BIT,24/32BIT的BMP分别应用“单点”的计算,一提取BMP数据区的像素信息,马上就作转换操作了,而在“邻域”计算里,把全部像素信息提取出来后,再进行转换操作比较合适:

  1. void SpatialDomainTemplate::BmpProcess24_32(OperateBMP& image, int Hdis, int Wdis, int step)
  2. {
  3.       int index;
  4.       int Wmax = (Wdis-1)*step;
  5.       FilterColor *color;
  6.       FilterColor *result_color; 
  7.  
  8.              color = new FilterColor[Hdis*Wdis];
  9.       result_color = new FilterColor[Hdis*Wdis];
  10.       memset(color, 0, Hdis*Wdis*sizeof(FilterColor));
  11.       memset(result_color, 0, Hdis*Wdis*sizeof(FilterColor));
  12.  
  13.       for(int j = 0; j < Hdis; j++)
  14.         for(int i = 0; i < Wdis; i++)
  15.         {
  16.             index = j*Wdis + i;
  17.             color[index].blue   =  image.GetImageData().buffer[i*step + 0 + Wmax * j];
  18.             color[index].green  =  image.GetImageData().buffer[i*step + 1 + Wmax * j];
  19.             color[index].red    =  image.GetImageData().buffer[i*step + 2 + Wmax * j];
  20.         }
  21.  
  22.  
  23.         ApplyTemplate(color, result_color, Hdis, Wdis);
  24.  
  25.         if(GetReadBack())
  26.         {
  27.           for(int k = 0; k < Hdis; k++)
  28.             for(int l = 0; l < Wdis; l++)
  29.             {
  30.               index = k*Wdis + l;
  31.               image.GetImageData().buffer[l*step + 0 + Wmax * k] = result_color[index].blue;
  32.               image.GetImageData().buffer[l*step + 1 + Wmax * k] = result_color[index].green;
  33.               image.GetImageData().buffer[l*step + 2 + Wmax * k] = result_color[index].red;     
  34.             }
  35.  
  36.         }
  37.  
  38.     delete []color;
  39.     delete []result_color;
  40. }

这是24/32BIT版本,其他BIT的可参照上篇文章,类似的。color,resultcolor数组分别作为操作函数ApplyTemplate的输入和输出,模板操作就在此函数里完成——它无关BMP是多少BIT的,进来的是一个代表原图像的RGB数组,出来的是代表结果图像的RGB数组,就这样。当然可以看出为了结构我还是牺牲了不少“效率”的。

  1. void SpatialDomainTemplate::ApplyTemplate(FilterColor* oColor, FilterColor* rColor, int Hdis, int Wdis)
  2. {
  3.     if(FilterType == AverageBlur)
  4.         ApplyAverageBlur(oColor, rColor, Hdis, Wdis);
  5.  
  6.     if(FilterType == MedianBlur)
  7.         ApplyMedianBlur(oColor, rColor, Hdis, Wdis);
  8.  
  9.     if(FilterType == FirstOrderSharp)
  10.         ApplyFirstOrderSharp(oColor, rColor, Hdis, Wdis);
  11.  
  12.     if(FilterType == SecondOrderSharp)
  13.         ApplySecondOrderSharp(oColor, rColor, Hdis, Wdis);
  14.  
  15.     if(FilterType == SelfDefine)
  16.         ApplySelfDefine(oColor, rColor, Hdis, Wdis);
  17. }

根据客户端的要求,调用不同的FILTER。举最后一个(自定义)为例:

  1. void SpatialDomainTemplate::ApplySelfDefine(FilterColor* oColor, FilterColor* rColor, int Hdis, int Wdis)
  2. {
  3.       for(int j = 0; j < Hdis; j++)
  4.         for(int i = 0; i < Wdis; i++)
  5.         {
  6.             AdjustImageEdge(i, j, Wdis, Hdis);
  7.  
  8.             rColor[Index[1][1]] 
  9.           = oColor[ Index[0][0] ] * templateParam[2]
  10.           + oColor[ Index[0][1] ] * templateParam[3]
  11.           + oColor[ Index[0][2] ] * templateParam[4]
  12.           + oColor[ Index[1][0] ] * templateParam[5]
  13.           + oColor[ Index[1][1] ] * templateParam[6]
  14.           + oColor[ Index[1][2] ] * templateParam[7]
  15.           + oColor[ Index[2][0] ] * templateParam[8]
  16.           + oColor[ Index[2][1] ] * templateParam[9]
  17.           + oColor[ Index[2][2] ] * templateParam[10];
  18.  
  19.             rColor[Index[1][1]] = rColor[Index[1][1]] * templateParam[0] / templateParam[1];
  20.  
  21.             if(rColor[Index[1][1]].blue < 0) rColor[Index[1][1]].blue = 0;
  22.             if(rColor[Index[1][1]].green < 0)rColor[Index[1][1]].green = 0;
  23.             if(rColor[Index[1][1]].red < 0)  rColor[Index[1][1]].red = 0;
  24.         }
  25.  
  26. }

对每个像素,以它为中心的3邻域每个邻接像素都乘以一个系数,相加后结果乘以一个主调节量,判断边界后得到该元素的结果。加上类型转换的截断,可以保证结果在0~255之间——为免去计算过程越界的危险,FilerColor间是整型的运算:

  1. class FilterColor {
  2. public:
  3.  
  4.    int red;
  5.  int green;
  6.  int blue;
  7. ............
  8.  
  9. }

只要最后结果的类型是UCHAR(或BYTE),VC6就能自动类型转换从INT转换到UCHAR。AdjustImageEdge函数是调节边界的,这里对于边界元素,它的那些“不存在的邻居”都被虚拟成一个与该像素等值的像素。边界问题总是那样需要掂量啊。

高斯平滑:

 原图片:
图像空间域-----www.zwqxin.com
处理后:
图像空间域处理-----www.zwqxin.com

本文来源于 ZwqXin (http://www.zwqxin.com/), 转载请注明
      原文地址:http://www.zwqxin.com/archives/image-processing/image-process-spatial-domain-filter.html

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

IE下本页面显示有问题?

→点击地址栏右侧【兼容视图】←

日历

Search

网站分类

最新评论及回复

最近发表

Powered By Z-Blog 1.8 Walle Build 100427

Copyright 2008-2013 ZwqXin. All Rights Reserved. Theme edited from ipati.