利用OpenCV把一幅彩色图像转换成灰度图

图像灰度化是将彩色图像转化为灰度图像的过程,简化了图像并加快计算速度。OpenCV提供了imread()函数配合0参数或cvtColor()函数进行转换。此外,还可以自定义公式(0.299R+0.587G+0.114B)实现转换。文章展示了如何使用这些方法并展示了转换结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

图像灰度化的目的是为了简化矩阵,提高运算速度。

彩色图像中的每个像素颜色由R、G、B三个分量来决定,而每个分量的取值范围都在0-255之间,这样对计算机来说,彩色图像的一个像素点就会有256*256*256=16777216种颜色的变化范围!

而灰度图像是R、G、B分量相同的一种特殊彩色图像,对计算机来说,一个像素点的变化范围只有0-255这256种。

假设我们现在有一幅彩色图像,但是我们现在想得到它的灰度图,应该怎么做呢?

Opencv自带了这种转换函数,

我们可以在用imread()函数读取时设置第二个参数为0,就可以直接得到彩色图像的灰度图;

Mat src0 = imread("C:\\Users\\32498\\Pictures\\16.png",0);

也可以先把彩色图像读进来,然后使用cvtColor函数进行转换得到它的灰度图。

Mat src = imread("C:\\Users\\32498\\Pictures\\16.png");
cvtColor(src, cvt_gray_image,COLOR_BGR2GRAY);

也可以使用心理学公式GRAY=0.299*R+0.587*G+0.114*B自己编写一个转换函数,其中的加权系数是根据人眼的亮度感知系统调节出来的参数。


void ConvertRGB2GRAY(const Mat& image, Mat& imageGray)
{
	if (!image.data || image.channels() != 3)
	{
		return;
	}
	//创建一张单通道的灰度图像
	imageGray = Mat::zeros(image.size(), CV_8UC1);
	//取出存储图像像素的数组的指针
	uchar* pointImage = image.data;
	uchar* pointImageGray = imageGray.data;
	//取出图像每行所占的字节数
	size_t stepImage = image.step;
	size_t stepImageGray = imageGray.step;

	
	for (int i = 0; i < imageGray.rows; i++)
	{
		for (int j = 0; j < imageGray.cols; j++)
		{
			//opencv的通道顺序是BGR,而不是我们常说的RGB顺序
			pointImageGray[i * stepImageGray + j] =
				(uchar)(0.114 * pointImage[i * stepImage + 3 * j] +
					0.587 * pointImage[i * stepImage + 3 * j + 1] +
					0.299 * pointImage[i * stepImage + 3 * j + 2]);
		}
	}
}

 在多通道图像中,比如RGB图像是这样保存的

int  widthStep;   /* 排列的图像行大小,以字节为单位 */
int  nChannels;     /* 大多数OPENCV函数支持1,2,3 或 4 个通道 */

图像矩阵是一个二维数组,不论是灰度图像还是彩色图像,在计算机内存中都是以一维数组的形式存储的。用Mat存储一幅图像时,若图像在内存中是连续存储的(Mat对象的isContinuous == true),则可以将图像的数据看成是一个一维数组,而其data(uchar*)成员就是指向图像数据的第一个字节的,因此可以用data指针访问图像的数据。

如果想要遍历其中的元素,可以使用指针的遍历方法


uchar* data=(uchar *)img->imageData;
int step = img->widthStep/sizeof(uchar);
int channels = img->nChannels;
uchar *b,*g,*r;
for(int i=0;i<img->height;i++)
     for(int j=0;j<img->width;j++){
           *b=data[i*step+j*chanels+0];
           *g=data[i*step+j*chanels+1];
           *r=data[i*step+j*chanels+2];
      }

下面我们来看一看用这几种方法进行灰度转化的结果

#include <opencv2\opencv.hpp>
using namespace cv;
void ConvertRGB2GRAY(const Mat& image, Mat& imageGray);

int main()
{
	Mat src = imread("C:\\Users\\32498\\Pictures\\16.png");
	Mat src0 = imread("C:\\Users\\32498\\Pictures\\16.png",0);
	Mat grayImage;
    Mat cvt_gray_image;

	//读入的彩色图
	namedWindow("origin_image", WINDOW_NORMAL);
	imshow("origin_image", src);

	//opencv使用imread函数读入彩色图,设置第二个参数为0得到的灰度图
	namedWindow("opencv_image", WINDOW_NORMAL);
	imshow("opencv_image", src0);

	//使用公式GRAY=0.299*R+0.587*G+0.114*B
	ConvertRGB2GRAY(src, grayImage);
	namedWindow("my_gray_image", WINDOW_NORMAL);
	imshow("my_gray_image", grayImage);

	//先读入彩色图,然后使用cvtColor函数进行灰度转化
	cvtColor(src, cvt_gray_image,COLOR_BGR2GRAY);
	namedWindow("cvt_gray_image", WINDOW_NORMAL);
	imshow("cvt_gray_image", cvt_gray_image);
	waitKey(0);
	return 0;
}

void ConvertRGB2GRAY(const Mat& image, Mat& imageGray)
{
	if (!image.data || image.channels() != 3)
	{
		return;
	}
	//创建一张单通道的灰度图像
	imageGray = Mat::zeros(image.size(), CV_8UC1);
	//取出存储图像像素的数组的指针
	uchar* pointImage = image.data;
	uchar* pointImageGray = imageGray.data;
	//取出图像每行所占的字节数
	size_t stepImage = image.step;
	size_t stepImageGray = imageGray.step;

	
	for (int i = 0; i < imageGray.rows; i++)
	{
		for (int j = 0; j < imageGray.cols; j++)
		{
			//opencv的通道顺序是BGR,而不是我们常说的RGB顺序
			pointImageGray[i * stepImageGray + j] =
				(uchar)(0.114 * pointImage[i * stepImage + 3 * j] +
					0.587 * pointImage[i * stepImage + 3 * j + 1] +
					0.299 * pointImage[i * stepImage + 3 * j + 2]);
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值