OpenCV数字图像处理基于C++:直方图修正

直方图修正

1、 灰度直方图

灰度直方图表示一幅图像分布情况的统计图表。直方图的横坐标是灰度级,一般用r表示,纵坐标是具有该灰度级的像素个数或出现这个灰度级的概率P。

img

N为一幅图像种像素的总数,img为第k集灰度的像素,img为第k个灰度级,img表示该灰度级出现的概率。对于相同的场景,由于获得图像时的亮度或对比度不同,所对应的直方图也不同。可以通过改变直方图的形状来达到增强图像对比度的效果。

直方图的常见用途:

1、数字化参数。描述图像整体灰度分布,判断灰度的利用量。

2、边界的阈值选取。图片中不同物体具有不同峰值区域,取直方图峰谷为阈值点可以实现边界分离与二值化处理。

1.1 实现灰度直方图

void calcHist(
	const Mat* images, 
	int nimages, 
	const int* channels, 
	InputArray mask, 
	OutputArray hist, 
	int dims, 
	const int* histSize, 
	const float** ranges, 
	bool uniform=true, 
	bool accumulate=false 
)
参数详解:
onst Mat* images:输入图像
int nimages:输入图像的个数
const int* channels:需要统计直方图的第几通道
InputArray mask:掩膜,,计算掩膜内的直方图  ...Mat()
OutputArray hist:输出的直方图数组
int dims:需要统计直方图通道的个数
const int* histSize:指的是直方图分成多少个区间,就是 bin的个数
const float** ranges: 统计像素值得区间
bool uniform=true::是否对得到的直方图数组进行归一化处理
bool accumulate=false:在多个图像时,是否累计计算像素值得个数
#include<opencv2/opencv.hpp>
#include<opencv2/imgproc/types_c.h>  //CV_RGB2GRAY
#include<iostream>

using namespace cv;
using namespace std;


//绘制灰度直方图
int main(int    argc, char* argv[])
{
	Mat src, gray;
	if (argc == 1)
		src = imread("E:\\Lena.jpg");  //读取工程目录下的p1.jpg图片
	else if (argc == 2)
		src = imread(argv[1]);

	if (src.empty()) //判断原图是否加载成功
	{
		cout << "图像加载失败" << endl;
		return -1;
	}
	cvtColor(src, gray, CV_RGB2GRAY);   //转换为灰度图
	int bins = 256;
	int hist_size[] = { bins };
	float range[] = { 0, 256 };
	const float* ranges[] = { range };
	MatND hist;
	int channels[] = { 0 };
	//计算出灰度直方图
	calcHist(&gray, 1, channels, Mat(), // do not use mask
		hist, 1, hist_size, ranges,
		true, // the histogram is uniform
		false);
	//画出直方图
	double max_val;
	minMaxLoc(hist, 0, &max_val, 0, 0);  //定位矩阵中最小值、最大值的位置
	int scale = 2;
	int hist_height = 256;
	Mat hist_img = Mat::zeros(hist_height, bins * scale, CV_8UC3); //创建一个全0的特殊矩阵
	for (int i = 0; i < bins; i++)
	{
		float bin_val = hist.at<float>(i);
		int intensity = cvRound(bin_val * hist_height / max_val);  //要绘制的高度
		rectangle(hist_img, Point(i * scale, hist_height - 1),  //画矩形
			Point((i + 1) * scale - 1, hist_height - intensity),
			CV_RGB(255, 255, 255));
	}
	//显示原图和直方图
	imshow("原图片", src);
	imshow("灰度直方图", hist_img);
	waitKey(10000000000);
	return 0;
}

image-20221006134105218

int main()
{
	Mat image, image_gray, hist;   //定义输入图像,灰度图像, 直方图
	image = imread("E:\\Lena.jpg");  //读取图像;
	if (image.empty())
	{
		cout << "读取错误" << endl;
		return -1;
	}

	cvtColor(image, image_gray, COLOR_BGR2GRAY);  //灰度化
	imshow(" image_gray", image_gray);   //显示灰度图像

	//获取图像直方图
	int histsize = 256;
	float ranges[] = { 0,256 };
	const float* histRanges = { ranges };
	calcHist(&image_gray, 1, 0, Mat(), hist, 1, &histsize, &histRanges, true, false);

	//创建直方图显示图像
	int hist_h = 300;//直方图的图像的高
	int hist_w = 512; //直方图的图像的宽
	int bin_w = hist_w / histsize;//直方图的等级
	Mat histImage(hist_h, hist_w, CV_8UC3, Scalar(0, 0, 0));//绘制直方图显示的图像

	//绘制并显示直方图
	normalize(hist, hist, 0, hist_h, NORM_MINMAX, -1, Mat());//归一化直方图
	for (int i = 1; i < histsize; i++)
	{
		line(histImage, Point((i - 1) * bin_w, hist_h - cvRound(hist.at<float>(i - 1))),
			Point((i)*bin_w, hist_h - cvRound(hist.at<float>(i))), Scalar(255, 0, 0), 2, 8, 0);
	}
	imshow("histImage", histImage);

	waitKey(0);  //暂停,保持图像显示,等待按键结束
	return 0;
}

image-20221006134601616

图像灰度化的目的是为了简化矩阵,提高运算速度。
有时图片进行了灰度处理后还是很大,也有可能会采用二值化图像(即像素值只能为0或1)。
void cvLine( CvArr* img,
        	 CvPoint pt1, 
			 CvPoint pt2, 
			 CvScalar color,
			 int thickness=1, 
			 int line_type=8, 
			 int shift=0 
			 );
第一个参数img:要划的线所在的图像;
第二个参数pt1:直线起点
第二个参数pt2:直线终点
第三个参数color:直线的颜色 e.g:Scalor(0,0,255)
第四个参数thickness=1:线条粗细
第五个参数line_type=8, 
   8 (or 0) - 8-connected line(8邻接)连接 线。
   4 - 4-connected line(4邻接)连接线。
   CV_AA - antialiased 线条。
第六个参数:坐标点的小数点位数。

2、直方图均衡化

2.1 介绍

直方图均衡化是一种简单有效的图像增强技术,通过改变图像的直方图来改变图像中各像素的灰度,主要用于增强动态范围偏小的图像的对比度。原始图像由于其灰度分布可能集中在较窄的区间,造成图像不够清晰。例如,过曝光图像的灰度级集中在高亮度范围内,而曝光不足将使图像灰度级集中在低亮度范围内。**采用直方图均衡化,可以把原始图像的直方图变换为均匀分布(均衡)的形式,这样就增加了像素之间灰度值差别的动态范围,从而达到增强图像整体对比度的效果。**换言之,直方图均衡化的基本原理是:对在图像中像素个数多的灰度值(即对画面起主要作用的灰度值)进行展宽,而对像素个数少的灰度值(即对画面不起主要作用的灰度值)进行归并,从而增大对比度,使图像清晰,达到增强的目的。

2.2 直方图均衡化的具体步骤

直方图均衡化是采用灰度级r 的累积分布函数作为变换函数的直方图修正法。

假设用p ( r )表示原图像灰度级r的灰度级概率密度函数,直方图均衡化变换函数为:

image-20221006142001136

T®是r的累积分布函数,随着r增大,s值单调增加,最大为1。
具体步骤:

(1)计算每个灰度值的像素个数img,即每个灰度在所有像素中出现了几次;

(2)计算原图像的灰度累计分布函数img

img

(3)求出灰度变换表img

img

其中,image-20221006142457574为第k个灰度级别变换后的灰度值,0.5的作用是四舍五入。

(4)根据灰度变换表将原图像各灰度级映射为新的灰度级,即可完成直方图均衡化。

image-20221006144806460

2.3 实现直方图均衡化

不使用已有函数实现直方图均衡化

int main(int argc, char** argv)
{
	Mat src = imread("E:\\Lena.jpg",0);
	imshow("原图", src);

	
	int Total = src.total();	// 总像素的个数
	
	//统计各像素数量
	vector<int> nk(256, 0);

	//1. 统计每种灰度对应的像素数量,比如灰度为0的像素数量
	for (int i = 0; i < Total; i++) {
		nk[src.data[i]]++;		//src.data[i] 表示第i个像素的灰度值,范围为0~255
	}

	//2. 执行完这个for循环,nk[i]相当于公式中的累积积分分布函数sk
	for (int i = 1; i < 256; i++) {
		nk[i] += nk[i - 1];
	}

	//3. 重新建立映射关系
	vector<int> new_nk(256, 0);		
	for (int i = 0; i < 256; i++) {
		new_nk[i] = (double(nk[i]) / Total) * 255;	//均值后像素值
	}

	for (int i = 0; i < src.total(); i++) {
		src.data[i] = new_nk[src.data[i]];
	}
	imshow("直方图均值后", src);

	waitKey(0);
	return 0;
}
//均值函数,直接调用
Mat junzhi(Mat &src) {
	int Total = src.total();	// 总像素的个数

	//统计各像素数量
	vector<int> nk(256, 0);

	//1. 统计每种灰度对应的像素数量,比如灰度为0的像素数量
	for (int i = 0; i < Total; i++) {
		nk[src.data[i]]++;		//src.data[i] 表示第i个像素的灰度值,范围为0~255
	}

	//2. 执行完这个for循环,nk[i]相当于公式中的累积积分分布函数sk
	for (int i = 1; i < 256; i++) {
		nk[i] += nk[i - 1];
	}

	//3. 重新建立映射关系
	vector<int> new_nk(256, 0);
	for (int i = 0; i < 256; i++) {
		new_nk[i] = (double(nk[i]) / Total) * 255;	//均值后像素值
	}

	for (int i = 0; i < src.total(); i++) {
		src.data[i] = new_nk[src.data[i]];
	}
	return src;
}

image-20221006145429979

image-20221006145631751

使用已有函数实现直方图均衡化

int main(int argc, char** argv)
{
	Mat src = imread("E:\\Lena.jpg");
	

	imshow("原图", src);

	Mat gray,dst;
	cvtColor(src, gray, COLOR_BGR2GRAY);
	
;	imshow("灰度图", gray);
	equalizeHist(gray, dst);
	
	imshow("直方图均衡化", dst);
	
	waitKey(0);
	return 0;
}

使用已有函数实现直方图均衡化*

int main(int argc, char** argv)
{
	Mat src = imread("E:\\Lena.jpg");
	

	imshow("原图", src);

	Mat gray,dst;
	cvtColor(src, gray, COLOR_BGR2GRAY);
	
;	imshow("灰度图", gray);
	equalizeHist(gray, dst);
	
	imshow("直方图均衡化", dst);
	
	waitKey(0);
	return 0;
}

image-20221006150117077

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值