c++平均值法灰度化图像_C++ 彩色图转灰度图

本文介绍了如何使用C++通过平均值法将彩色图像转换为灰度图像。遵循公式Gray = 0.299*R + 0.587*G + 0.114*B,该方法基于视觉科学原理。文章提供了一个实例,展示了原始图像和应用算法后的效果。

f0555b868b77da89644ed6207d5d8497.png

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

0fd3416954ab6bfca32d9a249a70b822.png

图像数据结构定义,该定义放在了单独头文件中,读者可根据自己的情况放置合适的位置:

/**
* @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;
}

实现效果:

原图:

412777640bccd2417f4595db42203369.png

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

f953409a4dcb6cd8faa354089c7851e9.png

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

6df190ef13a3e2ea33c518d3b2151fbf.png

很多的图像处理库都实现了彩色图转灰度图的功能,公式中Gray = 0.299*R+0.587*G+0.114*B为什么分量是这三个系数,据说是心理学家根据人的视觉特点得出的三个分量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值