OPENCV C++(十)gramm矫正+直方图均衡化

两者都是只对单通道使用,对多通道的话 就需要分离通道处理再合并通道

 两种方法,第一个要运算次数太多了,第二个只需要查表

伽马矫正函数,这里用第二种方法,且写法有点高级

int gammaCorrection(cv::Mat srcMat, cv::Mat& dstMat, float gamma) {
	//建立查询表
	unsigned char lut[256];

	for (int i = 0; i < 256; i++)
	{
		//saturate_cast,防止像素值溢出,如果值<0,则返回0,如果大于255,则返回255
		lut[i] = saturate_cast<uchar>(pow((float)(i / 255.0f), gamma) * 255.0f);
	}

	srcMat.copyTo(dstMat);

	MatIterator_<uchar> it, end;
	for (it = dstMat.begin<uchar>(), end = dstMat.end<uchar>(); it != end; it++) {
		*it = lut[(*it)];
	}

	return 0;

}

就是建立了查找表,然后计算查找表,再遍历像素直接赋值查找表,就不用计算了。

	int readType = 0;
	Mat srcMat = imread("kjy.jpg");
	resize(srcMat, srcMat,Size(srcMat.rows*0.5, srcMat.rows * 0.5));
	
	cv::Mat dstMat;
	float gamma = GAMMA_FACTOR;
	if (srcMat.type() == CV_8UC1){
	gammaCorrection(srcMat, dstMat, gamma);
	}
	else {
		Mat channel[3];
		Mat out[3];
		float hist[3][256];

		//通道分离
		split(srcMat, channel);

		for (int i = 0; i < 3; i++) {

			gammaCorrection(channel[i], out[i], gamma);
		}
		merge(out, 3, dstMat);
	}
	imshow("src", srcMat);
	imshow("dst", dstMat);
	waitKey(0);
	destroyAllWindows();

这就是grammar矫正的代码

直方图均衡化(只对单通道有效果)多通道的话先分离通道再合并一样的

equalizeHist(srcMat, equalizeHistMat);

 

计算直方图函数


int calcIntenHist(const cv::Mat src, float* dstHist)
{

	//输入必为单通道图
	if (src.type() != CV_8UC1) {
		return -1;
	}

	memset(dstHist, 0, sizeof(float) * 256);
	int height = src.rows;
	int width = src.cols;
	//指针遍历
	for (int k = 0; k < height; k++)
	{
		// 获取第k行的首地址
		const uchar* inData = src.ptr<uchar>(k);
		//处理每个像素
		for (int i = 0; i < width; i++)
		{
			int gray = inData[i];
			dstHist[gray]++;
		}
	}

	//直方图归一化
	float norm = height * width;
	for (int n = 0; n < 256; n++) {
		dstHist[n] = dstHist[n] / norm;
	}


	return 0;
}

 还进行了归一化

直方图画画函数


int drawIntenHist(cv::Mat& histMat, float* srcHist, int bin_width, int bin_heght)
{
	histMat.create(bin_heght, 256 * bin_width, CV_8UC3);
	histMat = Scalar(255, 255, 255);

	float maxVal = *std::max_element(srcHist, srcHist + 256);

	for (int i = 0; i < 256; i++) {
		Rect binRect;
		binRect.x = i * bin_width;
		float height_i = (float)bin_heght * srcHist[i] / maxVal;
		binRect.height = (int)height_i;
		binRect.y = bin_heght - binRect.height;
		binRect.width = bin_width;
		rectangle(histMat, binRect, CV_RGB(255, 0, 0), -1);
	}

	return 0;
}

 float height_i = (float)bin_heght * srcHist[i] / maxVal;是防止不够高度大小 要进行的高度归一

直方图均衡化的完整代码:

	float srcHist[256];
	float dstHist[256];
	Mat dstHistMat;
	Mat srcHistMat;
	Mat histMat[3];
	Mat equalizeHistMat;
	cv::Mat dstMat1;
	int bin_width = 2;
	int bin_heigth = 100;

	if (srcMat.type() == CV_8UC1) {
		equalizeHist(srcMat, equalizeHistMat);
		imshow("src", srcMat);
		imshow("equalizeHistMat", equalizeHistMat);
		waitKey(0);
		destroyAllWindows();



		calcIntenHist(dstMat1, dstHist);
		drawIntenHist(dstHistMat, dstHist, 3, 100);
		imshow("dstMat hist", dstHistMat);
		calcIntenHist(srcMat, srcHist);
		drawIntenHist(srcHistMat, srcHist, 3, 100);
		imshow("srcMat hist", srcHistMat);
		waitKey(0);
		destroyAllWindows();
	}
	else
	{

		Mat channel[3];
		Mat out[3];
		float hist[3][256];
		split(srcMat, channel);

		for (int i = 0; i < 3; i++) {
			equalizeHist(channel[i], out[i]);
			calcIntenHist(out[i], hist[i]);
			drawIntenHist(histMat[i], hist[i], bin_width, bin_heigth);

			//按照channel编号命名窗口
			stringstream ss;
			ss << i;
			string histWindow = "Hist of chanel " + ss.str();
			string matWindow = "Image of chanel " + ss.str();

			imshow(histWindow, histMat[i]);
			imshow(matWindow, out[i]);

		}

		merge(out, 3, dstMat1);

		cv::Mat grayMat;
		cv::Mat graydstMat;
		cvtColor(srcMat, grayMat, CV_BGR2GRAY);
		cvtColor(dstMat1, graydstMat, CV_BGR2GRAY);

		//计算并绘制直方图
		calcIntenHist(graydstMat, dstHist);
		drawIntenHist(dstHistMat, dstHist, 3, 100);
		imshow("dstMat", dstMat1);
		imshow("dstMat hist", dstHistMat);

		calcIntenHist(grayMat, srcHist);
		drawIntenHist(srcHistMat, srcHist, 3, 100);

		imshow("srcMat hist", srcHistMat);
		imshow("srcMat", srcMat);
		waitKey(0);
		destroyAllWindows();

	}

		return 0;
		
	}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值