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

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

彩色图像中的每个像素颜色由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]);
		}
	}
}

猜你喜欢

转载自blog.csdn.net/yangSHU21/article/details/130237669