bmp彩色转灰度

本文介绍了如何将BMP彩色图像转换为灰度图像,主要探讨了心理学公式和整数运算算法,包括整数乘法和移位运算,以提高效率。通过C++代码示例展示了具体实现过程,适用于图像处理和游戏编程等领域。
摘要由CSDN通过智能技术生成

一、基础

  对于彩色转灰度,有一个很著名的心理学公式:

Gray = R*0.299 + G*0.587 + B*0.114

二、整数算法

  而实际应用时,希望避免低速的浮点运算,所以需要整数算法。

  注意到系数都是3位精度的没有,我们可以将它们缩放1000倍来实现整数运算算法:

Gray = (R*299 + G*587 + B*114 + 500) / 1000

  RGB一般是8位精度,现在缩放1000倍,所以上面的运算是32位整型的运算。注意后面那个除法是整数除法,所以需要加上500来实现四舍五入。

  就是由于该算法需要32位运算,所以该公式的另一个变种很流行:

Gray = (R*30 + G*59 + B*11 + 50) / 100

  但是,虽说上一个公式是32位整数运算,但是根据80x86体系的整数乘除指令的特点,是可以用16位整数乘除指令来运算的。而且现在32位早普及了(AMD64都出来了),所以推荐使用上一个公式。

三、整数移位算法

  上面的整数算法已经很快了,但是有一点仍制约速度,就是最后的那个除法。移位比除法快多了,所以可以将系数缩放成 2的整数幂。

  习惯上使用16位精度,2的16次幂是65536,所以这样计算系数:

0.299 * 65536 = 19595.264 ≈ 19595

0.587 * 65536 + (0.264) = 38469.632 + 0.264 = 38469.896 ≈ 38469

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是C++将彩色换为灰度图的代码示例: ```c++ #include <iostream> #include <fstream> #include <cstdlib> #include <cmath> using namespace std; #pragma pack(push, 1) typedef struct { unsigned short bfType; unsigned int bfSize; unsigned short bfReserved1; unsigned short bfReserved2; unsigned int bfOffBits; } BITMAPFILEHEADER; typedef struct { unsigned int biSize; int biWidth; int biHeight; unsigned short biPlanes; unsigned short biBitCount; unsigned int biCompression; unsigned int biSizeImage; int biXPelsPerMeter; int biYPelsPerMeter; unsigned int biClrUsed; unsigned int biClrImportant; } BITMAPINFOHEADER; typedef struct { unsigned char rgbBlue; unsigned char rgbGreen; unsigned char rgbRed; unsigned char rgbReserved; } RGBQUAD; typedef struct { BITMAPFILEHEADER fileHeader; BITMAPINFOHEADER infoHeader; RGBQUAD *palette; unsigned char *data; } BMP; #pragma pack(pop) BMP* readBmp(char* filename) { BMP* bmp = new BMP; ifstream file(filename, ios::binary); if (!file) { cout << "Error: could not open file " << filename << endl; exit(1); } file.read((char*)&bmp->fileHeader, sizeof(BITMAPFILEHEADER)); file.read((char*)&bmp->infoHeader, sizeof(BITMAPINFOHEADER)); if (bmp->infoHeader.biBitCount <= 8) { bmp->palette = new RGBQUAD[1 << bmp->infoHeader.biBitCount]; file.read((char*)bmp->palette, sizeof(RGBQUAD) * (1 << bmp->infoHeader.biBitCount)); } bmp->data = new unsigned char[bmp->infoHeader.biSizeImage]; file.seekg(bmp->fileHeader.bfOffBits, ios::beg); file.read((char*)bmp->data, bmp->infoHeader.biSizeImage); file.close(); return bmp; } void writeBmp(char* filename, BMP* bmp) { ofstream file(filename, ios::binary); if (!file) { cout << "Error: could not open file " << filename << endl; exit(1); } file.write((char*)&bmp->fileHeader, sizeof(BITMAPFILEHEADER)); file.write((char*)&bmp->infoHeader, sizeof(BITMAPINFOHEADER)); if (bmp->infoHeader.biBitCount <= 8) { file.write((char*)bmp->palette, sizeof(RGBQUAD) * (1 << bmp->infoHeader.biBitCount)); } file.write((char*)bmp->data, bmp->infoHeader.biSizeImage); file.close(); } void rgb2gray(BMP* bmp) { if (bmp->infoHeader.biBitCount != 24) { cout << "Error: only support 24-bit color depth" << endl; exit(1); } int width = bmp->infoHeader.biWidth; int height = bmp->infoHeader.biHeight; int lineByte = (width * 24 + 31) / 32 * 4; unsigned char* data = bmp->data; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { int b = data[i * lineByte + j * 3]; int g = data[i * lineByte + j * 3 + 1]; int r = data[i * lineByte + j * 3 + 2]; int gray = (r * 19595 + g * 38469 + b * 7472) >> 16; data[i * lineByte + j * 3] = gray; data[i * lineByte + j * 3 + 1] = gray; data[i * lineByte + j * 3 + 2] = gray; } } } int main() { BMP* bmp = readBmp("color.bmp"); rgb2gray(bmp); writeBmp("gray.bmp", bmp); delete[] bmp->palette; delete[] bmp->data; delete bmp; return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值