日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

openCV 中值滤波算法解析

發布時間:2024/8/1 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 openCV 中值滤波算法解析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

中值濾波算法是使用一個模板,在圖像中移動的過程中,取模板內的排列中間的值替代模板中心的值。

常用的中值濾波的快速算法見論文“A Fast Two-Dimensional Median Filtering Algorithm”。本人按照論文上的方法實現了一下,發現效率僅是openCV的十分之一,研究了一下openCV1.0的源碼,發現他也是用的論文上的原理,但是,他的編程手法就高明多了。下面,咱們就看一下openCV是怎么處理的!

/*

1.src原圖

2.src_step原圖步長

3.dst處理后

4.dst圖步長

5.size 圖像大小

6.m模板大小

7.cn圖像通道數

*/

static CvStatus CV_STDCALL icvMedianBlur_8u_CnR( uchar* src, int src_step, uchar* dst, int dst_step, CvSize size, int m, int cn )

{
? ?//定義16級灰度直方圖
? ? #define N ?16

? ? int zone0[4][N];

? ? //定義256級灰度直方圖
? ? int zone1[4][N*N];

? ? int x, y;


? ? //中值的位置

? ? int n2 = m*m/2;?


? ?//每行(列)的中值位置
? ? int nx = (m + 1)/2 - 1;

? ? uchar* ?src_max = src + size.height*src_step;
? ? uchar* ?src_right = src + size.width*cn;


? ? //更新直方圖
? ? #define UPDATE_ACC01( pix, cn, op ) \
? ? { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
? ? ? ? int p = (pix); ? ? ? ? ? ? ? ? ?\
? ? ? ? zone1[cn][p] op; ? ? ? ? ? ? ? ?\
? ? ? ? zone0[cn][p >> 4] op; ? ? ? ? ? \
? ? }

? ? if( size.height < nx || size.width < nx )
? ? ? ? return CV_BADSIZE_ERR;


? ? //模板大小為3時候,單獨處理(效率高)

? ? if( m == 3 )
? ? {
? ? ? ? size.width *= cn;


//列循環
? ? ? ? for( y = 0; y < size.height; y++, dst += dst_step )
? ? ? ? {
? ? ? ? ? ? const uchar* src0 = src + src_step*(y-1);
? ? ? ? ? ? const uchar* src1 = src0 + src_step;

? ? ? ? ? ? const uchar* src2 = src1 + src_step;

? ? //處理第一列的時候src0 = src1

? ? ? ? ? ? if( y == 0 )

? ? ? ? ? ? ? ? src0 = src1;

? ?//處理最后一列的時候?src2 = src1

? ? ? ? ? ? else if( y == size.height - 1 )
? ? ? ? ? ? ? ? src2 = src1;

? ? ? ? ? ?//考慮多通道循環
? ? ? ? ? ? for( x = 0; x < 2*cn; x++ )
? ? ? ? ? ? {
? ? int x0 = x < cn ? x : size.width - 3*cn + x;
int x2 = x < cn ? x + cn : size.width - 2*cn + x;
int x1 = x < cn ? x0 : x2, t;


? ? ? ? ? ? ? ? int p0 = src0[x0], p1 = src0[x1], p2 = src0[x2];
? ? ? ? ? ? ? ? int p3 = src1[x0], p4 = src1[x1], p5 = src1[x2];
? ? ? ? ? ? ? ? int p6 = src2[x0], p7 = src2[x1], p8 = src2[x2];


? ? ? ? ? ? ? ? CV_MINMAX_8U(p1, p2); CV_MINMAX_8U(p4, p5);
CV_MINMAX_8U(p7, p8); CV_MINMAX_8U(p0, p1);

CV_MINMAX_8U(p3, p4); CV_MINMAX_8U(p6, p7);

//代碼圖解:0~5代表執行順序,


??
CV_MINMAX_8U(p1, p2); CV_MINMAX_8U(p4, p5);
CV_MINMAX_8U(p7, p8); CV_MINMAX_8U(p0, p3);
CV_MINMAX_8U(p5, p8); CV_MINMAX_8U(p4, p7);

? ? ? ? ? ? ? ? //代碼圖解:0~5代表執行順序,

//經過第一步六次對比,再加上本次的0~2的三次對比,3*3的數據已經達到行向有序(從小到大)

? ? ? ? ? ? ? ? //P0 P3 P6 是行向最小值 ,P2 P5 P8 是行向最大值

? ? ? ? ? ? ? ? CV_MINMAX_8U(p3, p6); CV_MINMAX_8U(p1, p4);
? ? ? ? ? ? ? ? CV_MINMAX_8U(p2, p5); CV_MINMAX_8U(p4, p7);
? ? ? ? ? ? ? ? CV_MINMAX_8U(p4, p2); CV_MINMAX_8U(p6, p4);

//代碼圖解:0~5代表執行順序,

//經過第二步的六次對比,再加上本次的0~3的四次對比,中間列(P1、P4、P7)已到達列向有序,第一列和第三列都沒有嚴格有序

//但是,可以確定的是P6是行向小值和列向最大值, P2 是行向最大值和列向最小值


? ? ? ? ? ? ? ? CV_MINMAX_8U(p4, p2);

//第三部經過4~5兩次斜向對比,再加上本步一次對比,實現了(P2、P4、P6)的斜向有序。

//對比完成后P4就是中值

//總之,其算法的基本思路是先對數據進行排序(算法中的行向有序),然后再在三組有序的數據中找到數據合并后的中位數

//那就是,取出有序序列組的最小值中的最大值、最大值中的最小值、中間列向的中值,三個數進行比較,取其中值就是

//三個有序序列的中值

? ? ? ? ? ? ? ? dst[x1] = (uchar)p4;
? ? ? ? ? ? }


? ? ? ? ? ? for( x = cn; x < size.width - cn; x++ )
? ? ? {
int p0 = src0[x-cn], p1 = src0[x], p2 = src0[x+cn];
int p3 = src1[x-cn], p4 = src1[x], p5 = src1[x+cn];
int p6 = src2[x-cn], p7 = src2[x], p8 = src2[x+cn];
int t;


? ? ? ? ? ? ? ? CV_MINMAX_8U(p1, p2); CV_MINMAX_8U(p4, p5);
? ? ? ? ? ? ? ? CV_MINMAX_8U(p7, p8); CV_MINMAX_8U(p0, p1);
? ? ? ? ? ? ? ? CV_MINMAX_8U(p3, p4); CV_MINMAX_8U(p6, p7);
? ? ? ? ? ? ? ? CV_MINMAX_8U(p1, p2); CV_MINMAX_8U(p4, p5);
? ? ? ? ? ? ? ? CV_MINMAX_8U(p7, p8); CV_MINMAX_8U(p0, p3);
? ? ? ? ? ? ? ? CV_MINMAX_8U(p5, p8); CV_MINMAX_8U(p4, p7);
? ? ? ? ? ? ? ? CV_MINMAX_8U(p3, p6); CV_MINMAX_8U(p1, p4);
? ? ? ? ? ? ? ? CV_MINMAX_8U(p2, p5); CV_MINMAX_8U(p4, p7);
? ? ? ? ? ? ? ? CV_MINMAX_8U(p4, p2); CV_MINMAX_8U(p6, p4);
? ? ? ? ? ? ? ? CV_MINMAX_8U(p4, p2);


? ? ? ? ? ? ? ? dst[x] = (uchar)p4;
? ? ? ? ? ? }
? ? ? ? }


? ? ? ? return CV_OK;
? ? }


? ? for( x = 0; x < size.width; x++, dst += cn )
? ? {
? ? ? ? uchar* dst_cur = dst;
? ? ? ? uchar* src_top = src;
? ? ? ? uchar* src_bottom = src;
? ? ? ? int k, c;
? ? ? ? int x0 = -1;


if( x <= m/2 )
nx++;


? ? ? ? if( nx < m )
? ? ? ? ? ? x0 = x < m/2 ? 0 : (nx-1)*cn;
? ? ? ? ? ??
? ? ? ? // init accumulator
? ? ? ? memset( zone0, 0, sizeof(zone0[0])*cn );
? ? ? ? memset( zone1, 0, sizeof(zone1[0])*cn );
? ? ? ??
? ? ? ? for( y = -m/2; y < m/2; y++ )
? ? ? ? {
? ? ? ? ? ? for( c = 0; c < cn; c++ )
? ? ? ? ? ? {
if( x0 >= 0 )
UPDATE_ACC01( src_bottom[x0+c], c, += (m - nx) );
for( k = 0; k < nx*cn; k += cn )
UPDATE_ACC01( src_bottom[k+c], c, ++ );
? ? ? ? ? ? }


? ? ? ? ? ? if( (unsigned)y < (unsigned)(size.height-1) )
? ? ? ? ? ? ? ? src_bottom += src_step;
? ? ? ? }


? ? ? ? for( y = 0; y < size.height; y++, dst_cur += dst_step )
? ? ? ? {
? ? ? ? ? ? if( cn == 1 )
? ? ? ? ? ? {
? ? ? ? ? ? ? ? for( k = 0; k < nx; k++ )
? ? ? ? ? ? ? ? ? ? UPDATE_ACC01( src_bottom[k], 0, ++ );
? ? ? ? ? ? }
? ? ? ? ? ? else if( cn == 3 )
? ? ? ? ? ? {
? ? ? ? ? ? ? ? for( k = 0; k < nx*3; k += 3 )
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? UPDATE_ACC01( src_bottom[k], 0, ++ );
? ? ? ? ? ? ? ? ? ? UPDATE_ACC01( src_bottom[k+1], 1, ++ );
? ? ? ? ? ? ? ? ? ? UPDATE_ACC01( src_bottom[k+2], 2, ++ );
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? else
? ? ? ? ? ? {
? ? ? ? ? ? ? ? assert( cn == 4 );
? ? ? ? ? ? ? ? for( k = 0; k < nx*4; k += 4 )
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? UPDATE_ACC01( src_bottom[k], 0, ++ );
? ? ? ? ? ? ? ? ? ? UPDATE_ACC01( src_bottom[k+1], 1, ++ );
? ? ? ? ? ? ? ? ? ? UPDATE_ACC01( src_bottom[k+2], 2, ++ );
? ? ? ? ? ? ? ? ? ? UPDATE_ACC01( src_bottom[k+3], 3, ++ );
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }


? ? ? ? ? ? if( x0 >= 0 )
? ? ? ? ? ? {
? ? ? ? ? ? ? ? for( c = 0; c < cn; c++ )
? ? ? ? ? ? ? ? ? ? UPDATE_ACC01( src_bottom[x0+c], c, += (m - nx) );
? ? ? ? ? ? }


? ? ? ? ? ? if( src_bottom + src_step < src_max )
? ? ? ? ? ? ? ? src_bottom += src_step;


? ? ? ? ? ? // find median

? //重點介紹一下這部分代碼

//計算過16級和256級的灰度直方圖之后,查找中值就很簡單了,相見論文“A Fast Two-Dimensional Median Filtering Algorithm”。

//這里看一下openCV的實現過程,論文中介紹了利用直方圖進行中位數計算的方法,但是并未介紹使用16級的直方圖,openCV編程的巧妙之處就在于他把兩種直方圖相

?//結合,這樣就會大大加速程序的執行效率。因為遍歷一個16級的直方圖很快,但是256級的直方圖就會非常慢。openCV的這種思路還是值得大家學習的。

? //至于里面的編程技巧,大家看著學吧!

? ? ? ? ? ? for( c = 0; c < cn; c++ )
? ? ? ? ? ? {
? ? ? ? ? ? ? ? int s = 0;
? ? ? ? ? ? ? ? for( k = 0; ; k++ )
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? int t = s + zone0[c][k];
? ? ? ? ? ? ? ? ? ? if( t > n2 ) break;
? ? ? ? ? ? ? ? ? ? s = t;
? ? ? ? ? ? ? ? }


? ? ? ? ? ? ? ? for( k *= N; ;k++ )
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? s += zone1[c][k];
? ? ? ? ? ? ? ? ? ? if( s > n2 ) break;
? ? ? ? ? ? ? ? }


? ? ? ? ? ? ? ? dst_cur[c] = (uchar)k;
? ? ? ? ? ? }


? ? ? ? ? ? if( cn == 1 )
? ? ? ? ? ? {
? ? ? ? ? ? ? ? for( k = 0; k < nx; k++ )
? ? ? ? ? ? ? ? ? ? UPDATE_ACC01( src_top[k], 0, -- );
? ? ? ? ? ? }
? ? ? ? ? ? else if( cn == 3 )
? ? ? ? ? ? {
? ? ? ? ? ? ? ? for( k = 0; k < nx*3; k += 3 )
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? UPDATE_ACC01( src_top[k], 0, -- );
? ? ? ? ? ? ? ? ? ? UPDATE_ACC01( src_top[k+1], 1, -- );
? ? ? ? ? ? ? ? ? ? UPDATE_ACC01( src_top[k+2], 2, -- );
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? else
? ? ? ? ? ? {
? ? ? ? ? ? ? ? assert( cn == 4 );
? ? ? ? ? ? ? ? for( k = 0; k < nx*4; k += 4 )
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? UPDATE_ACC01( src_top[k], 0, -- );
? ? ? ? ? ? ? ? ? ? UPDATE_ACC01( src_top[k+1], 1, -- );
? ? ? ? ? ? ? ? ? ? UPDATE_ACC01( src_top[k+2], 2, -- );
? ? ? ? ? ? ? ? ? ? UPDATE_ACC01( src_top[k+3], 3, -- );
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }


? ? ? ? ? ? if( x0 >= 0 )
? ? ? ? ? ? {
? ? ? ? ? ? ? ? for( c = 0; c < cn; c++ )
? ? ? ? ? ? ? ? ? ? UPDATE_ACC01( src_top[x0+c], c, -= (m - nx) );
? ? ? ? ? ? }


? ? ? ? ? ? if( y >= m/2 )
? ? ? ? ? ? ? ? src_top += src_step;
? ? ? ? }


? ? ? ? if( x >= m/2 )
? ? ? ? ? ? src += cn;
? ? ? ? if( src + nx*cn > src_right ) nx--;
? ? }
#undef N
#undef UPDATE_ACC
? ? return CV_OK;
}

總結

以上是生活随笔為你收集整理的openCV 中值滤波算法解析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。