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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

高斯算法实现

發(fā)布時間:2024/8/26 综合教程 32 生活家
生活随笔 收集整理的這篇文章主要介紹了 高斯算法实现 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

高斯算法的原理

首先,高斯濾波算法的一般過程分為兩步:

計算掩膜(高斯核)
卷積(即掩膜上每一個位置的值和圖像對應(yīng)位置的像素值的乘積、求和運算)

其次,我們知道高斯分布也叫做正態(tài)分布;

在二維空間中,這個公式生成的曲面的等高線是從中心開始呈正態(tài)分布的同心圓。分布不為零的像素組成的卷積矩陣與原始圖像做變換。每個像素的值都是周圍相鄰像素值的加權(quán)平均。原始像素的值有最大的高斯分布值,所以有最大的權(quán)重,相鄰像素隨著距離原始像素越來越遠(yuǎn),其權(quán)重也越來越小。

通過高斯分布公式計算出需要使用的高斯核(GaussKern),也就是計算出各個位置的所需的權(quán)重大小,使得不同位置的像素值影響度不同,距離中心點的越遠(yuǎn)的位置,權(quán)重越小,反之越近的權(quán)重越大。

int* Gauss::buildGaussKern(int winSize, int sigma)
{

int wincenter, x;
float sum = 0.0f;
//計算中心點大小
wincenter = winSize / 2;
//kern用來存儲高斯模糊前的數(shù)據(jù)
//ikern用來存儲高斯模糊后與像素值256的乘積值
float *kern = (float*)malloc(winSize*sizeof(float));
int *ikern = (int*)malloc(winSize*sizeof(int));
//計算高斯分布公式的系數(shù)
float SQRT_2PI = 2.506628274631f;
float sigmaMul2PI = 1.0f / (sigma * SQRT_2PI);
float divSigmaPow2 = 1.0f / (2.0f * sigma * sigma);

for (x = 0; x < wincenter + 1; x++)
{
    kern[wincenter - x] = kern[wincenter + x] = exp(-(x * x)* divSigmaPow2) * sigmaMul2PI;
    sum += kern[wincenter - x] + ((x != 0) ? kern[wincenter + x] : 0.0);
}
sum = 1.0f / sum;

for (x = 0; x < winSize; x++)
{
    kern[x] *= sum;
    ikern[x] = kern[x] * 256.0f;
}

free(kern);
return ikern;
}

理論上來講,圖像中每點的分布都不為零,這也就是說每個像素的計算都需要包含整幅圖像。在實際應(yīng)用中,在計算高斯函數(shù)的離散近似時,在大概3σ距離之外的像素都可以看作不起作用,這些像素的計算也就可以忽略。通常,圖像處理程序只需要計算 (6 sigma + 1) imes (6 sigma + 1) 的矩陣就可以保證相關(guān)像素影響。對于邊界上的點,通常采用復(fù)制周圍的點到另一面再進(jìn)行加權(quán)平均運算。

//忽略3sigma外的像素點
//計算(6*sigma+1)*(6*sigma+1)的矩陣
unsigned int  winsize = (1 + (((int)ceil(3 * sigma)) * 2));

除了圓形對稱之外,高斯模糊也可以在二維圖像上對兩個獨立的一維空間分別進(jìn)行計算,這叫作線性可分。這也就是說,使用二維矩陣變換得到的效果也可以通過在水平方向進(jìn)行一維高斯矩陣變換加上豎直方向的一維高斯矩陣變換得到。從計算的角度來看,這是一項有用的特性,因為這樣只需要O(n * M * N) + O(m * M * N)次計算,而不可分的矩陣則需要O(m * n * M * N)次計算,其中M,N是需要進(jìn)行濾波的圖像的維數(shù),m、n是濾波器的維數(shù)。

     for (unsigned int w = 0; w < width; w += channels)
    {
        //存儲r g b分量的數(shù)據(jù)
        unsigned int rowR = 0;
        unsigned int rowG = 0;
        unsigned int rowB = 0;
        unsigned int alpha = 0;
        //將高斯系數(shù)賦值給gaussKernPtr
        int * gaussKernPtr = gaussKern;
        int whalfsize = w + width - halfsize;
        //當(dāng)前位置
        unsigned int  curPos = rowWidth + w;
        for (unsigned int k = 1; k < winsize; k += channels)
        {
            unsigned int  pos = rowWidth + ((k + whalfsize) % width);
            int fkern = *gaussKernPtr++;
            //當(dāng)前像素值乘以高斯系數(shù),rowR G B這了泛指單通道的當(dāng)前像素點高斯處理后的數(shù)
            rowR += (pixels[pos + MT_RED] * fkern);
            rowG += (pixels[pos + MT_GREEN] * fkern);
            rowB += (pixels[pos + MT_BLUE] * fkern);
            alpha += (pixels[pos + MT_ALPHA] * fkern);
        }
算法實現(xiàn)部分
void Gauss::GaussBlur(unsigned char *pixels, unsigned int width, unsigned int height, unsigned int channels, int sigma)
{
//四個通道。 存儲每行數(shù)據(jù)的寬度
width = 4 * width;

if ((width % 4) != 0)
   width += (4 - (width % 4));
//窗的大小
//忽略3sigma外的像素點
//計算(6*sigma+1)*(6*sigma+1)的矩陣
unsigned int  winsize = (1 + (((int)ceil(3 * sigma)) * 2));
//構(gòu)建高斯核,計算高斯系數(shù)
int *gaussKern = buildGaussKern(winsize, sigma);

winsize *= 3;
//窗的邊到中心的距離
unsigned int  halfsize = winsize / 2;
//開辟新的內(nèi)存存儲處理高斯模糊后的數(shù)據(jù)
unsigned char *tmpBuffer = (unsigned char*)malloc(width * height* sizeof(unsigned char));
//外層循環(huán),圖像的高度
for (unsigned int h = 0; h < height; h++)
{
    //當(dāng)前行的寬度為圖像的高度乘以每行圖像的數(shù)據(jù)所占的寬度。
    //因為是按行存儲的數(shù)組
    unsigned int  rowWidth = h * width;
    
    for (unsigned int w = 0; w < width; w += channels)
    {
        //存儲r g b alpha分量的數(shù)據(jù)
        unsigned int rowR = 0;
        unsigned int rowG = 0;
        unsigned int rowB = 0;
        unsigned int alpha = 0;
        //將高斯系數(shù)賦值給gaussKernPtr
        int * gaussKernPtr = gaussKern;
        int whalfsize = w + width - halfsize;
        //當(dāng)前位置
        unsigned int  curPos = rowWidth + w;
        for (unsigned int k = 1; k < winsize; k += channels)
        {
            unsigned int  pos = rowWidth + ((k + whalfsize) % width);
            int fkern = *gaussKernPtr++;
            //當(dāng)前像素值乘以高斯系數(shù),rowR G B這了泛指單通道的當(dāng)前像素點高斯處理后的數(shù)
            rowR += (pixels[pos + MT_RED] * fkern);
            rowG += (pixels[pos + MT_GREEN] * fkern);
            rowB += (pixels[pos + MT_BLUE] * fkern);
            alpha += (pixels[pos + MT_ALPHA] * fkern);
        }
        //除以256
        tmpBuffer[curPos + MT_RED] = ((unsigned char)(rowR >> 8));
        tmpBuffer[curPos + MT_GREEN] = ((unsigned char)(rowG >> 8));
        tmpBuffer[curPos + MT_BLUE] = ((unsigned char)(rowB >> 8));
        tmpBuffer[curPos + MT_ALPHA] = ((unsigned char)(alpha >> 8));
    }
}
winsize /= 3;
//窗的邊到中心的距離
halfsize = winsize / 2;

for (unsigned int w = 0; w < width; w++)
{
    for (unsigned int h = 0; h < height; h++)
    {
        unsigned int col_all = 0;
        int hhalfsize = h + height - halfsize;
        for (unsigned int k = 0; k < winsize; k++)
        {
            col_all += tmpBuffer[((k + hhalfsize) % height)* width + w] * gaussKern[k];
        }
        pixels[h * width + w] = (unsigned char)(col_all >> 8);
    }
}
free(tmpBuffer);
free(gaussKern);
}

總結(jié)

以上是生活随笔為你收集整理的高斯算法实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。