技术宅的结界

 找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 2910|回复: 10
收起左侧

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

[复制链接]

1059

主题

2433

帖子

6万

积分

用户组: 管理员

一只技术宅

UID
1
精华
221
威望
348 点
宅币
19479 个
贡献
40233 次
宅之契约
0 份
在线时间
1837 小时
注册时间
2014-1-26
发表于 2015-9-6 09:20:42 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有帐号?立即注册→加入我们

x
原理很简单,就是把一个图像横着模糊一下,然后把这个横向模糊过的图像再纵向模糊一下,就是高斯模糊了。
[C] 纯文本查看 复制代码
#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[1],pUserData);
		break;
	case WM_DROPFILES:
		{
			TCHAR szFile[MAX_PATH];
			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;
}
20150906091611.png
SRC: 简单高斯模糊.7z (234.7 KB, 下载次数: 22)
回复

使用道具 举报

5

主题

48

帖子

197

积分

用户组: 小·技术宅

UID
167
精华
0
威望
3 点
宅币
132 个
贡献
11 次
宅之契约
0 份
在线时间
30 小时
注册时间
2014-3-30
发表于 2015-9-6 15:55:20 | 显示全部楼层
这个用于什么啊?打马赛克?

1059

主题

2433

帖子

6万

积分

用户组: 管理员

一只技术宅

UID
1
精华
221
威望
348 点
宅币
19479 个
贡献
40233 次
宅之契约
0 份
在线时间
1837 小时
注册时间
2014-1-26
 楼主| 发表于 2015-9-7 01:36:31 | 显示全部楼层
FFFFFFFE 发表于 2015-9-6 15:55
这个用于什么啊?打马赛克?

嗯。

1

主题

9

帖子

5119

积分

用户组: 技术宅的结界VIP成员

UID
682
精华
0
威望
1 点
宅币
5107 个
贡献
1 次
宅之契约
0 份
在线时间
12 小时
注册时间
2015-2-15
发表于 2015-9-7 02:13:37 来自手机 | 显示全部楼层
→_→3Q 原来你是这种癖好

3

主题

40

帖子

145

积分

用户组: 小·技术宅

UID
257
精华
0
威望
1 点
宅币
103 个
贡献
0 次
宅之契约
0 份
在线时间
8 小时
注册时间
2014-5-6
发表于 2015-9-11 13:19:19 | 显示全部楼层
为什么是这张图。。。

1059

主题

2433

帖子

6万

积分

用户组: 管理员

一只技术宅

UID
1
精华
221
威望
348 点
宅币
19479 个
贡献
40233 次
宅之契约
0 份
在线时间
1837 小时
注册时间
2014-1-26
 楼主| 发表于 2015-9-11 20:49:26 | 显示全部楼层
__star__ 发表于 2015-9-11 13:19
为什么是这张图。。。

为什么不能是这张图?

13

主题

76

帖子

1292

积分

用户组: 上·技术宅

UID
888
精华
0
威望
0 点
宅币
302 个
贡献
914 次
宅之契约
0 份
在线时间
36 小时
注册时间
2015-5-31
发表于 2016-1-7 14:41:28 | 显示全部楼层
我想知道如何用DirectX来处理高斯模糊。另外。实现高斯模糊还有种更简单的方法,使用GDI+的Effect类。

1059

主题

2433

帖子

6万

积分

用户组: 管理员

一只技术宅

UID
1
精华
221
威望
348 点
宅币
19479 个
贡献
40233 次
宅之契约
0 份
在线时间
1837 小时
注册时间
2014-1-26
 楼主| 发表于 2016-1-7 14:46:05 | 显示全部楼层
Kiss丿Huryo 发表于 2016-1-7 14:41
我想知道如何用DirectX来处理高斯模糊。另外。实现高斯模糊还有种更简单的方法,使用GDI+的Effect类。 ...

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

13

主题

76

帖子

1292

积分

用户组: 上·技术宅

UID
888
精华
0
威望
0 点
宅币
302 个
贡献
914 次
宅之契约
0 份
在线时间
36 小时
注册时间
2015-5-31
发表于 2016-1-7 14:51:30 | 显示全部楼层
0xAA55 发表于 2016-1-7 14:46
GDI+没有显卡加速,效率不高。我这个虽然用的是GDI,但是它是有显卡性能加成的。
DX的话,渲染方式也一样 ...

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

1059

主题

2433

帖子

6万

积分

用户组: 管理员

一只技术宅

UID
1
精华
221
威望
348 点
宅币
19479 个
贡献
40233 次
宅之契约
0 份
在线时间
1837 小时
注册时间
2014-1-26
 楼主| 发表于 2016-1-7 15:16:40 | 显示全部楼层
Kiss丿Huryo 发表于 2016-1-7 14:51
GDI+确实有点慢。用它处理一张700x700的图片 Round为20的图片竟然要400ms。。也可能是我电脑不好吧。。=_ ...


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

51

主题

80

帖子

642

积分

用户组: 大·技术宅

UID
3260
精华
7
威望
12 点
宅币
502 个
贡献
1 次
宅之契约
0 份
在线时间
22 小时
注册时间
2017-12-26
发表于 2019-5-7 22:17:38 | 显示全部楼层
丫丫的,废话代码全部贴出来了,什么加载文件,什么DC位图的,谁不知道啊,一句一语的都有。
这核心代码就:
bf.SourceConstantAlpha=(BYTE)(255/(x+1));    变模糊,代码在哪里
我来来看模糊算法的,结果就给我这个

本版积分规则

QQ|申请友链||Archiver|手机版|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图  

GMT+8, 2020-7-5 22:45 , Processed in 0.120406 second(s), 36 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表