opencv 颜色直方图(灰度图,均衡化,对比,描绘颜色直方图)

参考:

《OpenCV3编程入门》

《学习OpenCV(中文版)》


#################################################################33


最近上课需要将颜色直方图的内容,所以就把直方图一些常用的知识点复习了一遍,包括灰度图,均衡化,对比等。

#include "hist.h"

/**
 * @function : 显示灰度图和均衡化后的灰度图
 * @param : img_address - const string 图片地址
*/
void show_gray(const string img_address)
{
	Mat img, dst;
	//加载源图像
	img = imread(img_address, 1);
	if (img.empty()) 
	{
		cout<<"读取图片错误\n";
		return ;
	}

	//转为灰度图
	cvtColor(img, img, COLOR_BGR2GRAY);

	//直方图均衡化
	equalizeHist(img, dst);

	imshow("show", img);
	//显示结果
	imshow("show_equalize", dst);

	waitKey(0);
}

/**
 * @function : 提取灰度颜色直方图并展示
 * @param : color_address - string 图像地址 
*/
void show_gray_color_histogram(const string color_address)
{
	//载入原图并显示
	Mat srcImage = imread(color_address, 0);
	//imshow("原图", srcImage);
	if (!srcImage.data) 
	{
		cout<<"fail to load image"<<endl;
		return ;
	}
	Mat dst;
	equalizeHist(srcImage, dst);
	imshow("均衡化", dst);

	//定义变量
	MatND dstHist;
	int dims = 1;
	float hranges[] = {0,255};
	const float *ranges[] = {hranges};
	int size = 256;
	int channels = 0;

	//计算直方图
	calcHist(&dst, 1, &channels, Mat(), dstHist, dims, &size, ranges);
	int scale = 1;

	Mat dstImage(size*scale, size, CV_8U, Scalar(0));
	//获取最大值和最小值
	double maxValue = 0;
	double minValue = 0;
	minMaxLoc(dstHist, &minValue, &maxValue, 0, 0);

	//绘制直方图
	int hpt = saturate_cast<int>(0.9 * size);
	for (int i=0; i<256; i++) 
	{
		float binValue = dstHist.at<float>(i);
		int realValue = saturate_cast<int>(binValue * hpt / maxValue);
		rectangle(dstImage, Point(i*scale, size-1), Point((i+1)*scale-1, size-realValue), Scalar(255));
	}
	imshow("灰度直方图", dstImage);
	waitKey(0);
}

/**
 * @function : 绘制RGB颜色直方图
 * @param : img_address - const string 图片地址
*/
void show_RGB_histogram(const string img_address)
{
	//载入图片
	Mat srcImage;
	srcImage = imread(img_address);
	imshow("原图", srcImage);

	//参数准备
	int bins = 256;
	int hist_size[] = {bins};
	float range[] = {0, 256};
	const float *ranges[] = {range};
	MatND redHist, greenHist, blueHist;
	int channels_r[] = {0};

	//进行直方图的计算(红色部分)
	calcHist(&srcImage, 1, channels_r, Mat(), redHist, 1, hist_size, ranges, true, false);

	//绿色分量计算
	int channels_g[] = {1};
	calcHist(&srcImage, 1, channels_g, Mat(), greenHist, 1, hist_size, ranges, true, false);

	//蓝色分量计算
	int channels_b[] = {1};
	calcHist(&srcImage, 1, channels_b, Mat(), blueHist, 1, hist_size, ranges, true, false);

	//绘制rgb颜色直方图
	//参数准备
	double maxValue_red, maxValue_green, maxValue_blue;
	minMaxLoc(redHist, 0, &maxValue_red, 0, 0);
	minMaxLoc(greenHist, 0, &maxValue_green, 0, 0);
	minMaxLoc(blueHist, 0, &maxValue_blue, 0, 0);
	int scale = 1;
	int histHeight = 256;
	Mat histImage = Mat::zeros(histHeight, bins*3, CV_8UC3);

	//开始绘制
	for (int i=0; i<bins; i++)
	{
		//参数准备
		float binValue_red = redHist.at<float>(i);
		float binValue_green = greenHist.at<float>(i);
		float binValue_blue = blueHist.at<float>(i);

		int intensity_red = cvRound(binValue_red * histHeight / maxValue_red); //计算绘制高度
		int intensity_green = cvRound(binValue_green * histHeight / maxValue_green); //计算绘制高度
		int intensity_blue = cvRound(binValue_blue * histHeight / maxValue_blue); //计算绘制高度

		//绘制红色部分直方图
		rectangle(histImage, Point(i*scale, histHeight-1), Point((i+1)*scale-1, histHeight-intensity_red), Scalar(0, 0, 255));

		//绘制绿色部分直方图
		rectangle(histImage, Point((i+bins)*scale, histHeight-1), Point((i+bins+1)*scale-1, histHeight-intensity_green), Scalar(0, 255, 0));

		//绘制蓝色部分直方图
		rectangle(histImage, Point((i+bins*2)*scale, histHeight-1), Point((i+bins*2+1)*scale-1, histHeight-intensity_blue), Scalar(255, 0, 0));
	}

	//在窗口中显示
	imshow("RGB", histImage);
	waitKey(0);
}

/**
 * @function : 直方图对比
 * @param : srcImg_address - const string 原图地址
 * @param : comp1_address - const string 对比图1地址
 * @param : comp2_address - const string 对比图2地址
*/
void compare_hist(const string srcImg_address, const string comp1_address, const string comp2_address)
{
	//声明存储基准图像和另外两张对比图像的矩阵(RGB 和 HSV)
	Mat srcImage_base, hsvImage_base;
	Mat srcImage_test1, hsvImage_test1;
	Mat srcImage_test2, hsvImage_test2;
	Mat hsvImage_halfDown;

	//载入基准图像(srcImage_base)和两张测试图像srcImage_test1,srcImage_test2,并显示
	srcImage_base = imread(srcImg_address, 1);
	srcImage_test1 = imread(comp1_address, 1);
	srcImage_test2 = imread(comp2_address, 1);
	//显示
	imshow("基准图像", srcImage_base);
	imshow("测试图像1", srcImage_test1);
	imshow("测试图像2", srcImage_test2);

	//将图像由RGB色彩空间转换到HSV色彩空间
	cvtColor(srcImage_base, hsvImage_base, COLOR_BGR2HSV);
	cvtColor(srcImage_test1, hsvImage_test1, COLOR_BGR2HSV);
	cvtColor(srcImage_test2, hsvImage_test2, COLOR_BGR2HSV);
	
	//创建包含基准图像下半身的半身图像(HSV格式)
	hsvImage_halfDown = hsvImage_base(Range(hsvImage_base.rows/2, hsvImage_base.rows-1), Range(0, hsvImage_base.cols-1));

	//初始化计算直方图需要的实参
	//对hue通道使用30个bin,对saturation通道使用32个bin
	int h_bins = 50; int s_bins = 60;
	int histSize[] = {h_bins, s_bins};
	//hue的取值范围从0到256,saturation取值范围从0到180
	float h_ranges[] = {0, 256};
	float s_ranges[] = {0, 180};
	const float* ranges[] = {h_ranges, s_ranges};
	//使用第0和第1通道
	int channels[] = {0, 1};

	//创建存储直方图的MatND
	MatND baseHist;
	MatND halfDownHist;
	MatND testHist1;
	MatND testHist2;

	//计算基准图像,两张测试图像,半身基准图像的HSV直方图
	calcHist(&hsvImage_base, 1, channels, Mat(), baseHist, 2, histSize, ranges, true, false);
	normalize(baseHist, baseHist, 0, 1, NORM_MINMAX, -1, Mat());

	calcHist(&hsvImage_halfDown, 1, channels, Mat(), halfDownHist, 2, histSize, ranges, true, false);
	normalize(halfDownHist, halfDownHist, 0, 1, NORM_MINMAX, -1, Mat());

	calcHist(&hsvImage_test1, 1, channels, Mat(), testHist1, 2, histSize, ranges, true, false);
	normalize(testHist1, testHist1, 0, 1, NORM_MINMAX, -1, Mat());

	calcHist(&hsvImage_test2, 1, channels, Mat(), testHist2, 2, histSize, ranges, true, false);
	normalize(testHist2, testHist2, 0, 1, NORM_MINMAX, -1, Mat());

	//按顺序使用4种对比标准将基准图像的直方图与其余各直方图进行对比
	for (int i=0; i<4; i++)
	{
		//进行图像直方图的对比
		int compare_method = i;
		double base_base = compareHist(baseHist, baseHist, compare_method);
		double base_half = compareHist(baseHist, halfDownHist, compare_method);
		double base_test1 = compareHist(baseHist, testHist1, compare_method);
		double base_test2 = compareHist(baseHist, testHist2, compare_method);

		//输出结果
		cout<<"方法["<<i<<"]的匹配结果如下:"<<endl;
		cout<<"【基准图 - 基准图】:"<<base_base<<"  【基准图 - 半身图】:"<<base_half<<"  【基准图 - 测试图1】:"<<base_test1<<" 【基准图 - 测试图2】:"<<base_test2<<endl;
	}

	cout<<"endl..."<<endl;
	waitKey(0);
}

上面代码都是使用全局颜色直方图进行操作。在实际应用中,如果想要进行直方图对比,仅使用全局颜色直方图并不能得到很好的结果,因为全局颜色直方图忽略了图像的空间信息。改进方法如下:

将图像分成若干局域,比如上下左右四等分为4个区域,然后分别提取颜色直方图,计算相似度;

在上一步的基础上还可以增加权重值,对于比较重要的区域赋以高权重值;

还可以使用颜色直方图和其他特征向量进行联合对比,比如纹理特征,形状特征等。



  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值