0xAA55 发表于 2015-9-6 09:20:42

【图像】简单的高斯模糊实例

原理很简单,就是把一个图像横着模糊一下,然后把这个横向模糊过的图像再纵向模糊一下,就是高斯模糊了。
#include<Windows.h>
#include<stdlib.h>

#define 模糊程度 32

typedef struct
{
        HINSTANCE hInst;

        HWND hWnd;
        HDC hWindowDC;

        //原图
        HDC hImgDC;
        HBITMAP hImgBmp;
       
        //原图信息
        BITMAP ImgBmp;
        LONG BmpWidth;
        LONG BmpHeight;

        //横向模糊过的图
        HDC hDrawPad1DC;
        HBITMAP hDrawPad1Bmp;
        void*pDrawPad1Bits;

        //最终图
        HDC hFinalDrawPadDC;
        HBITMAP hFinalDrawPadBmp;
        void*pFinalDrawPadBits;
}GaussianDemo_t,*GaussianDemo_p;


//============================================================================
//函数:ShowLastError
//描述:弹出对话框显示GetLastError的文本信息
//----------------------------------------------------------------------------
void ShowLastError(HWND hWnd)
{
        LPVOID lpMsgBuf;
        FormatMessage
        (
                FORMAT_MESSAGE_ALLOCATE_BUFFER | //返回一个已分配的内存
                FORMAT_MESSAGE_FROM_SYSTEM |//系统消息
                FORMAT_MESSAGE_IGNORE_INSERTS, //无视插入信息
                NULL,
                GetLastError(),
                0, //默认语言
                (LPTSTR)&lpMsgBuf, //错误信息指针
                0,
                NULL
        );
        MessageBox(hWnd,(LPCTSTR)lpMsgBuf,NULL,MB_OK|MB_ICONINFORMATION);
        LocalFree(lpMsgBuf);//释放内存
}

//============================================================================
//函数:Create24BitDIBBmp
//描述:在内存中生成一个空的24位位图,用作“画板”
//----------------------------------------------------------------------------
HBITMAP Create24BitDIBBmp(HDC hDC,UINT Width,UINT Height,void**ppBits)
{
        BITMAPINFOHEADER BMIF={sizeof(BITMAPINFOHEADER),Width,Height,1,24,0,0,0,0,0,0};
        return CreateDIBSection(hDC,(LPBITMAPINFO)&BMIF,DIB_PAL_COLORS,ppBits,
                NULL,0);
}


//============================================================================
//函数:DrawGaussianBlur
//描述:生成高斯模糊图
//----------------------------------------------------------------------------
void DrawGaussianBlur(GaussianDemo_p pData,LONG BlurSize)
{
        LONG x,y;
        BLENDFUNCTION bf;
        LONG BlurOffset=BlurSize;

        bf.BlendOp=AC_SRC_OVER;
        bf.BlendFlags=0;
        bf.AlphaFormat=0;

        BlurSize*=2;

        //第一步:将图像横着模糊一遍,然后存入第一个画板
        for(x=0;x<BlurSize;x++)
        {
                bf.SourceConstantAlpha=(BYTE)(255/(x+1));
                AlphaBlend(pData->hDrawPad1DC,x-BlurOffset,0,pData->BmpWidth,pData->BmpHeight,
                        pData->hImgDC,0,0,pData->BmpWidth,pData->BmpHeight,bf);
        }

        //第二步:将画板中横着模糊的图片再纵向模糊一下,然后存入最终画板
        for(y=0;y<BlurSize;y++)
        {
                bf.SourceConstantAlpha=(BYTE)(255/(y+1));
                AlphaBlend(pData->hFinalDrawPadDC,0,y-BlurOffset,pData->BmpWidth,pData->BmpHeight,
                        pData->hDrawPad1DC,0,0,pData->BmpWidth,pData->BmpHeight,bf);
        }
}

//============================================================================
//函数:DeleteDrawPad
//描述:删除画板
//----------------------------------------------------------------------------
void DeleteDrawPad(GaussianDemo_p pData)
{
        if(pData->hImgBmp)DeleteObject(pData->hImgBmp);
        pData->hImgBmp=NULL;
        if(pData->hDrawPad1Bmp)DeleteObject(pData->hDrawPad1Bmp);
        pData->hDrawPad1Bmp=NULL;
        if(pData->hFinalDrawPadBmp)DeleteObject(pData->hFinalDrawPadBmp);
        pData->hFinalDrawPadBmp=NULL;
        if(pData->hImgDC)DeleteDC(pData->hImgDC);
        pData->hImgDC=NULL;
        if(pData->hDrawPad1DC)DeleteDC(pData->hDrawPad1DC);
        pData->hDrawPad1DC=NULL;
        if(pData->hFinalDrawPadDC)DeleteDC(pData->hFinalDrawPadDC);
        pData->hFinalDrawPadDC=NULL;
}

//============================================================================
//函数:SetupDrawPad
//描述:设置画板,用于绘制高斯模糊图
//----------------------------------------------------------------------------
BOOL SetupDrawPad(GaussianDemo_p pData)
{
        HWND hWnd=pData->hWnd;

        //分析位图
        GetObject(pData->hImgBmp,sizeof(pData->ImgBmp),&(pData->ImgBmp));

        //取得尺寸
        pData->BmpWidth=pData->ImgBmp.bmWidth;
        if(pData->ImgBmp.bmHeight<0)
                pData->BmpHeight=-pData->ImgBmp.bmHeight;
        else
                pData->BmpHeight=pData->ImgBmp.bmHeight;
        SelectObject(pData->hImgDC,pData->hImgBmp);

        //创建第一个画板
        if(pData->hDrawPad1Bmp)DeleteObject(pData->hDrawPad1Bmp);
        pData->hDrawPad1Bmp=Create24BitDIBBmp(pData->hDrawPad1DC,
                pData->BmpWidth,pData->BmpHeight,&(pData->pDrawPad1Bits));
        if(!pData->hDrawPad1Bmp)
        {
                ShowLastError(hWnd);
                DeleteDrawPad(pData);
                return FALSE;
        }
        SelectObject(pData->hDrawPad1DC,pData->hDrawPad1Bmp);//组装

        //创建第二个画板
        if(pData->hFinalDrawPadBmp)DeleteObject(pData->hFinalDrawPadBmp);
        pData->hFinalDrawPadBmp=Create24BitDIBBmp(pData->hFinalDrawPadDC,
                pData->BmpWidth,pData->BmpHeight,&(pData->pFinalDrawPadBits));
        if(!pData->hFinalDrawPadBmp)
        {
                ShowLastError(hWnd);
                DeleteDrawPad(pData);
                return FALSE;
        }
        SelectObject(pData->hFinalDrawPadDC,pData->hFinalDrawPadBmp);
        return TRUE;
}

//============================================================================
//函数:LoadPictureFileA
//描述:加载一个图像文件,并生成高斯模糊图
//----------------------------------------------------------------------------
BOOL LoadPictureFileA(CHAR*szFileName,GaussianDemo_p pData)
{
        HWND hWnd=pData->hWnd;

        //加载文件
        if(pData->hImgBmp)DeleteObject(pData->hImgBmp);
        pData->hImgBmp=(HBITMAP)LoadImageA(NULL,szFileName,IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
        if(!pData->hImgBmp)
        {
                if(!GetLastError())
                        MessageBox(hWnd,TEXT("不是bmp文件。"),NULL,MB_OK|MB_ICONINFORMATION);
                else
                        ShowLastError(hWnd);
                DeleteDrawPad(pData);
                return FALSE;
        }

        //设置好画板就进行模糊处理
        SetupDrawPad(pData);
        DrawGaussianBlur(pData,模糊程度);
        return TRUE;
}
BOOL LoadPictureFileW(WCHAR*szFileName,GaussianDemo_p pData)
{
        HWND hWnd=pData->hWnd;

        //加载文件
        if(pData->hImgBmp)DeleteObject(pData->hImgBmp);
        pData->hImgBmp=(HBITMAP)LoadImageW(NULL,szFileName,IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
        if(!pData->hImgBmp)
        {
                if(!GetLastError())
                        MessageBox(hWnd,TEXT("不是bmp文件。"),NULL,MB_OK|MB_ICONINFORMATION);
                else
                        ShowLastError(hWnd);
                DestroyWindow(hWnd);
                DeleteDrawPad(pData);
                return FALSE;
        }

        //设置好画板就进行模糊处理
        SetupDrawPad(pData);
        DrawGaussianBlur(pData,模糊程度);
        return TRUE;
}
#ifdef UNICODE
#define LoadPictureFile LoadPictureFileW
#else
#define LoadPictureFile LoadPictureFileA
#endif

LRESULT CALLBACK WndProc(HWND hWnd,UINT Msg,WPARAM wp,LPARAM lp)
{
        GaussianDemo_p pUserData;
        switch(Msg)
        {
        case WM_CREATE:
                //创建窗口的时候设置窗口的属性和附加的内容

                //接收文件拖放
                DragAcceptFiles(hWnd,TRUE);

                //附加内容
                pUserData=(GaussianDemo_p)malloc(sizeof(GaussianDemo_t));
                if(!pUserData)
                        return -1;

                //填写附加内容
                memset(pUserData,0,sizeof(GaussianDemo_t));
                pUserData->hInst=GetModuleHandle(NULL);
                pUserData->hWnd=hWnd;
                pUserData->hImgDC=CreateCompatibleDC(pUserData->hWindowDC=GetWindowDC(hWnd));
                pUserData->hDrawPad1DC=CreateCompatibleDC(pUserData->hWindowDC);
                pUserData->hFinalDrawPadDC=CreateCompatibleDC(pUserData->hWindowDC);

                //设置附加内容
                SetWindowLongPtr(hWnd,GWLP_USERDATA,(LONG_PTR)pUserData);

                if(__argc>1)
                        LoadPictureFileA(__argv,pUserData);
                break;
        case WM_DROPFILES:
                {
                        TCHAR szFile;
                        RECT rc;

                        //取得窗口附加信息
                        pUserData=(GaussianDemo_p)GetWindowLongPtr(hWnd,GWLP_USERDATA);

                        //取得拖拽入的文件名
                        DragQueryFile((HDROP)wp,0,szFile,MAX_PATH);

                        LoadPictureFile(szFile,pUserData);

                        GetClientRect(hWnd,&rc);
                        InvalidateRect(hWnd,&rc,TRUE);
                }
                break;
        case WM_PAINT:
                {
                        HDC hPaintDC;
                        RECT rc;
                        PAINTSTRUCT ps;

                        GetClientRect(hWnd,&rc);

                        //取得窗口附加信息
                        pUserData=(GaussianDemo_p)GetWindowLongPtr(hWnd,GWLP_USERDATA);

                        hPaintDC=BeginPaint(hWnd,&ps);
                        BitBlt(hPaintDC,0,0,rc.right-rc.left,rc.bottom-rc.top,pUserData->hFinalDrawPadDC,0,0,SRCCOPY);
                        EndPaint(hWnd,&ps);
                }
                break;
        case WM_DESTROY:
                pUserData=(GaussianDemo_p)GetWindowLongPtr(hWnd,GWLP_USERDATA);
                DeleteDrawPad(pUserData);
                free(pUserData);
                SetWindowLongPtr(hWnd,GWLP_USERDATA,(LONG_PTR)NULL);
                PostQuitMessage(0);
                break;
        default:
                return DefWindowProc(hWnd,Msg,wp,lp);
        }
        return 0;
}

void CreateInst(HINSTANCE hInst,int ShowCmd)
{
        WNDCLASSEX WCEx={sizeof(WNDCLASSEX),0,WndProc,0,0,hInst,LoadIcon(NULL,MAKEINTRESOURCE(IDI_APPLICATION)),LoadCursor(NULL,MAKEINTRESOURCE(IDC_ARROW)),(HBRUSH)COLOR_BTNFACE,NULL,TEXT("tuttb"),NULL};//窗口类
    HWND hWnd=CreateWindowEx(0,MAKEINTATOM(RegisterClassEx(&WCEx)),TEXT("请将文件拖拽进来"),WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT,CW_USEDEFAULT,400,300,NULL,NULL,hInst,NULL);//窗口句柄
    ShowWindow(hWnd,ShowCmd);
    UpdateWindow(hWnd);
}

int APIENTRY WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR szCmd,int ShowCmd)
{
    MSG msg;
        CreateInst(hInst,ShowCmd);
    while(GetMessage(&msg,NULL,0,0))//消息循环
    {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }
    return msg.wParam;
}
SRC:
BIN:

FFFFFFFE 发表于 2015-9-6 15:55:20

这个用于什么啊?打马赛克?

0xAA55 发表于 2015-9-7 01:36:31

FFFFFFFE 发表于 2015-9-6 15:55
这个用于什么啊?打马赛克?

嗯。

Avalon 发表于 2015-9-7 02:13:37

→_→3Q 原来你是这种癖好

__star__ 发表于 2015-9-11 13:19:19

为什么是这张图。。。

0xAA55 发表于 2015-9-11 20:49:26

__star__ 发表于 2015-9-11 13:19
为什么是这张图。。。

为什么不能是这张图?

账号已注销 发表于 2016-1-7 14:41:28

我想知道如何用DirectX来处理高斯模糊。另外。实现高斯模糊还有种更简单的方法,使用GDI+的Effect类。

0xAA55 发表于 2016-1-7 14:46:05

Kiss丿Huryo 发表于 2016-1-7 14:41
我想知道如何用DirectX来处理高斯模糊。另外。实现高斯模糊还有种更简单的方法,使用GDI+的Effect类。 ...

GDI+没有显卡加速,效率不高。我这个虽然用的是GDI,但是它是有显卡性能加成的。
DX的话,渲染方式也一样。重复绘制,每层透明度值减少。

账号已注销 发表于 2016-1-7 14:51:30

0xAA55 发表于 2016-1-7 14:46
GDI+没有显卡加速,效率不高。我这个虽然用的是GDI,但是它是有显卡性能加成的。
DX的话,渲染方式也一样 ...

GDI+确实有点慢。用它处理一张700x700的图片 Round为20的图片竟然要400ms。。也可能是我电脑不好吧。。=_=

0xAA55 发表于 2016-1-7 15:16:40

Kiss丿Huryo 发表于 2016-1-7 14:51
GDI+确实有点慢。用它处理一张700x700的图片 Round为20的图片竟然要400ms。。也可能是我电脑不好吧。。=_ ...

GDI+没有显卡性能加成,它都是靠的CPU处理。再快的电脑,用GDI+处理图片还是慢。

勇芳软件 发表于 2019-5-7 22:17:38

丫丫的,废话代码全部贴出来了,什么加载文件,什么DC位图的,谁不知道啊,一句一语的都有。
这核心代码就:
bf.SourceConstantAlpha=(BYTE)(255/(x+1));    变模糊,代码在哪里:@
我来来看模糊算法的,结果就给我这个:funk:
页: [1]
查看完整版本: 【图像】简单的高斯模糊实例