图像处理(五)双指数磨皮

磨皮对于现在的图像处理软件,可以说是一项重要的功能,在天天P图,可牛,ps,美图秀秀等软件中随处可见,有可能即使你非常熟悉图像处理的算法,然而却不懂磨皮怎么实现。其实磨皮就是所谓的保边缘滤波,也就是说在图像处理领域只要是滤波算法都可以实现磨皮,只是效果好坏的区别,然而现在对于大部分,都要求具有保细节的功能,这边先给大家介绍一种算法:双指数保边缘滤波,对应的 外围文献为:《Bi-Exponential Edge-Preserving Smoother》

下面是这篇文献最重要的部分,算法整个过程分为三个步骤:

(1)水平方向递归:包括对原始图像的水平方向进行向前递归(公式1)、对原始图片的水平方向进行向后递归(公式3),然后把向前递归结果、向后递归结果、原图像数据做一个加权组合(公式5),得到新的像素值。

(2)垂直方向递归:同样的对原始图像数据进行与水平方向的递归方式类似的方法,计算得到新的像素值

(3)把垂直递归与水平递归的结果相加,然后除以2,得到最后的结果

这个算法具有高度并行的效果,因此启用多线程毫无压力,而且算法是图像中常用的递归加速,因此速度挺快的,如果还觉得速度不够快,可以采用查询表的方式

图像处理(五)双指数磨皮_第1张图片

接着贴一下部分重要函数的代码,供参考,下面代码中我用了查询表的方式进行加速,速度可以比之前提高一倍,效果和原算法肉眼看不出来有什么区别,差别非常小,因此建议用查询表进行加速,还有其它的一些小细节我也没有根据原文进行写代码。

[cpp]  view plain  copy
  1. void CBeeps::Run(BYTE* pImage, int nWidth, int nHeight, int nStride)  
  2. {  
  3.     if (pImage == NULL)  
  4.     {  
  5.         return;  
  6.     }  
  7.     m_pImage=pImage;  
  8.     m_nWidth=nWidth;  
  9.     m_nHeight=nHeight;  
  10.     m_nStride=nStride;  
  11.   
  12.     ApplyBiExponentialEdgePreservingSmoother(20,0.02);  
  13. }  
  14. void CBeeps::ApplyBiExponentialEdgePreservingSmoother(double photometricStandardDeviation, double spatialDecay)  
  15. {  
  16.     m_exp_table=new double[256];  
  17.     m_g_table=new double[256];  
  18.     double c=-0.5/(photometricStandardDeviation * photometricStandardDeviation);  
  19.     double mu=spatialDecay/(2-spatialDecay);  
  20.     for (int i=0;i<=255;i++)  
  21.     {  
  22.         float a=exp(c*i*i);  
  23.         m_exp_table[i]=(1-spatialDecay)* exp(c*i*i);  
  24.         m_g_table[i]=mu*i;  
  25.     }  
  26.     BYTE* p0 =m_pImage;  
  27.     const int nChannel = 4;  
  28.     int m_length =m_nWidth*m_nHeight;  
  29.     float maxerror=0;  
  30.     float sum=0;  
  31.     // 对每个channel进行处理  
  32.     #pragma omp parallel for  
  33.     for (int idxChannel=0;idxChannel 
  34.     {  
  35.         double *data1 = new double[m_length];  
  36.         double* data2 = new double[m_length];  
  37.         //double* data3 = new double[m_length];  
  38.         //double* data4 = new double[m_length];  
  39.         BYTE *p1=p0+idxChannel;  
  40.         for (int i = 0; i < m_length;++i)  
  41.         {  
  42.             data1[i] = p1[i * nChannel];  
  43.         }  
  44.         memcpy(data2,data1, sizeof(double) * m_length);  
  45.         //memcpy(data3,data1, sizeof(double) * m_length);  
  46.         //memcpy(data4,data1, sizeof(double) * m_length);  
  47.   
  48.         //CBEEPSHorizontalVertical hv(data3, m_nWidth, m_nHeight,  photometricStandardDeviation, spatialDecay);  
  49.         //hv.run();  
  50.         //CBEEPSVerticalHorizontal vh(data4, m_nWidth, m_nHeight, photometricStandardDeviation, spatialDecay);  
  51.         //vh.run();  
  52.         runHorizontalVertical(data1, m_nWidth, m_nHeight,spatialDecay,m_exp_table,m_g_table);  
  53.         runVerticalHorizontal(data2, m_nWidth, m_nHeight,spatialDecay,m_exp_table,m_g_table);  
  54.         sum=0;  
  55.         for (int i =0;i
  56.         {  
  57.             //double val = (data3[i] + data4[i]) * 0.5;  
  58.             double val=(data1[i] + data2[i]) * 0.5;  
  59.             //double error0=abs((int)val2-(int)val);  
  60.             //sum=sum+error0;  
  61.             //if (error0>maxerror)  
  62.             //{  
  63.                 //maxerror=error0;  
  64.             //}  
  65.             if(255.0
  66.             p1[i * nChannel]=(BYTE)val;  
  67.          }  
  68.         //sum=sum/m_length;  
  69.         delete data1;  
  70.         delete data2;  
  71.     }//for  
  72.       
  73.     delete m_exp_table;m_exp_table=NULL;  
  74.     delete m_g_table;m_g_table=NULL;  
  75. }  
  76. //垂直方向递归  
  77. void CBeeps::runVerticalHorizontal(double *data,int width,int height,double spatialDecay,double *exp_table,double *g_table)  
  78. {  
  79.     int length0=height*width;  
  80.     double* g= new double[length0];  
  81.     int m = 0;  
  82.     for (int k2 = 0;k2
  83.     {  
  84.         int n = k2;  
  85.         for (int k1 = 0;k1
  86.         {  
  87.             g[n]=data[m++];  
  88.             n += height;  
  89.         }  
  90.     }  
  91.     double*p = new double[length0];  
  92.     double*r = new double[length0];  
  93.     memcpy(p, g, sizeof(double) * length0);  
  94.     memcpy(r, g, sizeof(double) * length0);  
  95.     for (int k1 = 0;k1
  96.     {  
  97.         int startIndex=k1 * height;  
  98.         double mu = 0.0;  
  99.         for (int k=startIndex+1,K =startIndex+height;k
  100.         {  
  101.             int div0=fabs(p[k]-p[k-1]);  
  102.             mu =exp_table[div0];  
  103.             p[k] = p[k - 1] * mu + p[k] * (1.0 - mu);//文献中的公式1,这里做了一下修改,效果影响不大  
  104.         }  
  105.         for (int k =startIndex+height-2;startIndex <= k;--k)  
  106.         {  
  107.             int div0=fabs(r[k]-r[k+1]);  
  108.             mu =exp_table[div0];  
  109.             r[k] = r[k+1] * mu + r[k] * (1.0-mu) ;//文献公式3  
  110.         }  
  111.     }  
  112.     double rho0=1.0/(2-spatialDecay);  
  113.     for (int k = 0;k 
  114.     {  
  115.         r[k]= (r[k]+p[k])*rho0-g_table[(int)g[k]];  
  116.     }  
  117.     m = 0;  
  118.     for (int k1=0;k1
  119.     {  
  120.         int n = k1;  
  121.         for (int k2 =0;k2
  122.         {  
  123.             data[n] = r[m++];  
  124.             n += width;  
  125.         }  
  126.     }  
  127.     memcpy(p,data, sizeof(double) * length0);  
  128.     memcpy(r,data, sizeof(double) * length0);  
  129.     for (int k2 = 0; k2
  130.     {  
  131.   
  132.         int startIndex=k2 * width;  
  133.         double mu = 0.0;  
  134.         for (int k=startIndex+1, K=startIndex+width;k
  135.         {  
  136.             int div0=fabs(p[k]-p[k-1]);  
  137.             mu =exp_table[div0];  
  138.             p[k] = p[k - 1] * mu + p[k] * (1.0 - mu);  
  139.         }  
  140.         for (int k=startIndex+width-2;startIndex<=k;--k)  
  141.         {  
  142.             int div0=fabs(r[k]-r[k+1]);  
  143.             mu =exp_table[div0];  
  144.             r[k] = r[k + 1] * mu + r[k] * (1.0 - mu) ;  
  145.         }  
  146.     }  
  147.   
  148.     double init_gain_mu=spatialDecay/(2-spatialDecay);  
  149.     for (int k = 0; k 
  150.     {  
  151.         data[k]=(p[k]+r[k])*rho0-data[k]*init_gain_mu;//文献中的公式5  
  152.     }  
  153.     delete p;  
  154.     delete r;  
  155.     delete g;  
  156. }  
  157. //水平方向递归  
  158. void CBeeps::runHorizontalVertical(double *data,int width,int height,double spatialDecay,double *exptable,double *g_table)  
  159. {  
  160.     int length=width*height;  
  161.     double* g = new double[length];  
  162.     double* p = new double[length];  
  163.     double* r = new double[length];  
  164.     memcpy(p,data, sizeof(double) * length);  
  165.     memcpy(r,data, sizeof(double) * length);  
  166.     double rho0=1.0/(2-spatialDecay);  
  167.     for (int k2 = 0;k2 < height;++k2)  
  168.     {  
  169.         int startIndex=k2 * width;  
  170.         for (int k=startIndex+1,K=startIndex+width;k
  171.         {  
  172.             int div0=fabs(p[k]-p[k-1]);  
  173.             double mu =exptable[div0];  
  174.             p[k] = p[k - 1] * mu + p[k] * (1.0 - mu);//文献公式1  
  175.   
  176.         }  
  177.         for (int k =startIndex + width - 2;startIndex <= k;--k)  
  178.         {  
  179.             int div0=fabs(r[k]-r[k+1]);  
  180.             double mu =exptable[div0];  
  181.             r[k] = r[k + 1] * mu + r[k] * (1.0 - mu);//文献公式3  
  182.         }  
  183.         for (int k =startIndex,K=startIndex+width;k
  184.         {  
  185.             r[k]=(r[k]+p[k])*rho0- g_table[(int)data[k]];  
  186.         }  
  187.     }  
  188.       
  189.   
  190.     int m = 0;  
  191.     for (int k2=0;k2
  192.     {  
  193.         int n = k2;  
  194.         for (int k1=0;k1
  195.         {  
  196.             g[n] = r[m++];  
  197.             n += height;  
  198.         }  
  199.     }  
  200.     memcpy(p, g, sizeof(double) * height * width);  
  201.     memcpy(r, g, sizeof(double) * height * width);  
  202.     for (int k1=0;k1
  203.     {  
  204.         int startIndex=k1 * height;  
  205.         double mu = 0.0;  
  206.         for (int k =startIndex+1,K =startIndex+height;k
  207.         {  
  208.             int div0=fabs(p[k]-p[k-1]);  
  209.             mu =exptable[div0];  
  210.             p[k] = p[k - 1] * mu + p[k] * (1.0 - mu);  
  211.         }  
  212.         for (int k=startIndex+height-2;startIndex<=k;--k)  
  213.         {  
  214.             int div0=fabs(r[k]-r[k+1]);  
  215.             mu =exptable[div0];  
  216.             r[k] = r[k + 1] * mu + r[k] * (1.0 - mu);  
  217.         }  
  218.     }  
  219.   
  220.   
  221.   
  222.     double init_gain_mu=spatialDecay/(2-spatialDecay);  
  223.     for (int k = 0;k 
  224.     {  
  225.         r[k]= (r[k]+p[k])*rho0- g[k]*init_gain_mu;  
  226.     }  
  227.     m = 0;  
  228.     for (int k1=0;k1
  229.     {  
  230.         int n = k1;  
  231.         for (int k2=0;k2
  232.         {  
  233.             data[n]=r[m++];  
  234.             n += width;  
  235.         }  
  236.     }  
  237.     delete p;  
  238.     delete r;  
  239.     delete g;  
  240. }  


最后看一下我用这个算法,实现磨皮的结果:

图像处理(五)双指数磨皮_第2张图片

原图

图像处理(五)双指数磨皮_第3张图片

美图秀秀磨皮结果

图像处理(五)双指数磨皮_第4张图片

双指数递归算法磨皮结果

本文地址:http://blog.csdn.net/hjimce/article/details/45420965    作者:hjimce     联系qq:1393852684     更多资源请关注我的博客:http://blog.csdn.net/hjimce                  原创文章,版权所有,转载请保留这两行作者信息

你可能感兴趣的:(图像处理)