c++读取8位和24位BMP位图数据 俺的作业

家人萌 我因为这个作业爆炸了好多天...所以我想发一下

菜鸡一个 别骂别骂 欢迎指正

 关于这个作业要先了解一下这些登西...

1)BMP 位图的结构

1、BMP文件头(14字节) ,文件的第0字节到第13字节为BMP图像的文件头。BMP文件头数据结构含有BMP文件的类型、文件大小和位图起始位置等信息。

typedef struct tagBITMAPFILEHEADER

         {

             WORD bfType; // 位图文件的类型,必须为BM(0-1字节)

             DWORD bfSize; // 整个位图文件的大小,以字节为单位(2-5字节)

             WORD bfReserved1; // 位图文件保留字,必须为0(6-7字节)

             WORD bfReserved2; // 位图文件保留字,必须为0(8-9字节)

             DWORD bfOffBits; // 位图数据的起始位置,以相对于位图(10-13字节) 

         }

2、位图信息头(40字节),文件的第14个字节到第53个字节为BMP图像的信息头,位图信息头数据用于说明位图的尺寸等信息。在这部分读取位图的长和宽

 typedef struct tagBITMAPINFOHEADER {

         DWORD biSize; // 本结构所占用字节数(14-17字节)

         LONG biWidth; // 位图的宽度,以像素为单位(18-21字节)

         LONG biHeight; // 位图的高度,以像素为单位(22-25字节)

         WORD biPlanes; // 目标设备的级别,必须为1(26-27字节)

         WORD biBitCount;// 每个像素所需的位数,必须是1(双色), 4(16色),8(256色)或24(真彩色)之一(28-29字节)

         DWORD biCompression; // 位图压缩类型,必须是 0(不压缩), 1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一(30-33字节)

         DWORD biSizeImage; // 位图数据部分的大小,以字节为单位(34-37字节)

         LONG biXPelsPerMeter; // 位图水平分辨率,每米像素数(38-41字节)

         LONG biYPelsPerMeter; // 位图垂直分辨率,每米像素数(42-45字节)

         DWORD biClrUsed;// 位图实际使用的颜色表中的颜色数(46-49字节)

         DWORD biClrImportant;// 位图显示过程中重要的颜色数(50-53字节)

    }

3.调色板

调色板用于说明位图中的颜色,它有若干个表项,每一个表项是一个RGBQUAD类型的结构,定义一种颜色。RGBQUAD结构的定义如下:

typedef struct tagRGBQUAD {

         BYTE rgbBlue;    // 蓝色的亮度(值范围为0-255)

         BYTE rgbGreen;   // 绿色的亮度(值范围为0-255)

         BYTE rgbRed;     // 红色的亮度(值范围为0-255)

         BYTE rgbReserved;// 保留,必须为0

    }

调色板中RGBQUAD结构数据的个由biBitCount来确定: 

当biBitCount=1,4,8时,分别有2,16,256个表项;  2的n次方吼

当biBitCount=24时,该BMP图像就是24Bit真彩图,没有调色板项

还有!!!每个表项为4个字节

4、位图数据

位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。

位图的一个像素值所占的字节数由biBitCount来确定:

当biBitCount=1时,8个像素占1个字节; 

当biBitCount=4时,2个像素占1个字节; 

当biBitCount=8时,1个像素占1个字节; 

当biBitCount=24时,1个像素占3个字节;(每个像素的颜色信息每3个字节一组,按BGR的顺序存放,其中每个字节只存一个颜色值。颜色值范围是0~255,用无符号char型存储)

!!!Windows规定一个扫描行所占的字节数必须是4的倍数(即以long为单位),不足的以0填充

24位真彩图每一行占的实际字节数 =((宽度*3+3)/4)*4 

灰度图每一行占的实际字节数= ((宽度+3)/4)*4

2)读取文件

利用fstream读文件

要注意BMP文件每个部分所占的字节数,因为不是每个部分的信息要需要读取,所以要利用seekg函数移动读文件的指针位置,还有就是利用read函数读取文件时,也要确定读取的字节数。

BMP的文件头没有要读取的内容,所以移动指针“跳过”文件头,然后读取信息头,可以利用sizeof()得到文件头和信息头所占的字节数。调色板部分也不需要读取,如果是24位位图,没有调色板,可以直接向下进行,其他位图都需要得到调色板的大小然后“跳过”,读取下一部分的位图数据。

这个作业写的 只能读8位和24位的 而且只是读入数据 没有修改

Image.h

#ifndef IMAGE_H
#define IMAGE_H
#include<iostream>
#include<fstream>
#include<windows.h>
#include<cmath>
#include<string>
using namespace std;
class Image {
	friend Image& operator+(Image& img1, Image& img2);
public:
	Image();
	Image(string fliename);
	~Image();
	long getWidth();
	long getHeight();
	float Average();
	float Variance();
	void show();
private:
	long m_width;
	long m_height;
	int m_bitCount;
	unsigned char* m_pData;
};

Image& operator+(Image& img1, Image& img2);

#endif

Image.cpp

#include"Image.h"

Image::Image() {
	this->m_width = 0;
	this->m_height = 0;
	this->m_pData = NULL;
}
Image::Image(string filename) {//bmp文件的地址
	
	ifstream open(filename, ios::binary);
	if (!open.is_open()) {
		cout <<filename<< "文件打开成功" << endl;
	}

	//跳过位图文件头
	open.seekg(sizeof(BITMAPFILEHEADER));

	//读取位图信息头
	BITMAPINFOHEADER a;
	open.read((char*)&a, sizeof(BITMAPINFOHEADER));
	m_height = a.biHeight;
	m_width = a.biWidth;
	m_bitCount= a.biBitCount;

	cout << "文件"<<filename << "为" << m_bitCount << "位位图" << endl;
	cout << "高度:" << m_height << endl;
	cout << "宽度:" << m_width << endl;


	//如果是24位位图 无调色板 直接向下进行
	//其他位图有调色板 需要跳过调色板读取位图数据
	if (m_bitCount != 24) {
		open.seekg(4 * (pow(2.0, m_bitCount)));//调色板大小 4*色彩数
	}
	
	//读取位图数据(有0补位)
	if(m_bitCount==8)
	{
		m_pData = new unsigned char[m_height * (((m_width + 3) / 4) * 4)];
		open.read((char*)m_pData, m_height * (((m_width + 3) / 4) * 4));
	}
	else if (m_bitCount == 24)
	{
		m_pData = new unsigned char[m_height * ((m_width * 3 + 3) / 4) * 4];
		open.read((char*)m_pData, m_height * ((m_width * 3 + 3) / 4) * 4);
	}
	
	open.close();
}
Image::~Image() {
	delete[] m_pData;
}
long Image::getHeight(){
	return m_height;
}
long Image::getWidth() {
	return m_width;
}

float Image::Average() {

	try {
		if (m_pData == NULL)
			throw exception("位图数据为空!");
		if (m_bitCount != 8 && m_bitCount != 24)
			throw m_bitCount;

		float sum = 0;
		if(m_bitCount==8)

		{
			for (int i = 0; i < m_height * ((m_width + 3) / 4) * 4; i++) {
				sum += m_pData[i];
			}
			return sum * 1.0 / (m_height * m_width);
		}
		else if (m_bitCount == 24) {

			for (int i = 0; i < m_height * ((m_width*3 + 3) / 4) * 4; i++) {
				sum += m_pData[i];
			}
			return sum * 1.0 / (m_height * m_width*3);
		}

	}
	catch (exception error) {
		cout << error.what() << endl;
		return 0;
	}
	catch (int) {
		cout << "无法对" << m_bitCount << "位位图计算 T_T" << endl;
		return 0;
	}
}

float Image::Variance() {

	try {
		if (m_pData == NULL)
			throw exception("位图数据为空!");
		if (m_bitCount != 8 && m_bitCount != 24)
			throw m_bitCount;

		float sum = 0;
		long long count = 0;
	
		//每行补位0的个数
		int n = (m_width % 4 == 0) ? 0 : 4 - m_width % 4;

		if(m_bitCount==8)
		{
			for (int i = 0; i < m_height; i++) {
				for (int j = 0; j < m_width; j++) {
					sum += ((m_pData[count] - this->Average()) * (m_pData[count] - this->Average()));
					count++;
				}
				if (n != 0)
					count += (n - 1);
			}
		}

		else if (m_bitCount == 24) {
			for (int i = 0; i < m_height; i++) {

				for (int j = 0; j < m_width; j++) {
					float sum1 = 0, avg1 = 0;
					for (int k = 0; k < 3; k++) {
						sum1 += m_pData[count];
						count += 1;
					}
					avg1 = sum1 * 1.0 / 3;
					sum += ((Average() - avg1) * (Average() - avg1));
				}
				if (n != 0)
					count += (n - 1);
			}
		}
		return sum * 1.0 / (m_height * m_width);
	}

	catch (exception error) {
		cout << error.what() << endl;
		return 0;
	}
	catch (int) {
		cout << "无法对" << m_bitCount << "位位图计算 T_T" << endl;
		return 0;
	}
}

Image& operator+(Image& img1, Image& img2) {

	try {
		if (img1.getHeight() != img2.getHeight() || img1.getWidth() != img2.getWidth())
			throw exception("两个位图长宽不同 无法运算");
		

		for (int i = 0; i < img1.getHeight() * ((img1.getWidth() + 3) / 4) * 4; i++) {
			if (img1.m_pData[i] + img2.m_pData[i] <= 255) {
				img1.m_pData[i] += img2.m_pData[i];
			}
			else {
				img1.m_pData[i] = (img1.m_pData[i] + img2.m_pData[i]) % 255;
			}
		}
		return img1;
	}
	catch (exception error) {
		cout << error.what() << endl;
	}
}

void Image::show() {
	
	cout <<"位图平均值:" << Average() << endl;
	cout << "位图方差:" << Variance() << endl;
}

Test.cpp

#include"Image.h"
int main() {
	string filename1, filename2, filename3, filename4, filename5;//F:\\Image\\test01.bmp F:\\Image\\test02.bmp F:\\Image\\test03.bmp F:\\Image\\test04.bmp F:\\Image\\test05.bmp
	cout << "输入5个位图的地址" << endl;
	cin >> filename1 >> filename2 >> filename3 >> filename4 >> filename5;
	 
	//样例信息:
	Image img1(filename1);//8位
	Image img2(filename2);//8位
	Image img3(filename3);//8位 (不同大小
	Image img4(filename4);//24位
	Image img5(filename5);//24位
	Image img6;//空

	cout << "img1:" << endl;
	img1.show();
	cout << "img2:" << endl;
	img2.show();
	
	cout << "img1+img2:" << endl;
	(img1 + img2).show();

	cout << "img1+img3:" << endl;
	img1 + img3;

	cout << "img4:" << endl;
	img4.show();
	cout << "img5:" << endl;
	img5.show();

	cout << "img6:" << endl;
	img6.show();

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值