c/c++图片转换为字符串画_图片转字符串

前言

  本文主要介绍了将BMP图像转换为字符串画的一般过程,包括图像的缩放、灰度化和C++读取处理等步骤。

BMP文件格式简介

  BMP(Bitmap-File)图形文件,几乎所有图像处理软件都支持BMP图像文件格式,是非常见一种图像格式,通常文件体积较大。

BMP位图文件由4个部分组成:位图文件头(bitmap-file header)、位图信息头(bitmap-information header)、彩色表(color table)和定义位图的字节(位图数据,即图像数据,Data Bits 或Data Body)阵列,它具有如下所示的形式。
在这里插入图片描述
在Windows中具体的结构定义,可以包含头文件#include <Windows.h>,可以查看详细信息。
文件头(共计14字节):
typedef struct tagBITMAPFILEHEADER {
WORD bfType; //2字节,标记,通常为BM, 十六进制为0x4D42
DWORD bfSize; //4字节,文件大小
WORD bfReserved1; //2字节,保留
WORD bfReserved2; //2字节,保留
DWORD bfOffBits; //4字节,图像数据在文件中的偏移量
} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;

信息头(共计40字节):
typedef struct tagBITMAPINFOHEADER{
DWORD biSize; //4字节,
LONG biWidth; //4字节,图像宽度,以像素为单位
LONG biHeight; //4字节,图像高度,以像素为单位
WORD biPlanes; //2字节
WORD biBitCount; //2字节,位深, 1、4、8、16、24、32
DWORD biCompression; //4字节,压缩标识
DWORD biSizeImage; //4字节,位图数据的大小,必须是4的倍数
LONG biXPelsPerMeter; //4字节,像素/米表示的水平分辨率
LONG biYPelsPerMeter; //4字节,像素/米表示的垂直分辨率
DWORD biClrUsed; //4字节,位图使用的颜色数
DWORD biClrImportant; //4字节,重要的颜色数
} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;

图像缩放算法

  转为字符画时,图像的宽度太宽时在控制台显示时,会自动换行,就看不出图像的大致样子,所以在显示处理之前先把图像缩小一下,常见的的缩放算法有邻域插值、双线性插值、双三次插值,本文使用邻域插值算法,因为比较简单容易处理。

图像灰度化

  像灰度化是将一幅彩色图像转换为灰度化图像的过程。彩色图像通常包括R、G、B三个分量,分别显示出红绿蓝等各种颜色,灰度化就是使彩色图像的R、G、B三个分量相等的过程。灰度图像中每个像素仅具有一种样本颜色,其灰度是位于黑色与白色之间的多级色彩深度,灰度值大的像素点比较亮,反之比较暗,像素值最大为255(表示白色),像素值最小为0(表示黑色)。
  一种常见的方法是将RGB三个分量求和再取平均值,但更为准确的方法是设置不同的权重,将RGB分量按不同的比例进行灰度划分。比如人类的眼睛感官蓝色的敏感度最低,敏感最高的是绿色,因此将RGB按照0.299、0.587、0.144比例加权平均能得到较合理的灰度图像,公式如下所示。
G r a y = R ∗ 0.299 + G ∗ 0.587 + B ∗ 0.114 Gray = R * 0.299 + G * 0.587 + B * 0.114 Gray=R0.299+G0.587+B0.114

示例代码

#include <iostream>
#include <fstream>
#include <Windows.h>
using namespace std;

//字符表,可以自行调整
string table = "#8XOHLTI)i=+;:,. ";

/*
* data      图像数据
* srcWidth  图像宽度
* srcHeight 图像高度
* ratio     缩放比例
*/
void output(const char *data, int srcWidth, int srcHeight, double ratio)
{
	int width = int(double(srcWidth) * ratio);     //缩放后的宽度
	int height = int(double(srcHeight) * ratio);   //缩放后的高度
	int lineBytes = (srcWidth * 24 + 31) / 32 * 4; //原始图像每行字节数
	int rowSize = (width * 24 + 31) / 32 * 4;      //缩放后每行字节数
	double unit = 257.0 / double(table.size());

	for (int i = height - 1; i >= 0; --i) {
		int x = (int)(double(i) / ratio);//原始行
		for (int j = 0; j < width; ++j) {
			int y = (int)(double(j) / ratio);//原始列
			if (x >= 0 && x < srcHeight && y >= 0 && y < srcHeight) {
				const uint8_t* p = (const uint8_t*)(data + x * lineBytes + y * 3);
				//灰度化
				int gray = (unsigned int)((float)p[2] * 0.299 +
					(float)p[1] * 0.587 +
					(float)p[0] * 0.114);
				//映射到对应的字符
				int idx = int(gray / unit);
				cout << table[idx];
			}
		}
		cout << "\n";
	}
}

int main()
{
	const char* filename = "1.bmp";
	ifstream file(filename, ios::binary);
	if (!file.is_open()) {
		return 0;
	}
	BITMAPFILEHEADER header = { 0 };
	BITMAPINFOHEADER info = { 0 };
	file.read((char*)&header, sizeof(header));
	file.read((char*)&info, sizeof(info));
	if (header.bfType != 0x4D42 || info.biBitCount != 24) {
		cout << "不支持" << endl;
		return 0;
	}

	char* buffer = new char[info.biSizeImage];
	file.read(buffer, info.biSizeImage);
	output(buffer, info.biWidth, info.biHeight, 0.4);
	delete[] buffer;
	return 0;
}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

五轮车

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值