C语言实现BMP图像处理(读取与保存)

// 数据类型说明:
// WORD:16位无符号短整形,占2个字节
// DWORD:32位无符号短整形,占4个字节
// LONG:有符号32位整形,占4个字节
// RGBQUAD:用于定义调色板数组元素的类型
// LPBITMAPINFOHEADER:位图信息头(BITMAPINFOHEADER)的指针
// LOGPALETTE:定义了一个逻辑调色板
// LPRGBQUAD:指向RGBQUAD结构的指针
// HPALETTE:调色板句柄
// HDC:设备句柄
// HLOCAL:局部内存句柄
// HWND:窗口句柄
// HFILE:文件句柄
// HBITMAP:位图句柄
// HGLOBAL:表示一个内存块句柄,GlobalAlloc分配,GlobalLock读取
// LPSTR:一种字符串数据类型,指向以‘\0’结尾的32位ANSI字符数组指针
// LPCWSTR:一个纸箱unicode编码字符串的32位指针,指向字符串是wchar型,而不是char型

// BITMAPFILEHEADER:位图文件头结构体
// BITMAPINFOHEADER:位图信息头结构体

//************ 关于文件的操作:https://blog.csdn.net/virtualdesk/article/details/4379704 ************
// _lopen:以二进制形式打开指定的文件
// lread: 将文件中的数据读入内存缓冲区
// lwrite:将数据从内存缓冲区写入一个文件
// lcreat:创建一个文件

#include <stdio.h>
#include <Windows.h>

#define WIDTHBYTES(i) ((i+31)/32*4)

BITMAPFILEHEADER bf;
BITMAPINFOHEADER bi;
HBITMAP hBitmap;
HPALETTE hPalette;
HGLOBAL hImgData;
DWORD NumColors;
DWORD LineBytes; // 每行的字节数
int xOffset = 0, yOffset = 0;

BOOL LoadBmpFile(HWND hWnd, char *BmpFileName)
{
	HFILE hf;                     // 文件句柄
	LPBITMAPINFOHEADER lpImgData; // 信息头指针
	LOGPALETTE *pPal;             // 指向调色版的指针
	LPRGBQUAD lpRGB;              // 指向RGBQUAD结构的指针
	HPALETTE hPrePalette;         // 保存设备中调色板
	HDC hDc;                      // 设备句柄
	HLOCAL hPal;                  // 存储调色板的局部内存句柄
	DWORD ImgSize;                // 实际的图像数据占用的字节数
	DWORD i;

	BmpFileName = "G:\c语言图像处理\T102\T102\0.bmp";

	if ((hf = _lopen(BmpFileName, OF_READ)) == HFILE_ERROR)
	{
		MessageBox(hWnd, (LPCWSTR)"File not found", (LPCWSTR)"ERROR Message", MB_OK | MB_ICONEXCLAMATION);
		return FALSE;
	}
	
	_lread(hf, (LPSTR)&bf, sizeof(BITMAPFILEHEADER)); // 将BITMAPFILEHEADER结构从文件中读出,写到bf中
	_lread(hf, (LPSTR)&bi, sizeof(BITMAPINFOHEADER)); // 将BITMAPINFOHEADER结构从文件中读出,写到bf中
	
	LineBytes = (DWORD)GDI_WIDTHBYTES(bi.biWidth*bi.biBitCount); // 每行的字节数
	ImgSize = (DWORD)LineBytes*bi.biHeight;          // 实际的图像数据占用的字节数
	
	if (bi.biClrUsed != 0)                           // 调色板数组中实际的颜色数
		NumColors = (DWORD)bi.biClrUsed;
	else
	{
		switch (bi.biBitCount)
		{
		case 1:
			NumColors = 2;
			break;
		case 4:
			NumColors = 16;
			break;
		case 8:
			NumColors = 256;
			break;
		case 24:
			NumColors = 0;
			break;
		default:
			MessageBox(hWnd, (LPCWSTR)"Invalid Color Numbers", (LPCWSTR)"Error Message", MB_OK | MB_ICONEXCLAMATION);
		_lclose(hf);
		return FALSE;
		}

		if (bf.bfOffBits != (DWORD)(NumColors*sizeof(RGBQUAD)  // 计算出的偏移量与实际的偏移量不符,则颜色数出错
			+sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)))
		{
			MessageBox(hWnd, (LPCWSTR)"Invalid Color Numbers", (LPCWSTR)"Error Message", MB_OK | MB_ICONEXCLAMATION);
			_lclose(hf);
			return FALSE;
		}

		bf.bfSize = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)
			+NumColors*sizeof(RGBQUAD)+ImgSize; // 分配内存,大小为BITMAPINFOHEADER结构长度+调色板+实际位图

		hImgData = GlobalAlloc(GHND, (DWORD)(sizeof(BITMAPINFOHEADER)+NumColors*sizeof(RGBQUAD)+ImgSize));

		if (hImgData == NULL)
		{
			_lclose(hf);
			return FALSE;
		}

		lpImgData = (LPBITMAPINFOHEADER)GlobalLock(hImgData); // lpImgData指向该内存区
		
		_llseek(hf, sizeof(BITMAPFILEHEADER), SEEK_SET); // 文件指针重新定位到LPBITMAPINFOHEADER开始处

		_hread(hf, (char*)lpImgData, 
			(long)sizeof(BITMAPINFOHEADER)+(long)NumColors*sizeof(RGBQUAD)+ImgSize); // 将文件内容读入lpImgData

		_lclose(hf);

		if (NumColors != 0) // 颜色数不为0,说明用到了调色板
		{
			hPal = LocalAlloc(LHND, sizeof(LOGPALETTE)+NumColors*sizeof(PALETTEENTRY)); // 为逻辑调色板分配内存
			pPal = (LOGPALETTE*)LocalLock(hPal);         // 指针pPal指向内存区
			pPal->palNumEntries = NumColors;             // 逻辑调色板结构头
			pPal->palVersion = 0x300;
			lpRGB = (LPRGBQUAD)((LPSTR)lpImgData + (DWORD)sizeof(BITMAPINFOHEADER));   // lpRGB指向调色板开始的位置
			
			for (i = 0; i < NumColors; ++i) // 填写数据
			{
				pPal->palPalEntry[i].peRed = lpRGB->rgbRed;
				pPal->palPalEntry[i].peGreen = lpRGB->rgbGreen;
				pPal->palPalEntry[i].peBlue = lpRGB->rgbBlue;
				pPal->palPalEntry[i].peFlags = (BYTE)0;
				lpRGB++;
			}
			hPalette = CreatePalette(pPal);  // 产生逻辑调色板
			LocalUnlock(hPal);  // 释放局部内存
			LocalFree(hPal);    // 释放局部内存
		}
		hDc = GetDC(hWnd); 		// 获取上下文句柄

		if (hPalette)
		{
			hPrePalette = SelectPalette(hDc, hPalette, FALSE);//将新的逻辑调色板选入 DC,将旧的逻辑调色板句柄保存在//hPrevPalette
			RealizePalette(hDc);
		}

		// 产生位图句柄
		hBitmap = CreateDIBitmap(hDc, (LPBITMAPINFOHEADER)lpImgData, (LONG)CBM_INIT, 
			(LPSTR)lpImgData + sizeof(BITMAPINFOHEADER)+NumColors*sizeof(RGBQUAD), (LPBITMAPINFO)lpImgData, DIB_RGB_COLORS);
		
		// 将原来的调色板(如果有的话)选入设备上下文句柄
		if (hPalette && hPrePalette)
		{
			SelectPalette(hDc, hPrePalette, FALSE);
			RealizePalette(hDc);
		}
		ReleaseDC(hWnd, hDc);    // 释放设备上下文
		GlobalUnlock(hImgData);  // 解锁内存区

		return TRUE;
	}
}

后续持续更新用C语言实现图像处理算法,敬请期待,欢迎关注。

  • 10
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
C语言可以通过以下步骤实现BMP图像添加高斯噪声: 1.首先,需要引入一个随机数生成器函数来生成高斯噪声。可以使用标准C库中的rand()函数来生成一个0到RAND_MAX(通常是32767)之间的随机整数。可以将其归一化为0到1之间的浮点数,并使用均值为0,标准差为sigma的高斯分布函数生成高斯噪声值。 float gaussNoise(float sigma) { float u1, u2, v1, v2, s; do { u1 = rand() / ((float)RAND_MAX); u2 = rand() / ((float)RAND_MAX); v1 = 2 * u1 - 1; v2 = 2 * u2 - 1; s = v1 * v1 + v2 * v2; } while (s >= 1 || s == 0); float mul = sqrt(-2.0 * log(s) / s); return v2 * mul * sigma; } 2.读取BMP图像的像素数据。可以使用图像处理库,如OpenCV来读取BMP图像的像素数据。 unsigned char* imageData; // 存储图像像素数据的指针 int width, height; // 图像的宽度和高度 int channels; // 图像的通道数 // 使用OpenCV读取BMP图像,将像素数据存储在imageData指针中 // 获取图像的宽度、高度和通道数 3.遍历图像的每个像素,并为每个像素添加高斯噪声。 for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { for (int c = 0; c < channels; c++) { float noise = gaussNoise(sigma); // 根据设定的标准差生成高斯噪声 imageData[(i * width + j) * channels + c] += (unsigned char)noise; } } } 4.将处理后的像素数据保存为新的BMP图像。同样可以使用图像处理库来保存处理后的像素数据为BMP图像。 // 使用OpenCV保存像素数据为BMP图像 // 释放imageData的内存 这样,通过以上步骤,利用C语言实现了对BMP图像添加高斯噪声的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值