生活随笔
收集整理的這篇文章主要介紹了
图像处理(五)双指数磨皮
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
磨皮對于現(xiàn)在的圖像處理軟件,可以說是一項重要的功能,在天天P圖,可牛,ps,美圖秀秀等軟件中隨處可見,有可能即使你非常熟悉圖像處理的算法,然而卻不懂磨皮怎么實現(xiàn)。其實磨皮就是所謂的保邊緣濾波,也就是說在圖像處理領(lǐng)域只要是濾波算法都可以實現(xiàn)磨皮,只是效果好壞的區(qū)別,然而現(xiàn)在對于大部分,都要求具有保細(xì)節(jié)的功能,這邊先給大家介紹一種算法:雙指數(shù)保邊緣濾波,對應(yīng)的 外圍文獻(xiàn)為:《Bi-Exponential Edge-Preserving Smoother》
下面是這篇文獻(xiàn)最重要的部分,算法整個過程分為三個步驟:
(1)水平方向遞歸:包括對原始圖像的水平方向進(jìn)行向前遞歸(公式1)、對原始圖片的水平方向進(jìn)行向后遞歸(公式3),然后把向前遞歸結(jié)果、向后遞歸結(jié)果、原圖像數(shù)據(jù)做一個加權(quán)組合(公式5),得到新的像素值。
(2)垂直方向遞歸:同樣的對原始圖像數(shù)據(jù)進(jìn)行與水平方向的遞歸方式類似的方法,計算得到新的像素值
(3)把垂直遞歸與水平遞歸的結(jié)果相加,然后除以2,得到最后的結(jié)果
這個算法具有高度并行的效果,因此啟用多線程毫無壓力,而且算法是圖像中常用的遞歸加速,因此速度挺快的,如果還覺得速度不夠快,可以采用查詢表的方式
接著貼一下部分重要函數(shù)的代碼,供參考,下面代碼中我用了查詢表的方式進(jìn)行加速,速度可以比之前提高一倍,效果和原算法肉眼看不出來有什么區(qū)別,差別非常小,因此建議用查詢表進(jìn)行加速,還有其它的一些小細(xì)節(jié)我也沒有根據(jù)原文進(jìn)行寫代碼。
[cpp]?view plaincopy
void?CBeeps::Run(BYTE*?pImage,?int?nWidth,?int?nHeight,?int?nStride)?? {?? ????if?(pImage?==?NULL)?? ????{?? ????????return;?? ????}?? ????m_pImage=pImage;?? ????m_nWidth=nWidth;?? ????m_nHeight=nHeight;?? ????m_nStride=nStride;?? ?? ????ApplyBiExponentialEdgePreservingSmoother(20,0.02);?? }?? void?CBeeps::ApplyBiExponentialEdgePreservingSmoother(double?photometricStandardDeviation,?double?spatialDecay)?? {?? ????m_exp_table=new?double[256];?? ????m_g_table=new?double[256];?? ????double?c=-0.5/(photometricStandardDeviation?*?photometricStandardDeviation);?? ????double?mu=spatialDecay/(2-spatialDecay);?? ????for?(int?i=0;i<=255;i++)?? ????{?? ????????float?a=exp(c*i*i);?? ????????m_exp_table[i]=(1-spatialDecay)*?exp(c*i*i);?? ????????m_g_table[i]=mu*i;?? ????}?? ????BYTE*?p0?=m_pImage;?? ????const?int?nChannel?=?4;?? ????int?m_length?=m_nWidth*m_nHeight;?? ????float?maxerror=0;?? ????float?sum=0;?? ?????? ????#pragma?omp?parallel?for?? ????for?(int?idxChannel=0;idxChannel?<nChannel;?idxChannel++)?? ????{?? ????????double?*data1?=?new?double[m_length];?? ????????double*?data2?=?new?double[m_length];?? ?????????? ?????????? ????????BYTE?*p1=p0+idxChannel;?? ????????for?(int?i?=?0;?i?<?m_length;++i)?? ????????{?? ????????????data1[i]?=?p1[i?*?nChannel];?? ????????}?? ????????memcpy(data2,data1,?sizeof(double)?*?m_length);?? ?????????? ?????????? ?? ?????????? ?????????? ?????????? ?????????? ????????runHorizontalVertical(data1,?m_nWidth,?m_nHeight,spatialDecay,m_exp_table,m_g_table);?? ????????runVerticalHorizontal(data2,?m_nWidth,?m_nHeight,spatialDecay,m_exp_table,m_g_table);?? ????????sum=0;?? ????????for?(int?i?=0;i<m_length;++i)?? ????????{?? ?????????????? ????????????double?val=(data1[i]?+?data2[i])?*?0.5;?? ?????????????? ?????????????? ?????????????? ?????????????? ?????????????????? ?????????????? ????????????if(255.0<val)val=255.0;?? ????????????p1[i?*?nChannel]=(BYTE)val;?? ?????????}?? ?????????? ????????delete?data1;?? ????????delete?data2;?? ????}?? ?????? ????delete?m_exp_table;m_exp_table=NULL;?? ????delete?m_g_table;m_g_table=NULL;?? }?? ?? void?CBeeps::runVerticalHorizontal(double?*data,int?width,int?height,double?spatialDecay,double?*exp_table,double?*g_table)?? {?? ????int?length0=height*width;?? ????double*?g=?new?double[length0];?? ????int?m?=?0;?? ????for?(int?k2?=?0;k2<height;++k2)?? ????{?? ????????int?n?=?k2;?? ????????for?(int?k1?=?0;k1<width;++k1)?? ????????{?? ????????????g[n]=data[m++];?? ????????????n?+=?height;?? ????????}?? ????}?? ????double*p?=?new?double[length0];?? ????double*r?=?new?double[length0];?? ????memcpy(p,?g,?sizeof(double)?*?length0);?? ????memcpy(r,?g,?sizeof(double)?*?length0);?? ????for?(int?k1?=?0;k1<width;?++k1)?? ????{?? ????????int?startIndex=k1?*?height;?? ????????double?mu?=?0.0;?? ????????for?(int?k=startIndex+1,K?=startIndex+height;k<K;++k)?? ????????{?? ????????????int?div0=fabs(p[k]-p[k-1]);?? ????????????mu?=exp_table[div0];?? ????????????p[k]?=?p[k?-?1]?*?mu?+?p[k]?*?(1.0?-?mu);?? ????????}?? ????????for?(int?k?=startIndex+height-2;startIndex?<=?k;--k)?? ????????{?? ????????????int?div0=fabs(r[k]-r[k+1]);?? ????????????mu?=exp_table[div0];?? ????????????r[k]?=?r[k+1]?*?mu?+?r[k]?*?(1.0-mu)?;?? ????????}?? ????}?? ????double?rho0=1.0/(2-spatialDecay);?? ????for?(int?k?=?0;k?<length0;++k)?? ????{?? ????????r[k]=?(r[k]+p[k])*rho0-g_table[(int)g[k]];?? ????}?? ????m?=?0;?? ????for?(int?k1=0;k1<width;++k1)?? ????{?? ????????int?n?=?k1;?? ????????for?(int?k2?=0;k2<height;++k2)?? ????????{?? ????????????data[n]?=?r[m++];?? ????????????n?+=?width;?? ????????}?? ????}?? ????memcpy(p,data,?sizeof(double)?*?length0);?? ????memcpy(r,data,?sizeof(double)?*?length0);?? ????for?(int?k2?=?0;?k2<height;++k2)?? ????{?? ?? ????????int?startIndex=k2?*?width;?? ????????double?mu?=?0.0;?? ????????for?(int?k=startIndex+1,?K=startIndex+width;k<K;++k)?? ????????{?? ????????????int?div0=fabs(p[k]-p[k-1]);?? ????????????mu?=exp_table[div0];?? ????????????p[k]?=?p[k?-?1]?*?mu?+?p[k]?*?(1.0?-?mu);?? ????????}?? ????????for?(int?k=startIndex+width-2;startIndex<=k;--k)?? ????????{?? ????????????int?div0=fabs(r[k]-r[k+1]);?? ????????????mu?=exp_table[div0];?? ????????????r[k]?=?r[k?+?1]?*?mu?+?r[k]?*?(1.0?-?mu)?;?? ????????}?? ????}?? ?? ????double?init_gain_mu=spatialDecay/(2-spatialDecay);?? ????for?(int?k?=?0;?k?<length0;?k++)?? ????{?? ????????data[k]=(p[k]+r[k])*rho0-data[k]*init_gain_mu;?? ????}?? ????delete?p;?? ????delete?r;?? ????delete?g;?? }?? ?? void?CBeeps::runHorizontalVertical(double?*data,int?width,int?height,double?spatialDecay,double?*exptable,double?*g_table)?? {?? ????int?length=width*height;?? ????double*?g?=?new?double[length];?? ????double*?p?=?new?double[length];?? ????double*?r?=?new?double[length];?? ????memcpy(p,data,?sizeof(double)?*?length);?? ????memcpy(r,data,?sizeof(double)?*?length);?? ????double?rho0=1.0/(2-spatialDecay);?? ????for?(int?k2?=?0;k2?<?height;++k2)?? ????{?? ????????int?startIndex=k2?*?width;?? ????????for?(int?k=startIndex+1,K=startIndex+width;k<K;++k)?? ????????{?? ????????????int?div0=fabs(p[k]-p[k-1]);?? ????????????double?mu?=exptable[div0];?? ????????????p[k]?=?p[k?-?1]?*?mu?+?p[k]?*?(1.0?-?mu);?? ?? ????????}?? ????????for?(int?k?=startIndex?+?width?-?2;startIndex?<=?k;--k)?? ????????{?? ????????????int?div0=fabs(r[k]-r[k+1]);?? ????????????double?mu?=exptable[div0];?? ????????????r[k]?=?r[k?+?1]?*?mu?+?r[k]?*?(1.0?-?mu);?? ????????}?? ????????for?(int?k?=startIndex,K=startIndex+width;k<K;k++)?? ????????{?? ????????????r[k]=(r[k]+p[k])*rho0-?g_table[(int)data[k]];?? ????????}?? ????}?? ?????? ?? ????int?m?=?0;?? ????for?(int?k2=0;k2<height;k2++)?? ????{?? ????????int?n?=?k2;?? ????????for?(int?k1=0;k1<width;k1++)?? ????????{?? ????????????g[n]?=?r[m++];?? ????????????n?+=?height;?? ????????}?? ????}?? ????memcpy(p,?g,?sizeof(double)?*?height?*?width);?? ????memcpy(r,?g,?sizeof(double)?*?height?*?width);?? ????for?(int?k1=0;k1<width;++k1)?? ????{?? ????????int?startIndex=k1?*?height;?? ????????double?mu?=?0.0;?? ????????for?(int?k?=startIndex+1,K?=startIndex+height;k<K;++k)?? ????????{?? ????????????int?div0=fabs(p[k]-p[k-1]);?? ????????????mu?=exptable[div0];?? ????????????p[k]?=?p[k?-?1]?*?mu?+?p[k]?*?(1.0?-?mu);?? ????????}?? ????????for?(int?k=startIndex+height-2;startIndex<=k;--k)?? ????????{?? ????????????int?div0=fabs(r[k]-r[k+1]);?? ????????????mu?=exptable[div0];?? ????????????r[k]?=?r[k?+?1]?*?mu?+?r[k]?*?(1.0?-?mu);?? ????????}?? ????}?? ?? ?? ?? ????double?init_gain_mu=spatialDecay/(2-spatialDecay);?? ????for?(int?k?=?0;k?<length;++k)?? ????{?? ????????r[k]=?(r[k]+p[k])*rho0-?g[k]*init_gain_mu;?? ????}?? ????m?=?0;?? ????for?(int?k1=0;k1<width;++k1)?? ????{?? ????????int?n?=?k1;?? ????????for?(int?k2=0;k2<height;++k2)?? ????????{?? ????????????data[n]=r[m++];?? ????????????n?+=?width;?? ????????}?? ????}?? ????delete?p;?? ????delete?r;?? ????delete?g;?? }??
最后看一下我用這個算法,實現(xiàn)磨皮的結(jié)果:
原圖
美圖秀秀磨皮結(jié)果
雙指數(shù)遞歸算法磨皮結(jié)果
本文地址:http://blog.csdn.net/hjimce/article/details/45420965?? ?作者:hjimce ? ? 聯(lián)系qq:1393852684 ? ??更多資源請關(guān)注我的博客:http://blog.csdn.net/hjimce?? ? ? ? ? ? ? ? ?原創(chuàng)文章,版權(quán)所有,轉(zhuǎn)載請保留這兩行作者信息
總結(jié)
以上是生活随笔為你收集整理的图像处理(五)双指数磨皮的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。