目的:通过构建bitmap header将图像unsigned char*纯数据 数组图像保存为位图

目的:通过构建bitmap header将图像unsigned char*纯数据数组图像保存为位图

环境:

系统:Win10 x64
环境:win10/centos 7.5
    	vs2017/gcc

问题分析:

有朋友在c环境下,使用cv::Mat.data保存了图片中的纯unsigned char*数据。然后需要在另外的环境使用这部分数据还原出图片来。在不使用任何三方库的情况下,最简单的做法莫过于使用自己构建的bmp header来生成bitmap位图。

参考博客连接:
bitmap构建header保存
https://blog.csdn.net/xiajun07061225/article/details/6633938

图像X轴翻转
https://blog.csdn.net/tounaobun/article/details/17377777?utm_medium=distribute.pc_relevant_download.none-task-blog-BlogCommendFromBaidu-3.nonecase&depth_1-utm_source=distribute.pc_relevant_download.none-task-blog-BlogCommendFromBaidu-3.nonecas

RGB转BGR
https://bbs.csdn.net/topics/392366646

解决方案:

直接上代码,代码较随意,看构建过程即可

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>

//BMP文件头(14字节)
typedef struct                       /**** BMP file header structure ****/
{
	unsigned int   bfSize;           /* Size of file */
	unsigned short bfReserved1;      /* Reserved */
	unsigned short bfReserved2;      /* ... */
	unsigned int   bfOffBits;        /* Offset to bitmap data */
} MyBITMAPFILEHEADER;

//位图信息头(40字节)
typedef struct                       /**** BMP file info structure ****/
{
	unsigned int   biSize;           /* Size of info header */
	int            biWidth;          /* Width of image */
	int            biHeight;         /* Height of image */
	unsigned short biPlanes;         /* Number of color planes */
	unsigned short biBitCount;       /* Number of bits per pixel */
	unsigned int   biCompression;    /* Type of compression to use */
	unsigned int   biSizeImage;      /* Size of image data */
	int            biXPelsPerMeter;  /* X pixels per meter */
	int            biYPelsPerMeter;  /* Y pixels per meter */
	unsigned int   biClrUsed;        /* Number of colors used */
	unsigned int   biClrImportant;   /* Number of important colors */
} MyBITMAPINFOHEADER;

// 保存为bmp文件
void MySaveBmp(const char *filename, unsigned char *rgbbuf, int width, int height)
{
	MyBITMAPFILEHEADER bfh;
	MyBITMAPINFOHEADER bih;
	/* Magic number for file. It does not fit in the header structure due to alignment requirements, so put it outside */
	unsigned short bfType = 0x4d42;
	bfh.bfReserved1 = 0;
	bfh.bfReserved2 = 0;
	bfh.bfSize = 2 + sizeof(MyBITMAPFILEHEADER) + sizeof(MyBITMAPINFOHEADER) + width * height * 2;
	bfh.bfOffBits = 0x36;

	bih.biSize = sizeof(MyBITMAPINFOHEADER);
	bih.biWidth = width;
	bih.biHeight = height;
	bih.biPlanes = 1;
	bih.biBitCount = 24;
	bih.biCompression = 0;
	bih.biSizeImage = 0;
	bih.biXPelsPerMeter = 5000;
	bih.biYPelsPerMeter = 5000;
	bih.biClrUsed = 0;
	bih.biClrImportant = 0;

	printf("filename=%s \n", filename);
	FILE *file = fopen(filename, "wb");
	if (!file)
	{
		printf("Could not write file\n");
		return;
	}

	/*Write headers*/
	fwrite(&bfType, sizeof(bfType), 1, file);
	fwrite(&bfh, sizeof(bfh), 1, file);
	fwrite(&bih, sizeof(bih), 1, file);

	fwrite(rgbbuf, width*height * 3, 1, file);
	fclose(file);
}

// rgb格式转rgr
int RGB2BGR(unsigned char *pImageDst, unsigned char *pImageSrc, int nWidth, int nHeight, int nBitCount)
{
	unsigned char *pImageDataTmp = pImageSrc;
	int nWidthNum = (nWidth * nBitCount + 31) / 32 * 4;
	for (int i = 0; i < nHeight; i++)
	{
		for (int j = 0; j < nWidthNum; j += 3)
		{
			*pImageDst = *(pImageDataTmp + 2);
			*(pImageDst + 1) = *(pImageDataTmp + 1);
			*(pImageDst + 2) = *pImageDataTmp;
			pImageDst += 3;
			pImageDataTmp += 3;
		}
	}

	return 0;
}

// 图像沿X轴旋转
void bmpXFlip(unsigned char* srcData, unsigned char* dstData, int nWidth, int nHeight, int nBitCount){
	int lineSize = (nWidth * nBitCount + 31) / 32 * 4;

	for (int i = 0; i < nHeight; i++) {
		for (int j = 0; j < lineSize; j++) {
			dstData[i * lineSize + j] = srcData[lineSize * (nHeight - 1 - i) + j];
		}
	}
}

// 涂抹图像,通过将按比例区域的像素点值清除达到效果
void smearImg(unsigned char* srcData, int nWidth, int nHeight, int nBitCount) {
	int lineSize = (480 * 24 + 31) / 32 * 4;
	for (int i = 0; i < 480; i++) {
		for (int j = 0; j < lineSize; j++) {
			if (j < lineSize * 2 / 3 && j > lineSize / 3 && i < 240 && i > 160) {
				srcData[i * lineSize + j] = 10;
			}
		}
	}
}

int main()
{
	FILE *inFile = fopen("./01.img", "rb");
	if (!inFile)
	{
		printf("Could not read file\n");
		return 0;
	}

	unsigned int current_read_position = ftell(inFile);

	int file_size;
	fseek(inFile, 0, SEEK_END);
	file_size = ftell(inFile);

	fseek(inFile, current_read_position, SEEK_SET);
	printf("uchar file size: %d\n", file_size);

	int bufferSize = 480 * 480 * 2 * 2;
	unsigned char* imgBuffer = (unsigned char*)malloc(bufferSize);
	fread(imgBuffer, bufferSize, 1, inFile);
	fclose(inFile);

	//rgb转bgr
	unsigned char* imgBgr = (unsigned char*)malloc(bufferSize);
	RGB2BGR(imgBgr, imgBuffer, 480, 480, 24);

	// 水平X轴翻转
	memset(imgBuffer, 0, bufferSize);
	bmpXFlip(imgBgr, imgBuffer, 480, 480, 24);

	MySaveBmp("./out.bmp", imgBuffer, 480, 480);

	free(imgBgr);
	free(imgBuffer);

	return 0;
}

PS:
1. 文中使用的01.img文件链接
https://download.csdn.net/download/Alger_magic/12518712

2. 从朋友出获取到一个信息:图像沿X轴翻转还有一个简便的做法,就是在构建位图时将MyBITMAPINFOHEADER结构中的biHeight赋值为负数,比如原数据高为480,那么这里赋值为-480.则生成的图像就是已经做过X轴翻转的,就不需要额外调用bmpXFlip()。

补充几点遇到的问题
1. unsigned short bfType = 0x4d42; 位图类型,必须写入位图文件的最前面,然后才是bmp文件头,位图信息头。
2. 由于原cv::Mat中选用的是RGB类型,所以在代码中添加了RGB转BGR的函数,如果原Mat直接加载的是BGR,则不需要转换。
3. 由于直接保存的unsigned char*数据写入位图以后发现,位图图片是沿X轴翻转过的倒立图片。目前不清楚原因,猜测可能跟cv::Mat存储图片信息的方式有关系。所以在代码中添加了沿X轴翻转的照片。
4. 由于原图包含人脸,所以使用了一个涂抹函数将人脸的部分进行了黑涂抹。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值