直方图均衡化实现图像增强

环境:vs2019+OpenCV4.5.1

实验内容:对图像进行对数变换和直方图均衡化处理,显示两种方法处理后的图像直方图

#include<opencv2/opencv.hpp>
#include<iostream>
#include<vector>

using namespace cv;
using namespace std;

Mat Histogram_Display(Mat& srcImage);
void logTransform1(cv::Mat srcImage, int c);
Mat equahist(const cv::Mat& image, cv::Mat& result);
int main()
{
	//灰
	Mat srcImage = imread("d:\\images\\Gray.jpg");
	 
	//亮
	//Mat srcImage = imread("d:\\images\\bright1.png");
	 
	//彩色
	//Mat srcImage = imread("d:\\images\\lena.jpg");
	Mat result;

	imshow("【原图】", srcImage);
	Mat yuan = Histogram_Display(srcImage);
	imshow("【原图直方图】", yuan);

	//均衡化处理
	Mat equahistResult = equahist(srcImage, result);
	imshow("【均衡化】", equahistResult);
	Mat equahistHistogram = Histogram_Display(equahistResult);
	imshow("【均衡化直方图】", equahistHistogram);


	//对数
	//对数变换实现了扩展低灰度值而压缩高灰度值的效果 此时a大于1
	float c = 2;
	logTransform1(srcImage, c);

	waitKey(0);

	return 0;
}
//均衡化处理
Mat equahist(const cv::Mat& image, cv::Mat& result)
{
	double count[256] = { 0 };
	//这个意思是声明mymax并对i进行初始化为0
	long mymax(0);
	float map[256] = { 0 };
	//创建一个指定大小(Size),指定类型 type(CV_8UC1, CV_16SC1, CV_32FC3)的图像矩阵的矩阵体
	result.create(image.size(), image.type());
	long x, y;
	/*
	行列与坐标系对应关系 
	行rows:Y (height)
	列cols:X (width)
	注意!注意!注意! 
	在Mat类型变量访问时下标是反着写的,即:按照(y, x)的关系形式访问
	*/
	//cols 列 x
	int w = image.cols * image.channels();
	//rows y
	int h = image.rows;
	for (y = 0; y < h; y++)
		for (x = 0; x < w; x++) {
			//当图像连通时,我们就可以把图像完全展开,看成是一行。此时调用Mat::ptr<>()方法就等价于Mat::data

			count[*(image.data + y * w + x)]++;
		}
	//感觉这个循环的作用是把每个像素点变成浮点型,方便下个循环将累计直方图进行区间转换
	for (int i = 0; i < 256; i++)
	{
		map[i] = 0;
		float t = 0;
		for (int j = 0; j <= i; j++)
		{
			t += 1.0 * count[j] / w / h;
		}
		map[i] = t;
	}
	for (int y = 0; y < h; y++)
		for (int x = 0; x < w; x++)
		{
			/*
			saturate_cast<uchar>此处为溢出保护,此处相当于 在剪切数值
			>255    赋值为255;
			<0        赋值为0;
			*/
			result.data[y * w + x] = cv::saturate_cast<uchar>(map[*(image.data + y * w+ x)] * 255);
		}
	return result;
}


//显示直方图
Mat Histogram_Display(Mat& srcImage)
{


	//为计算直方图配置变量
	//首先是需要计算的图像的通道,就是需要计算图像的哪个通道(bgr空间需要确定计算 b或g货r空间)
	int channels = 0;
	//然后是配置输出的结果存储的 空间 ,用MatND类型来存储结果
	MatND dstHist;
	//接下来是直方图的每一个维度的 柱条的数目(就是将数值分组,共有多少组)
	int histSize[] = { 256 };		//如果这里写成int histSize = 256;   那么下面调用计算直方图的函数的时候,该变量需要写 &histSize
	//最后是确定每个维度的取值范围,就是横坐标的总数
	//首先得定义一个变量用来存储 单个维度的 数值的取值范围
	float midRanges[] = { 0, 256 };
	const float* ranges[] = { midRanges };

	calcHist(&srcImage, 1, &channels, Mat(), dstHist, 1, histSize, ranges, true, false);

	//calcHist  函数调用结束后,dstHist变量中将储存了 直方图的信息  用dstHist的模版函数 at<Type>(i)得到第i个柱条的值
	//at<Type>(i, j)得到第i个并且第j个柱条的值

	//开始直观的显示直方图——绘制直方图
	//首先先创建一个黑底的图像,为了可以显示彩色,所以该绘制图像是一个8位的3通道图像
	Mat drawImage = Mat::zeros(Size(256, 256), CV_8UC3);
	//因为任何一个图像的某个像素的总个数,都有可能会有很多,会超出所定义的图像的尺寸,针对这种情况,先对个数进行范围的限制
	//先用 minMaxLoc函数来得到计算直方图后的像素的最大个数
	double g_dHistMaxValue;
	//minMaxLoc 函数的作用是在数组中找到全局最小和最大值
	minMaxLoc(dstHist, 0, &g_dHistMaxValue, 0, 0);
	//将像素的个数整合到 图像的最大范围内
	//遍历直方图得到的数据
	for (int i = 0; i < 256; i++)
	{
		//cvRound 返回和参数最接近的整数值
		int value = cvRound(dstHist.at<float>(i) * 256 * 0.9 / g_dHistMaxValue);
		/*
		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,
		*/
		line(drawImage, Point(i, drawImage.rows - 1), Point(i, drawImage.rows - 1 - value), Scalar(255, 0, 0));
	}

	return drawImage;


}


// 对数变换方法1
void logTransform1(cv::Mat srcImage, int c)
{
	// 输入图像判断
	if (srcImage.empty())
		std::cout << "No data!" << std::endl;
	cv::Mat resultImage =
		cv::Mat::zeros(srcImage.size(), srcImage.type());
	// 计算 1 + r
	cv::add(srcImage, cv::Scalar(1.0), srcImage);
	// 转换为32位浮点数
	srcImage.convertTo(srcImage, CV_32F);
	// 计算 log(1 + r)
	log(srcImage, resultImage);
	resultImage = c * resultImage;
	// 归一化处理
	cv::normalize(resultImage, resultImage,
		0, 255, cv::NORM_MINMAX);
	cv::convertScaleAbs(resultImage, resultImage);
	imshow("【log图】", resultImage);
	Mat logImages = Histogram_Display(resultImage);
	imshow("【log直方图】", logImages);
}

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值