1. 程式人生 > 其它 >快速高斯濾波函式[修正完善版]

快速高斯濾波函式[修正完善版]

原文地址:http://blog.csdn.net/markl22222/article/details/10313565
進行了修正和變數優化。原來作者的函式只支援2次方圖片,這次做了修正(windows 的 bitmap 行寬是 4 位元組對齊的)。

( 基本完善了,但是在某些條件下,Y方向的底邊還是會出現偏差,一時找不到原因,暫且發表,希望有人能提醒一下。)

今天檢查了一下程式碼,發現了一個低階的技術性錯誤,Y方向底邊的顏色偏差已經修正,這個函式趨於完美,收工。

函式結構我規整了一下,很清晰,很好閱讀。

int gauss_blur(
    byte_t* image,    //點陣圖資料
    int
linebytes, //點陣圖行位元組數,BMP資料在windows中是4位元組對齊的。否則在處理非二次冪的影象時會有偏差 int width, //點陣圖寬度 int height, //點陣圖高度 int cbyte, //顏色通道數量 float sigma //高斯係數 ) { int x = 0, y = 0, n = 0; int channel = 0; int srcline = 0, dstline = 0; int channelsize = width*height;
int bufsize = width > height ? width + 4 : height + 4; float *w1 = NULL, *w2 = NULL, *imgbuf = NULL; int time = 0; #if defined(_INC_WINDOWS) time = GetTickCount(); #elif defined(_CLOCK_T) time = clock(); #endif w1 = (float*)malloc(bufsize * sizeof(float
)); if(!w1) { return -1; } w2 = (float*)malloc(bufsize * sizeof(float)); if(!w2) { free(w1); return -1; } imgbuf = (float*)malloc(channelsize * sizeof(float)); if(!imgbuf) { free(w1); free(w2); return -1; } //----------------計算高斯核---------------------------------------// float q = 0; float q2 = 0, q3 = 0; float b0 = 0, b1 = 0, b2 = 0, b3 = 0; float B = 0; if (sigma >= 2.5f) { q = 0.98711f * sigma - 0.96330f; } else if ((sigma >= 0.5f) && (sigma < 2.5f)) { q = 3.97156f - 4.14554f * (float) sqrt (1.0f - 0.26891f * sigma); } else { q = 0.1147705018520355224609375f; } q2 = q * q; q3 = q * q2; b0 = (1.57825+ (2.44413f*q)+(1.4281f *q2)+(0.422205f*q3)); b1 = ( (2.44413f*q)+(2.85619f*q2)+(1.26661f* q3)); b2 = ( -((1.4281f*q2)+(1.26661f* q3))); b3 = ( (0.422205f*q3)); B = 1.0-((b1+b2+b3)/b0); b1 /= b0; b2 /= b0; b3 /= b0; //----------------計算高斯核結束---------------------------------------// // 處理影象的多個通道 for (channel = 0; channel < cbyte; ++channel) { // 獲取一個通道的所有畫素值,並預處理 for(y=0; y<height; ++y) { srcline = y*linebytes; dstline = y*width; for(x=0, n=channel; x<width; ++x, n+=cbyte) { (imgbuf+dstline)[x] = float((image+srcline)[n]); } } for (int x=0; x<width; ++x) {//橫向處理 w1[0] = (imgbuf + x)[0]; w1[1] = (imgbuf + x)[0]; w1[2] = (imgbuf + x)[0]; for (y=0, n=0; y<height; ++y, n+=width) { w1[y+3] = B*(imgbuf + x)[n] + (b1*w1[y+2] + b2*w1[y+1] + b3*w1[y+0]); } w2[height+0]= w1[height+2]; w2[height+1]= w1[height+1]; w2[height+2]= w1[height+0]; for (int y=height-1, n=y*width; y>=0; --y, n-=width) { //儲存資料到快取 (imgbuf + x)[n] = w2[y] = B*w1[y+3] + (b1*w2[y+1] + b2*w2[y+2] + b3*w2[y+3]); } }//橫向處理 for (y=0, srcline=0, dstline=0; y<height; ++y, srcline+=width, dstline+=linebytes) {//縱向處理 //取當前行資料 w1[0] = (imgbuf + srcline)[0]; w1[1] = (imgbuf + srcline)[0]; w1[2] = (imgbuf + srcline)[0]; //正方向橫向處理3個點的資料 for (x=0; x<width ; ++x) { w1[x+3] = B*(imgbuf + srcline)[x] + (b1*w1[x+2] + b2*w1[x+1] + b3*w1[x+0]); } w2[width+0]= w1[width+2]; w2[width+1]= w1[width+1]; w2[width+2]= w1[width+0]; //反方向處理 for (x=width-1, n=x*cbyte+channel; x>=0; --x, n-=cbyte) { //處理儲存資料到快取 //(imgbuf + dstline)[x] = w2[x] = B*w1[x+3] + (b1*w2[x+1] + b2*w2[x+2] + b3*w2[x+3]); //儲存返回資料 (image + dstline)[n] = w2[x] = B*w1[x+3] + (b1*w2[x+1] + b2*w2[x+2] + b3*w2[x+3]); } }//縱向處理 /* //儲存處理完畢的通道 for(int y=0; y<height; y++) { int dstline = y*linebytes; int srcline = y*width; for (int x=0; x<width; x++) { (image + dstline)[x * cbyte + channel] = (imgbuf + srcline)[x]; //byte_edge((imgbuf + srcline)[x]-1); } }//儲存迴圈 //*/ }//通道迴圈 free(w1); w1=NULL; free(w2); w2=NULL; free(imgbuf); imgbuf=NULL; #if defined(_INC_WINDOWS) return GetTickCount() - time; #elif defined(_CLOCK_T) return clock() - time; #else return 0; #endif }

應用例項:

//開啟一個24位BMP影象
HBITMAP hbmp = (HBITMAP)LoadImage(NULL, "a.bmp", IMAGE_BITMAP, 0, 0,
            LR_DEFAULTSIZE|LR_CREATEDIBSECTION|LR_LOADFROMFILE);
BITMAP bm;
if(hbmp)
{
    HDC dc = CreateCompatibleDC(NULL);
    SelectObject(dc, hbmp);
    GetObject(Image1->Picture->Bitmap->Handle, sizeof(bm), &bm);
    //高斯影象處理
    gauss_blur((BYTE*)bm.bmBits, bm.bmWidthBytes, bm.bmWidth, bm.bmHeight, 3, 3.0);
    //複製到你的DC上
    BitBlt(hMyDC, 0, 0, bm.bmWidth, bm.bmHeight, dc, 0, 0, SRCCOPY);
    DeleteObject(hbmp);
    DeleteDC(dc);
}

文章釋出於 2014-08-01 02:58:37,現逐步拋棄 CSDN,轉部落格園。