
彩色图转灰度图公式为Gray = 0.299*R+0.587*G+0.114*B。如下例子中我们读入一幅bmp彩色图像,然后利用该公式转化为灰度图,图像的读入参考之前的文章。

图像数据结构定义,该定义放在了单独头文件中,读者可根据自己的情况放置合适的位置:
/**
* @brief 简单概述
* @brief 图像格式
*/
enum ImageFormat
{
IMAGE_GREY = 0x0000, // 灰度图像
IMAGE_RGB, // 彩色RGB图像
IMAGE_BGR, // 彩色BGR图像
IMAGE_RGBA, // 彩色RGBA图像
IMAGE_BGRA // 彩色BGRA图像
};
/**
* @brief 简单概述
* @brief 图像数据结构
*/
typedef struct
{
ImageFormat format;
int width;
int height;
unsigned char* pBuffer = NULL;
}Image;
算法头文件 algorithm.h:
/*****************************************************************************
* C++ 图像读取
* Copyright (C) 2020 1158292387@qq.com
*
* @file
* @brief 对文件的简单概述
* Details.
*
* @author Leeme
* @email 1158292387@qq.com
* @version 1.0.0.1(版本)
* @date 2020.11.21
* @license GNU General Public License (GPL)
*
*----------------------------------------------------------------------------
* Remark : Description
*----------------------------------------------------------------------------
* Change History :
* <Date> | <Version> | <Author> | <Description>
*----------------------------------------------------------------------------
* 2020/10/30 | 1.0.0.1 | Leeme | Create file
*----------------------------------------------------------------------------
*
*****************************************************************************/
#pragma once
#include "define.h"
/**
* @brief 简单概述
* @brief 图像算法基类
*/
class ImgAlg
{
public:
ImgAlg(){}
~ImgAlg()
{
delete m_Image.pBuffer;
m_Image.pBuffer = NULL;
}
/**
* @brief 简单概述
* @brief 设置图像
*/
bool SetInputData(const Image& src)
{
if (src.pBuffer == NULL)
return false;
m_Image.width = src.width;
m_Image.height = src.height;
m_Image.format = src.format;
if (m_Image.pBuffer != NULL)
{
delete[]m_Image.pBuffer;
m_Image.pBuffer = NULL;
}
long ImageSize = src.width*src.height;
long pBufSize = ImageSize;
switch (m_Image.format)
{
case IMAGE_GREY:
{
m_Image.pBuffer = new unsigned char[ImageSize];
}
break;
case IMAGE_RGB:
{
pBufSize = ImageSize * 3;
m_Image.pBuffer = new unsigned char[pBufSize];
}
break;
case IMAGE_BGR:
{
pBufSize = ImageSize * 3;
m_Image.pBuffer = new unsigned char[pBufSize];
}
break;
case IMAGE_RGBA:
{
pBufSize = ImageSize * 4;
m_Image.pBuffer = new unsigned char[pBufSize];
}
break;
case IMAGE_BGRA:
{
pBufSize = ImageSize * 4;
m_Image.pBuffer = new unsigned char[pBufSize];
}
break;
default:
break;
}
memcpy(m_Image.pBuffer, src.pBuffer, pBufSize);
return true;
}
/**
* @brief 简单概述
* @brief 获取图像计算结果
*/
bool GetOutputData(Image* src)
{
if (m_Image.pBuffer == NULL)
return false;
src->width = m_Image.width;
src->height = m_Image.height;
src->format = m_Image.format;
if (src->pBuffer != NULL)
{
delete[] src->pBuffer;
src->pBuffer = NULL;
}
long ImageSize = m_Image.width*m_Image.height;
long pBufSize = ImageSize;
switch (m_Image.format)
{
case IMAGE_GREY:
{
src->pBuffer = new unsigned char[ImageSize];
}
break;
case IMAGE_RGB:
{
pBufSize = ImageSize * 3;
src->pBuffer = new unsigned char[pBufSize];
}
break;
case IMAGE_BGR:
{
pBufSize = ImageSize * 3;
src->pBuffer = new unsigned char[pBufSize];
}
break;
case IMAGE_RGBA:
{
pBufSize = ImageSize * 4;
src->pBuffer = new unsigned char[pBufSize];
}
break;
case IMAGE_BGRA:
{
pBufSize = ImageSize * 4;
src->pBuffer = new unsigned char[pBufSize];
}
break;
default:
break;
}
memcpy(src->pBuffer, m_Image.pBuffer, pBufSize);
return true;
}
virtual void SetAlgType(int) = 0;
/**
* @brief 简单概述
* @brief 图像算法实现接口
*/
virtual bool UpdateData() = 0;
protected:
Image m_Image;
};
/**
* @brief 简单概述
* @brief 彩色图像转灰度图像
*/
class Rgb2Grey : public ImgAlg
{
public:
Rgb2Grey();
~Rgb2Grey() {}
enum AlgType
{
ALG_EXPERT=0x0000, // 常用计算方法 Gray = 0.299*R+0.587*G+0.114*B
ALG_AVG // 平均值计算法 Gray = (R+G+B)/3
};
void SetAlgType(int type) { m_AlgType = (AlgType)type; }
bool UpdateData();
private:
/**
* @brief 简单概述
* @brief 彩色图像转灰度图像算法接口
* @brief Gray = 0.299*R+0.587*G+0.114*B
* @brief Gray = (R*299+G*587+B*114+500)/1000
* @brief Gray = (R*30+G*59+B*11+50)/100
* @brief 为了避免浮点型数据的计算耗时,我们将浮点型计算转化为整形计算
*/
void CaclUseExpert(unsigned char* pBuf,long pBufSize);
/**
* @brief 简单概述
* @brief 彩色图像转灰度图像算法接口
* @brief 采用平均值方式进行计算
*/
void CaclUseAvg(unsigned char* pBuf, long pBufSize);
AlgType m_AlgType;
};
算法实现文件 algorithm.cpp:
#include "algorithm.h"
Rgb2Grey::Rgb2Grey()
{
m_AlgType = ALG_EXPERT;
}
bool Rgb2Grey::UpdateData()
{
if (m_Image.pBuffer == NULL || m_Image.format == IMAGE_GREY)
return false;
long pBufSize = m_Image.width*m_Image.height;
unsigned char* pBuf = new unsigned char[pBufSize];
if (m_AlgType == ALG_EXPERT)
{
this->CaclUseExpert(pBuf, pBufSize);
}
else if (m_AlgType == ALG_AVG)
{
this->CaclUseAvg(pBuf, pBufSize);
}
m_Image.format = IMAGE_GREY;
delete[] m_Image.pBuffer;
m_Image.pBuffer = pBuf;
return true;
}
/**
* @brief 简单概述
* @brief 彩色图像转灰度图像算法接口
* @brief Gray = 0.299*R+0.587*G+0.114*B
* @brief Gray = (R*299+G*587+B*114+500)/1000
* @brief Gray = (R*30+G*59+B*11+50)/100
* @brief 为了避免浮点型数据的计算耗时,我们将浮点型计算转化为整形计算
*/
void Rgb2Grey::CaclUseExpert(unsigned char* pBuf,long pBufSize)
{
short kr = 30;
short kg = 59;
short kb = 11;
switch (m_Image.format)
{
case IMAGE_RGB:
{
for (int i = 0; i < pBufSize * 3; i += 3)
{
*pBuf = (m_Image.pBuffer[i] * kr + m_Image.pBuffer[i + 1] * kg + m_Image.pBuffer[i + 2] * kb + 50) / 100;
pBuf++;
}
}
break;
case IMAGE_BGR:
{
for (int i = 0; i < pBufSize * 3; i += 3)
{
*pBuf = (m_Image.pBuffer[i] * kb + m_Image.pBuffer[i + 1] * kg + m_Image.pBuffer[i + 2] * kr + 50) / 100;
pBuf++;
}
}
break;
case IMAGE_RGBA:
{
for (int i = 0; i < pBufSize * 4; i += 4)
{
*pBuf = (m_Image.pBuffer[i] * kr + m_Image.pBuffer[i + 1] * kg + m_Image.pBuffer[i + 2] * kb + 50) / 100;
pBuf++;
}
}
break;
case IMAGE_BGRA:
{
for (int i = 0; i < pBufSize * 4; i += 4)
{
*pBuf = (m_Image.pBuffer[i] * kb + m_Image.pBuffer[i + 1] * kg + m_Image.pBuffer[i + 2] * kr + 50) / 100;
pBuf++;
}
}
break;
default:
break;
}
pBuf -= pBufSize;
}
/**
* @brief 简单概述
* @brief 彩色图像转灰度图像算法接口
* @brief 采用平均值方式进行计算
*/
void Rgb2Grey::CaclUseAvg(unsigned char* pBuf, long pBufSize)
{
switch (m_Image.format)
{
case IMAGE_RGB:
{
for (int i = 0; i < pBufSize * 3; i += 3)
{
*pBuf = (m_Image.pBuffer[i] + m_Image.pBuffer[i + 1] + m_Image.pBuffer[i + 2])/3;
pBuf++;
}
}
break;
case IMAGE_BGR:
{
for (int i = 0; i < pBufSize * 3; i += 3)
{
*pBuf = (m_Image.pBuffer[i] + m_Image.pBuffer[i + 1] + m_Image.pBuffer[i + 2]) / 3;
pBuf++;
}
}
break;
case IMAGE_RGBA:
{
for (int i = 0; i < pBufSize * 4; i += 4)
{
*pBuf = (m_Image.pBuffer[i] + m_Image.pBuffer[i + 1] + m_Image.pBuffer[i + 2]) / 3;
pBuf++;
}
}
break;
case IMAGE_BGRA:
{
for (int i = 0; i < pBufSize * 4; i += 4)
{
*pBuf = (m_Image.pBuffer[i] + m_Image.pBuffer[i + 1] + m_Image.pBuffer[i + 2]) / 3;
pBuf++;
}
}
break;
default:
break;
}
pBuf -= pBufSize;
}
实现效果:
原图:

采用心理学公式得出的效果图:

采用平均值得出的效果图:

很多的图像处理库都实现了彩色图转灰度图的功能,公式中Gray = 0.299*R+0.587*G+0.114*B为什么分量是这三个系数,据说是心理学家根据人的视觉特点得出的三个分量。
本文介绍了如何使用C++通过平均值法将彩色图像转换为灰度图像。遵循公式Gray = 0.299*R + 0.587*G + 0.114*B,该方法基于视觉科学原理。文章提供了一个实例,展示了原始图像和应用算法后的效果。

5171

被折叠的 条评论
为什么被折叠?



