图像处理之图像直方图

图像处理之图像直方图

1、什么是图像灰度直方图?什么是直方图均衡化?什么是直方图规定化?

  • 灰度直方图从数学上来说,图像直方图是描述图像的各个灰度级的统计特性,它是图像灰度值的函数,统计图像中各个灰度级出现的次数或频率从图像上来说,灰度直方图是一个二维图像,横坐标为图像中各个像素点的灰度级别,纵坐标表示具有各个灰度级别的像素在图像中出现的次数和频率
  • 图像的灰度直方图是一个离散函数,它表示图像的每一灰度级与该灰度级出现频率的对应关系。
  • 直方图均衡化是指通过某种灰度映射(如:非线性拉伸)使原始图像的直方图变换为在整个灰度范围内均匀分布。
  • 目的:增加像素灰度值的动态范围,增强图像整体对比度。
  • 直方图规定化就是要调整原始图像的直方图去逼近规定的目标直方图。有选择地增强某个灰度范围内的对比度或使图像灰度值满足某种特定的分布。
  • 归一化直方图:各个灰度级出现的次数除以图像的像素总数,即得到各个灰度级出现的概率,从而得到归一化直方图。
  • 代码:知道图像指针unchar *ptr,图像宽int width,高int height,求图像灰度直方图。

OpenCV实现图像直方图:

// RGB三色分量直方图.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

#include   //包含核心功能,尤其是底层数据结构和算法函数。
#include    //包含读写图像及视频的函数,以及操作图形用户界面函数。
#include    //包含图像处理函数。
#include 

using namespace std;

//绘制 RGB 图像分离通道后的每一单通道的直方图
void f_getRGBHist(cv::Mat& img)
{
	int bins = 256;
	int hist_size[] = {bins};
	float range[] = {0, 256};
	const float* ranges[] = {range};

	cv::MatND hist_r, hist_g, hist_b;
	int nImages = 1;
	int dims = 1;

	int channels_r[] ={0};
	cv::calcHist(&img, 1, channels_r, cv::Mat(), hist_r, 1, hist_size, ranges, true, false);

	int channels_g[] = {1};
	cv::calcHist(&img, 1, channels_g, cv::Mat(), hist_g, 1, hist_size, ranges, true, false);

	int channels_b[] = {2}; 
	cv::calcHist(&img, 1, channels_b, cv::Mat(), hist_b, 1, hist_size, ranges, true, false);


	double max_val_r, max_val_g, max_val_b;
	double min_val_r, min_val_g, min_val_b;
	cv::minMaxLoc(hist_r, &min_val_r, &max_val_r, 0, 0);
	cv::minMaxLoc(hist_g, &min_val_g, &max_val_g, 0, 0);
	cv::minMaxLoc(hist_b, &min_val_b, &max_val_b, 0, 0);

	int scale = 1;
	int hist_height = 256;
	cv::Mat hist_img = cv::Mat::zeros(hist_height, bins*3, CV_8UC3);
	for (int i=0; i(i);
		float bin_val_g = hist_g.at(i);
		float bin_val_b = hist_b.at(i);

		int intensity_r = cvRound(bin_val_r*hist_height/max_val_r); //要绘制的高度
		int intensity_g = cvRound(bin_val_g*hist_height/max_val_g);
		int intensity_b = cvRound(bin_val_b*hist_height/max_val_b);

		//cv::rectangle();
		cv::rectangle(hist_img, cv::Point(i*scale, hist_height-1), cv::Point((i+1)*scale-1,hist_height-intensity_r), CV_RGB(255,0,0));
		cv::rectangle(hist_img, cv::Point((i+bins)*scale, hist_height-1), cv::Point((i+bins+1)*scale-1,hist_height-intensity_g), CV_RGB(0,255,0));
		cv::rectangle(hist_img, cv::Point((i+bins*2)*scale, hist_height-1), cv::Point((i+bins*2+1)*scale, hist_height-intensity_b), CV_RGB(0,0,255));
	}
	cout << "finish drawing histogram." << endl;
	cv::imwrite("../RGB_Histogram.bmp", hist_img);
	cv::namedWindow("RGB Histogram", 1);
	cv::imshow("RGB Histogram", hist_img);
	cv::waitKey();
}

int _tmain(int argc, _TCHAR* argv[])
{
	cv::Mat src;
	src = cv::imread("../baboon.bmp");
	if (src.data==NULL)
	{
		cout << "fail to load image." << endl;
		return 0;
	}
	cv::namedWindow("source", 1);
	cv::imshow("source", src);
	
	f_getRGBHist(src);
	f_getRGBHist2(src);


	return 0;
}

图像处理之图像直方图_第1张图片

 图1 原图src

图像处理之图像直方图_第2张图片

图2 RGB三色分量的直方图

int f_getRGBHist2(cv::Mat& src)
{
	//Mat src;
	Mat dst;

	/ 装载图像
	//src = imread( "../baboon.jpg", 1 );

	if( !src.data )
	{ 
		return -1; 
	}

	Mat gray_Image;
	cvtColor(src, gray_Image, CV_BGR2GRAY);
	imshow("gray_Image", gray_Image);
	imwrite("../gray_Image.bmp", gray_Image);

	Mat result;
	//直方图均衡化
	equalizeHist(gray_Image, result);

	imshow("equalizeHist", result);
	imwrite("../equalizeHist.bmp", result);


	/// BGR彩色图像分割成3个单通道图像 ( R, G 和 B )
	vector rgb_planes;
	split( src, rgb_planes );

	/// 设定bin数目
	int histSize = 255;

	/// 设定取值范围 ( R,G,B) )
	float range[] = { 0, 255 } ;
	const float* histRange = { range };

	bool uniform = true; 
	bool accumulate = false;

	Mat r_hist, g_hist, b_hist;

	/// 计算直方图:
	calcHist( &rgb_planes[0], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate );
	calcHist( &rgb_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate );
	calcHist( &rgb_planes[2], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate );

	// 创建直方图画布
	int hist_w = 600; int hist_h = 400;
	int bin_w = cvRound( (double) hist_w/histSize );

	Mat rgb_hist[3];
	//初始化
	for(int i=0; i<3; ++i)  
	{  
		rgb_hist[i] = Mat(hist_h, hist_w, CV_8UC3, Scalar::all(0));  
	}  

	Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) );

	/// 将直方图归一化到范围 [ 0, histImage.rows ]
	normalize(r_hist, r_hist, 0, histImage.rows-10, NORM_MINMAX, -1, Mat() );
	normalize(g_hist, g_hist, 0, histImage.rows-10, NORM_MINMAX, -1, Mat() );
	normalize(b_hist, b_hist, 0, histImage.rows-10, NORM_MINMAX, -1, Mat() );

	/// 在直方图画布上画出直方图
	for( int i = 1; i < histSize; i++ )
	{
		line( histImage, Point( bin_w*(i-1), hist_h - cvRound(r_hist.at(i-1)) ) ,
			Point( bin_w*(i), hist_h - cvRound(r_hist.at(i)) ),
			Scalar( 0, 0, 255), 2, 8, 0  );
		line( histImage, Point( bin_w*(i-1), hist_h - cvRound(g_hist.at(i-1)) ) ,
			Point( bin_w*(i), hist_h - cvRound(g_hist.at(i)) ),
			Scalar( 0, 255, 0), 2, 8, 0  );
		line( histImage, Point( bin_w*(i-1), hist_h - cvRound(b_hist.at(i-1)) ) ,
			Point( bin_w*(i), hist_h - cvRound(b_hist.at(i)) ),
			Scalar( 255, 0, 0), 2, 8, 0  );
	}
	/// 显示直方图
	namedWindow("calcHist Demo", 1);
	imshow("calcHist Demo", histImage );
	imwrite("../calcHist_Demo.bmp", histImage );


	for (int j=0; j(r_hist.at(j));  
		rectangle(rgb_hist[0], Point(j*2+10, rgb_hist[0].rows), Point((j+1)*2+10, rgb_hist[0].rows-val), Scalar(0,0,255),1,8);  

		val = saturate_cast(g_hist.at(j));  
		rectangle(rgb_hist[1], Point(j*2+10, rgb_hist[1].rows), Point((j+1)*2+10, rgb_hist[1].rows-val), Scalar(0,255,0),1,8);  

		val = saturate_cast(b_hist.at(j));  
		rectangle(rgb_hist[2], Point(j*2+10, rgb_hist[2].rows), Point((j+1)*2+10, rgb_hist[2].rows-val), Scalar(255,0,0),1,8);  
	}

	imshow("R", rgb_hist[0]);  
	imshow("G", rgb_hist[1]);  
	imshow("B", rgb_hist[2]);  
	cv::imwrite("../R_Histogram.bmp", rgb_hist[0]);
	cv::imwrite("../G_Histogram.bmp", rgb_hist[1]);
	cv::imwrite("../B_Histogram.bmp", rgb_hist[2]);

	waitKey(0);

	return 0;
}

图像处理之图像直方图_第3张图片

图3 灰度图像(BGR--->GRAY)

图像处理之图像直方图_第4张图片

图4  经过灰度直方图均衡化处理后的图像

对比图3和图4 ,可以明显的看出图4 的整体对比度要比图3 强很多,亮度也要明亮很多。由此可以看出图像直方图均衡化的作用就是:增加像素灰度值的动态范围,增强图像整体对比度。 由此可见,可以通过图像直方图均衡化的方式来达到图像增强的目的。

图像处理之图像直方图_第5张图片

图5  R通道的图像直方图

图像处理之图像直方图_第6张图片

图6  G通道的图像直方图

图像处理之图像直方图_第7张图片

 图7  B通道的图像直方图

图像处理之图像直方图_第8张图片

图8  灰度图像直方图

//绘制H-S二维直方图
int f_HS_hist(cv::Mat src)
{
	//cv::Mat src;
	//src=cv::imread("../baboon.jpg");

	cv::Mat hsv;
	cv::cvtColor(src, hsv, CV_BGR2HSV);
	cv::namedWindow( "HSV", 1 );
	cv::imshow( "HSV", hsv );
	cv::waitKey();
	cv::imwrite("../hsvImg.bmp", hsv );

	// Quantize the hue to 30 levels
	// and the saturation to 32 levels
	int hbins = 256, sbins = 180;
	int histSize[] = {hbins, sbins}; //每个维度的直方图尺寸的数组

	// hue varies from 0 to 179, see cvtColor
	//定义色调变化范围为 0到179
	float hranges[] = { 0, 180 };

	// saturation varies from 0 (black-gray-white) to
	// 255 (pure spectrum color)
	float sranges[] = { 0, 256 };
	const float* ranges[] = { hranges, sranges }; //每一维数值的取值范围
	cv::MatND hist; //输出的目标直方图

	// we compute the histogram from the 0-th and 1-st channels
	int channels[] = {0, 1};//H 通道, S 通道
	cv::calcHist( 
		&hsv, //输入的数组
		1, //数组个数为 1 
		channels, //通道索引
		cv::Mat(), //不使用掩模
		hist, //输出的目标直方图
		2, //需要计算的直方图维数为2
		histSize, //存放每个维度的直方图尺寸的数组
		ranges, //每一维数值的取值范围数组
		true, //指示直方图是否均匀的标识,true表示均匀
		false ); //累计标识,false表示直方图在配置阶段会被清零
	double maxVal=0;
	cv::minMaxLoc(hist, 0, &maxVal, 0, 0);
	int scale = 2;
	cv::Mat histImg = cv::Mat::zeros(sbins*scale, hbins*scale, CV_8UC3);
	//双层循环,绘制直方图
	for( int h = 0; h < hbins; h++ )
	{
		for( int s = 0; s < sbins; s++ )
		{
			float binVal = hist.at(h, s); //直方图直条的值
			int intensity = cvRound(binVal*255/maxVal); //强度
			//正式进行绘制
			cv::rectangle( histImg, cv::Point(h*scale, s*scale),
				cv::Point( (h+1)*scale - 1, (s+1)*scale - 1),
				cv::Scalar::all(intensity), CV_FILLED );
		}
	}

	cv::namedWindow( "Source", 1 );
	cv::imshow( "Source", src );

	cv::namedWindow( "H-S Histogram", 1 );
	cv::imshow( "H-S Histogram", histImg );
	cv::waitKey();
	cv::imwrite("../H-S_hist.bmp", histImg );

	return 0;
}

图像处理之图像直方图_第9张图片

 图9 - HSV图像

图像处理之图像直方图_第10张图片

 图10 - H-S直方图

【不经一番彻骨寒,哪有梅花扑鼻香。】

你可能感兴趣的:(OpenCV,图像处理,opencv,图像处理,直方图)