【影象演算法】高斯模糊+徑向縮放模糊

查志強發表於2014-11-21

【原文:http://blog.csdn.net/meegomeego/article/details/8790309

初學圖形程式設計,開始記錄

工作內容:通過學習某知名商業引擎,構建新遊戲引擎,對新引擎進行簡單測試。

札記:

1、移植程式碼大部分時間都是很枯燥的,不用想只需要重複的做,重複的做。。。。, 最多要改的地方就是編碼規範,然後是在許多模組沒有建立的基礎上對把移植好的模組編譯連線,最重要的技巧就是註釋,許多設計沒有建立的模組太多,只能留下空實現的函式,以後用到的時候再實現吧。

2、這次做完了Texture模組,雖然還沒有做任何渲染相關的程式碼,但是測試還是需要的,不然以後累加起來可能就忘記了。

2.1。測試流程:載入一個圖片到快取,操作快取(即畫素),做出特定的模糊效果,再另儲存為檔案,進行檢視。(注:檔案操作和DDS影象檔案讀取已經做完)

2.2。製作高斯模糊(累加畫素求平均值):

      輸入:畫素資料指標,高斯模糊半徑(X和Y分量上各一個)

      演算法流程:1、遍歷每一個畫素點

                     2、以這個畫素點為中心,根據高斯模糊半徑建立一個區域,此區域內的畫素用來計算中心點畫素的高斯模糊值。

                     3、遍歷這個區域的每一個畫素,累加RGBA的各個分量值(我測試的圖片是32位的DDS檔案)。

                     4、用各個分量除以累加的數量組合成一個畫素(即高斯模糊後的畫素點)。

      注:

          1、使用unsigned char儲存一個畫素的分量,但累加的時候要使用更大儲存空間的型別比如unsigned int,否則會溢位。

          2、這次操作的影象是讀DDS檔案,儲存格式為BMP,發現兩種格式檔案的RGBA的通道儲存順序是不一致的,所以操作的時候要改為正確的才能進行儲存。

          3、BMP格式解析檔案是從下到上進行倒置儲存的。

          4、進行多次遍歷畫素點的時候要保持遍歷的順序,否則容易出現貼圖倒置或翻轉的效果。

      事例程式碼:

//---------------------------------------------------------------------------
void FillPerPixelGaussBlur(yqg_IPixelData * pDest, DWORD originX, DWORD originY, BYTE * pSrc, DWORD radiusX, DWORD radiusY)
{
    // 記錄共受多少個畫素的影響
    DWORD t_Num = 0;
    // 獲得高斯模糊半徑內的畫素區域
    DWORD t_pixelLeft  = originX > radiusX ? originX-radiusX : 0;
    DWORD t_pixelTop   = originY > radiusY ? originY-radiusY : 0;
    DWORD t_pixelRight = (originX+radiusX) < pDest->GetWidth()  ? originX+radiusX : pDest->GetWidth();
    DWORD t_pixelBottom= (originY+radiusY) < pDest->GetHeight() ? originY+radiusY : pDest->GetHeight();
    DWORD t_pPixels[4];
    for(int t_d = 0; t_d < 4; ++t_d)
    {
        t_pPixels[t_d] = 0;
    }
    // 遍歷區域內的每個元素
    for(DWORD t_dX = t_pixelLeft; t_dX < t_pixelRight; ++t_dX)
    {
        for(DWORD t_dY = t_pixelTop; t_dY < t_pixelBottom; ++t_dY)
        {
            // 計數
            ++t_Num;
            // 將影響畫素分值新增到高斯模糊畫素上
            BYTE * t_pOrigin = (BYTE*)&(((DWORD*)pSrc)[t_dX + t_dY * pDest->GetWidth()]);
            t_pPixels[0] = t_pPixels[0] + *(t_pOrigin+0);            //Red
            t_pPixels[1] = t_pPixels[1] + *(t_pOrigin+1);            //Green
            t_pPixels[2] = t_pPixels[2] + *(t_pOrigin+2);            //Blue
            t_pPixels[3] = t_pPixels[3] + *(t_pOrigin+3);            //Alpha
        }
    }
    // 取累加後的畫素平均值,即高斯模糊
    if(t_Num != 0)
    {
        BYTE * t_pDestPixel = pDest->operator()(originX, originY);
        *(t_pDestPixel+0) = (BYTE)(t_pPixels[0] / t_Num);//Blue    
        *(t_pDestPixel+1) = (BYTE)(t_pPixels[1] / t_Num);//Green
        *(t_pDestPixel+2) = (BYTE)(t_pPixels[2] / t_Num);//Red
        *(t_pDestPixel+3) = (BYTE)(t_pPixels[3] / t_Num);
    }
}
//---------------------------------------------------------------------------

2.3。製作徑向縮放模糊(針對任意一點,迴圈數量,根據數量值求出單位縮放,確定當前數量下的畫素點,進行累加,然後求平均值):

      輸入:畫素資料指標,徑向縮放中心點(指定的畫素位置),數量

      演算法流程:1、遍歷每一個畫素點

                     2、迴圈數量,根據每個數量下的單位縮放值和中心點累加畫素值。

                     3、求平均值,即該畫素點的徑向縮放模糊值。

      注:做縮放值和畫素點的計算時要確定型別,如unsigned int相減是不會的得到負數的,細節很重要。

      事例程式碼:

//---------------------------------------------------------------------------
void FillPerPixelRadialBlur(yqg_IPixelData * pDest, BYTE * pSrc, DWORD dCenterX, DWORD dCenterY, DWORD dNum, DWORD dCurrentPosX, DWORD dCurrentPosY)
{
    // 縮放值
    float t_fScale;
    // 根據縮放值和中心點計算後用來累加畫素點的位置
    DWORD t_caluPixelPosX;
    DWORD t_caluPixelPosY;
    // 臨時儲存累加的計算結果,並初始化
    DWORD t_pPixels[4];
    for(int t_d = 0; t_d < 4; ++t_d)
    {
        t_pPixels[t_d] = 0;
    }
    // 遍歷數量
    for(DWORD t_dIndex = 0; t_dIndex < dNum; ++t_dIndex)
    {
        // 計算縮放值
        t_fScale = 1.0f + (-(dNum*1.0f/pDest->GetWidth()) * t_dIndex) / (dNum - 1);
        // 計算累加畫素點的位置
        t_caluPixelPosX = (DWORD)(((int)dCurrentPosX - (int)dCenterX) * t_fScale + dCenterX);
        t_caluPixelPosY = (DWORD)(((int)dCurrentPosY - (int)dCenterY) * t_fScale + dCenterY);
        t_caluPixelPosX = (t_caluPixelPosX > (pDest->GetWidth() - 1)) ? (pDest->GetWidth() - 1) : t_caluPixelPosX;
        t_caluPixelPosY = (t_caluPixelPosY > (pDest->GetHeight() - 1)) ? (pDest->GetHeight() - 1) : t_caluPixelPosY;
        // 將影響畫素分值新增到徑向縮放模糊畫素上
        BYTE * t_pOrigin = (BYTE*)&(((DWORD*)pSrc)[t_caluPixelPosX + t_caluPixelPosY * pDest->GetWidth()]);
        t_pPixels[0] = t_pPixels[0] + *(t_pOrigin+0);            //Red
        t_pPixels[1] = t_pPixels[1] + *(t_pOrigin+1);            //Green
        t_pPixels[2] = t_pPixels[2] + *(t_pOrigin+2);            //Blue
        t_pPixels[3] = t_pPixels[3] + *(t_pOrigin+3);            //Alpha
    }
    // 取累加後的畫素平均值,即高斯模糊
    BYTE * t_pDestPixel = pDest->operator()(dCurrentPosX, dCurrentPosY);
    *(t_pDestPixel+0) = (BYTE)(t_pPixels[0] / dNum);//Blue
    *(t_pDestPixel+1) = (BYTE)(t_pPixels[1] / dNum);//Green
    *(t_pDestPixel+2) = (BYTE)(t_pPixels[2] / dNum);//Red
    *(t_pDestPixel+3) = (BYTE)(t_pPixels[3] / dNum);

}
//---------------------------------------------------------------------------

以下是原圖和效果圖

 

相關文章