项目需要将Mat图像转换为bmp图像(1位图)参考了一个大神的写法,发现不能正常运行,稍微做了修改。
参考地址:把opencv Mat 按位存成bmp二值图像 (1bit 1pixel)_suifeng50的专栏-CSDN博客
#include <cstring>
#include <cstdio>
#include<iostream>
#include <fstream>
#include <windows.h>
#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;
//将mat数组转换为二进制,255用1表示,0用0表示
int mat2Binary(const cv::Mat img, int line_byte, char* data)
{
int width = img.cols;
int height = img.rows;
size_t line_size = line_byte * 8;
size_t bit_size = line_size * height;
char* p = data; int offset, v; unsigned char temp;
for (int row = height - 1; row >= 0; row--)
{
for (int col = 0; col < width; col++)
{
offset = col % 8;
//v = img.data[row * width + col];
v = img.at<uchar>(row, col);
temp = 1;
temp = temp << (8 - offset - 1);
if (v == 255)
{
*(p + col / 8) |= temp;
}
else
{
temp = ~temp;
*(p + col / 8) &= temp;
}
}
//注释掉一下代码,列数否则不能被4整除的图像最后4列会出现黑边
/* for (int j = width / 8; j < line_byte + 1; j++) {
p[j] = 0;
} */
p = p + line_byte;
}
return 0;
}
//将Mat图像保存为1位bmp图
int save1BitImage(const cv::Mat img, std::string dst)
{
int width = img.cols;
int height = img.rows;
const int biBitCount = 1;
//待存储图像数据每行字节数为4的倍数,计算位图每行占多少个字节
//int line_byte = (width * biBitCount >> 3 + 3) / 4 * 4;
int line_byte = (width * biBitCount / 8 + 5) / 4 * 4;//+3改为+5,否则无法向上对齐,造成崩溃
char* p_data = (char*)malloc(line_byte * height + 1);//后面加1否则会报heap错误
//memset(p_data, 0x01, line_byte * height+1);
//将mat数组转换为二进制,255用1表示,0用0表示
mat2Binary(img, line_byte, p_data);
//bmp位图颜色表大小,以字节为单位,灰度图像颜色表为256*4字节,彩色图像颜色表大小为0,二值图为2*4
int color_type_num = 2;
int colorTablesize = color_type_num * sizeof(RGBQUAD);
RGBQUAD* pColorTable = new RGBQUAD[color_type_num];
for (int i = 0; i < color_type_num; i++) {
pColorTable[i].rgbBlue = i * 255;
pColorTable[i].rgbRed = i * 255;
pColorTable[i].rgbGreen = i * 255;
pColorTable[i].rgbReserved = 0;
}
//申请位图文件头结构变量,填写文件头信息
BITMAPFILEHEADER fileHead;
fileHead.bfType = 0x4D42; //bmp类型
fileHead.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + colorTablesize + line_byte * height; //bfSize是图像文件4个组成部分之和,图文件的大小,以字节为单位
fileHead.bfReserved1 = 0;//位图文件保留字,必须为0
fileHead.bfReserved2 = 0;
fileHead.bfOffBits = 54 + colorTablesize; //bfOffBits是图像文件前3个部分所需空间之和,位图数据的起始位置
//申请位图信息头结构变量,填写信息头信息
BITMAPINFOHEADER head;
head.biBitCount = biBitCount;//每个像素所需的位数,必须是1(双色),(29-30字节)4(16色),8(256色)16(高彩色)或24(真彩色)之一
head.biCompression = BI_RGB; 位图压缩类型,必须为BI_RGB否则图片打开会有错误
head.biHeight = height;//位图的高度,以像素为单位
head.biWidth = width;
//head.biSize = 40;
head.biSize = sizeof(BITMAPINFOHEADER);//本结构所占用字节数
head.biSizeImage = line_byte * height;//位图的大小(其中包含了为了补齐行数是4的倍数而添加的空字节)
head.biPlanes = 1;//目标设备的级别,必须为1
head.biXPelsPerMeter = 23622;//位图水平分辨率,每米像素数,分辨率设为600
head.biYPelsPerMeter = 23622;//位图垂直分辨率,每米像素数
head.biClrImportant = 0;//位图显示过程中重要的颜色数
head.biClrUsed = 0;//位图实际使用的颜色表中的颜色数
std::ofstream fp(dst.c_str(), std::ios::binary | std::ios::out);
if (!fp.is_open()) {
return -1;
}
fp.write((char*)&fileHead, sizeof(BITMAPFILEHEADER)); //写文件头进文件
//写位图信息头进内存
fp.write((char*)&head, sizeof(BITMAPINFOHEADER));
//颜色表,写入文件
fp.write((char*)pColorTable, sizeof(RGBQUAD) * color_type_num);
//写位图数据进文件pBmpBuf
fp.write((char*)p_data, height * line_byte);
fp.close();
delete[]pColorTable;
delete[]p_data;
return 0;
}
int main()
{
Mat src = imread("D://1750343960224282.png");//加载图像
string dst = "D://1750343960224282_binc.bmp";//存放生成1位位图的路径
cvtColor(src, src, COLOR_BGR2GRAY); //转为灰度图
save1BitImage(src, dst);
Mat src2 = imread("D://1750343960224282_binc.bmp");//加载图像
return 0;
}