歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

C++實現純高斯模糊算法處理灰度圖片

實現功能:
C++語言實現純高斯模糊處理灰度圖像,不受圖片格式限制

算法實現:
/// <summary>   
/// 程序功能:c語言實現純高斯模糊處理灰度圖像 
/// 系統win7,VS2010開發環境,編程語言C++,OpenCV2.4.7最新整理時間 whd 2016.9.9。
/// </summary>
/// <param name=" pixels">源圖像數據在內存的起始地址。</param>
/// <param name="width">源和目標圖像的寬度。</param>
/// <param name="height">源和目標圖像的高度。</param>
/// <param name=" channels">通道數,灰度圖像cn=1,彩色圖像cn=3</param>
/// <param name="sigma">sigma的平方是高斯函數的方差</param>
/// <remarks> 1: 能處理8位灰度和24位圖像。需要分開進行,後面會合成一個程序</remarks>
//  以下為參考函數實現的整個過程
//(1)建立工程,復制粘貼博客代碼。
// (2) 添加malloc()和free()函數的頭文件
// (3) exp()函數的頭文件
// (4) 修改Gasussblur中形參int sigma為float sigma,更加符合實際情況
// (5) 配置OpenCV
// (6) 調用函數
#include "stdafx.h"
#include<stdlib.h>  //malloc(),free()函數需要的頭文件
#include<math.h>
#include<windows.h>  //包含時鐘頭文件
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
inline int* buildGaussKern(int winSize, int sigma)
{
    int wincenter, x;
    float  sum = 0.0f;
    wincenter = winSize / 2;
    float *kern = (float*)malloc(winSize*sizeof(float));
    int *ikern = (int*)malloc(winSize*sizeof(int));
    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;
}
void GaussBlur(unsigned char*  pixels, unsigned int    width, unsigned int  height, unsigned  int channels, float sigma)
{
    width = 3 * width;
    if ((width % 4) != 0) width += (4 - (width % 4));

    unsigned int  winsize = (1 + (((int)ceil(3 * sigma)) * 2));
    int *gaussKern = buildGaussKern(winsize, sigma);
    winsize *= 3;
    unsigned int  halfsize = winsize / 2;

    unsigned char *tmpBuffer = (unsigned char*)malloc(width * height* sizeof(unsigned char));

    for (unsigned int h = 0; h < height; h++)
    {
        unsigned int  rowWidth = h * width;

        for (unsigned int w = 0; w < width; w += channels)
        {
            unsigned int rowR = 0;
            unsigned int rowG = 0;
            unsigned int rowB = 0;
            int * gaussKernPtr = gaussKern;
            int whalfsize = w + width - halfsize;
            unsigned int  curPos = rowWidth + w;
            for (unsigned int k = 1; k < winsize; k += channels)
            {
                unsigned int  pos = rowWidth + ((k + whalfsize) % width);
                int fkern = *gaussKernPtr++;
                rowR += (pixels[pos] * fkern);
                rowG += (pixels[pos + 1] * fkern);
                rowB += (pixels[pos + 2] * fkern);
            }

            tmpBuffer[curPos] = ((unsigned char)(rowR >> 8));
            tmpBuffer[curPos + 1] = ((unsigned char)(rowG >> 8));
            tmpBuffer[curPos + 2] = ((unsigned char)(rowB >> 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);
}
void GaussBlur1D(unsigned char*  pixels,unsigned char*  pixelsout, unsigned int  width, unsigned int  height, float sigma)  //刪掉unsigned  int channels,因為是單通道沒有用
{
    width = 1 * width;  //3修改為1,因為三個通道變為了1個通道,存儲每行數據的寬度變為了原來的1/3.
    if ((width % 4) != 0) width += (4 - (width % 4));

    unsigned int  winsize = (1 + (((int)ceil(3 * sigma)) * 2));  //窗的大小
    int *gaussKern = buildGaussKern(winsize, sigma); //構建高斯核,計算高斯系數
    winsize *= 1; //3改為1,高斯窗的寬度變為原來的1/3
    unsigned int  halfsize = winsize / 2;  //窗的邊到中心的距離

    unsigned char *tmpBuffer = (unsigned char*)malloc(width * height* sizeof(unsigned char));  //開辟新的內存存儲處理高斯模糊後的數據

    for (unsigned int h = 0; h < height; h++)    //外層循環,圖像的高度
    {
        unsigned int  rowWidth = h * width;    //當前行的寬度為圖像的高度乘以每行圖像的數據所占的寬度。因為是按行存儲的數組。

        for (unsigned int w = 0; w < width; w++) //w+=channels,可以修改為w++,因為是單通道數據,而不是三通道數據
        {
            unsigned int rowR = 0;  //存儲r分量的數據
            int * gaussKernPtr = gaussKern;//將高斯系數賦值給gaussKernPtr
            int whalfsize = w + width - halfsize;
            unsigned int  curPos = rowWidth + w;  //當前位置
            for (unsigned int k = 1; k < winsize;k++) // k += channels修改為k++
            {
                unsigned int  pos = rowWidth + ((k + whalfsize) % width);
                int fkern = *gaussKernPtr++;
                rowR += (pixels[pos] * fkern);  //當前像素值乘以高斯系數,rowR這了泛指單通道的當前像素點高斯處理後的數 
            }

            tmpBuffer[curPos] = ((unsigned char)(rowR >> 8)); //除以256

        }
    }
    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];
            }
            pixelsout[h * width + w] = (unsigned char)(col_all >> 8);
        }
    }
    free(tmpBuffer);
    free(gaussKern);
}

int _tmain(int argc, _TCHAR* argv[])
{

    const char* imagename = "C:\\Users\\Administrator.IES7LSEJAZ1GGRL\\Desktop\\PureGaussian-master\\GaussianBlur\\GaussianBlur\\InputName.bmp";
    //從文件中讀入圖像
    Mat img = imread(imagename);
    Mat dst = imread(imagename);
    Mat gray_img;
    Mat gray_dst;
    cvtColor(img, gray_img, CV_BGR2GRAY);
    cvtColor(dst, gray_dst, CV_BGR2GRAY);
    //如果讀入圖像失敗
    if(img.empty())
    {
        fprintf(stderr, "Can not load image %s\n", imagename);
        return -1;
    }
    LARGE_INTEGER m_nFreq;
    LARGE_INTEGER m_nBeginTime;
    LARGE_INTEGER nEndTime;
    QueryPerformanceFrequency(&m_nFreq); // 獲取時鐘周期
    QueryPerformanceCounter(&m_nBeginTime); // 獲取時鐘計數
      GaussBlur1D(gray_img.data,gray_dst.data,gray_img.cols,gray_img.rows,2);
    QueryPerformanceCounter(&nEndTime);
    cout << (nEndTime.QuadPart-m_nBeginTime.QuadPart)*100/m_nFreq.QuadPart << endl;
    //顯示圖像
    imshow("原圖像",gray_img);
    imshow("模糊圖像", gray_dst);
    //此函數等待按鍵,按鍵盤任意鍵就返回
    waitKey();
    return 0;
}

算法實現效果:sigma=2.0

Copyright © Linux教程網 All Rights Reserved