图像处理之灰度变换(C++)

图像处理之灰度变换(C++)



前言

灰度变换是将图像的灰度级从一个范围映射到另一个范围的操作,从而实现调整图像的亮度和对比度,增强图像的细节和视觉效果。灰度级是指图像中像素的亮度或者灰度值的程度。
灰度变换增强(线性灰度变换、分段线性灰度变换、非线性灰度变换)C++实现。


一、线性灰度变换

1.原理

线性灰度变换的公式: g(x,y) = a*f(x,y) + b
其中,g(x,y)为变换后的灰度值,f(x,y)为原始灰度值,a和b为常数。通过调整a和b的值,可以实现不同的灰度变换效果。
常见的线性灰度变换包括亮度增强、对比度增强、灰度拉伸等操作。例如,
如果要进行亮度增强,可以选择a>1,b=0;
如果要进行对比度增强,可以选择a>1,b=(1-a)*128。

2.代码实现

#include <iostream>
#include <opencv.hpp>
using namespace std;

/*
* @param cv::Mat src	输入图像
* @param cv::Mat& dst	输出图像
* @breif 灰度线性变换
*/
void LinearGrayTrans(const cv::Mat& src,cv::Mat& dst,float a,float b)
{
	//建立灰度映射表
	float grayTable[256];
	for (int i = 0; i < 256; i++)
		grayTable[i] = a * i + b;

	//遍历修改灰度值
	//为了防止发生截断(像素值超过255或者小于0),对dst图像进行数据类型转换
	//dst.convertTo(dst, CV_16FC1);
	int temp = 0;
	for(int i=0;i<src.rows;i++)
		for (int j = 0; j < src.cols; j++)
		{
			temp = src.at<uchar>(i, j);
			dst.at<float>(i, j) = grayTable[temp];
		}
	//将数据缩放到0-255
	cv::normalize(dst, dst, 0, 255, cv::NORM_MINMAX);
	//dst的数据类型还原为CV_8UC1
	dst.convertTo(dst,CV_8UC1);
}

int main()
{
	// 读取图片
	string filepath = "F://work_study//algorithm_demo//zidane.jpg";
	cv::Mat src = cv::imread(filepath,cv::IMREAD_GRAYSCALE);
	if (src.empty())
	{
		return -1;
	}

	//注意:大坑!因为CV_16FC1是为了深度学习引入的,所以在后续的其他函数不支持。更改数据类型为CV_32FC1
	cv::Mat dst(src.size(), CV_32FC1);		

	LinearGrayTrans(src,dst,1.45,15.0);
	
	// 显示图片
	cv::imshow("dst", dst); 
	
	system("pause");
	return 0;
}

二、分段线性灰度变换

1.原理

分段线性变换是指在不同的区间内,使用不同的线性函数进行变换。其公式可以表示为:
分段线性函数公式
其中,a1、a2分别为不同区间内的斜率,b1、b2分别为不同区间内的截距,x1为灰度变换灰度值分界点。根据实际需要,可以有多个分段和不同的线性函数。

2.代码实现

/*
* @param cv::Mat src	输入图像
* @param cv::Mat& dst	输出图像
* @param float a1,b1	第一段分段变换直线的斜率和截距
* @param float a2,b2	第二段分段变换直线的斜率和截距
* @param int x			分段变换灰度值临界点,范围是[0,255]
* @breif 分段灰度线性变换
*/
void PieceLinearGrayTrans(const cv::Mat& src, cv::Mat& dst, float a1, float b1,float a2,float b2,int x)
{
	//建立灰度映射表
	float grayTable[256];
	for (int i = 0; i < 256; i++)
	{
		if(i<x)
			grayTable[i] = a1 * i + b1;
		else 
			grayTable[i] = a2 * i + b2;
	}
		

	//遍历修改灰度值
	//为了防止发生截断(像素值超过255或者小于0),对dst图像进行数据类型转换
	//dst.convertTo(dst, CV_16FC1);
	int temp = 0;
	for (int i = 0; i < src.rows; i++)
		for (int j = 0; j < src.cols; j++)
		{
			temp = src.at<uchar>(i, j);
			dst.at<float>(i, j) = grayTable[temp];
		}
	//将数据缩放到0-255
	cv::normalize(dst, dst, 0, 255, cv::NORM_MINMAX);
	//dst的数据类型还原为CV_8UC1
	dst.convertTo(dst, CV_8UC1);
}



int main()
{
	// 读取图片
	string filepath = "F://work_study//algorithm_demo//zidane.jpg";
	cv::Mat src = cv::imread(filepath,cv::IMREAD_GRAYSCALE);
	if (src.empty())
	{
		return -1;
	}

	//注意:大坑!因为CV_16FC1是为了深度学习引入的,所以在后续的其他函数不支持。更改数据类型为CV_32FC1
	cv::Mat dst(src.size(), CV_32FC1);		

	PieceLinearGrayTrans(src,dst,1.45,15.0,1.5,25,100);
	
	// 保存图片
	cv::imwrite("dst.jpg", dst); 
	
	system("pause");
	return 0;
}

三、非线性灰度变换(对数变换、伽马变换)

1.原理

1.1 对数变换

对数变换(Logarithmic Transformation)是一种将图像的亮度值进行对数运算的方法,可以增强图像的暗部细节。其原理是通过对亮度值进行对数变换,将较大亮度的像素值压缩到较小范围,同时增强较小亮度的像素值。对数变换的公式为:

									s = c * log(1 + v*r)

其中,s为变换后的亮度值,r为原始亮度值,c为常数,用于调控变换的幅度,v为系数。

1.2 伽马变换

伽马变换(Gamma transformations)的原理是通过对原始数据进行幂次运算,改变数据的幅度范围,从而使得数据更加符合人眼对亮度的感知。幂次变换的公式为:

									s = c*(r ^ γ)

其中,c为常数,r为原始数据,s为变换后的数据,γ为幂次指数。
当γ>1时,幂次变换将增强较暗的像素值,减弱较亮的像素值;
当γ<1时,幂次变换将增强较亮的像素值,减弱较暗的像素值;
当γ=1时,幂次变换不对像素值进行变换。

2.代码实现

1.1 对数变换

/*
* @param cv::Mat src	输入图像
* @param cv::Mat& dst	输出图像
* @param float c		常数,用于控制变换幅度
* @param float v		系数
* @breif 对数变换
*/
void LogGrayTrans(const cv::Mat& src, cv::Mat& dst,float c,float v)
{
	//建立灰度映射表
	float grayTable[256];
	for (int i = 0; i < 256; i++)
	{
		grayTable[i] = c*log(1 + v * i);
	}


	//遍历修改灰度值
	//为了防止发生截断(像素值超过255或者小于0),对dst图像进行数据类型转换
	//dst.convertTo(dst, CV_16FC1);
	int temp = 0;
	for (int i = 0; i < src.rows; i++)
		for (int j = 0; j < src.cols; j++)
		{
			temp = src.at<uchar>(i, j);
			dst.at<float>(i, j) = grayTable[temp];
		}
	//将数据缩放到0-255
	cv::normalize(dst, dst, 0, 255, cv::NORM_MINMAX);
	//dst的数据类型还原为CV_8UC1
	dst.convertTo(dst, CV_8UC1);
}

int main()
{
	// 读取图片
	string filepath = "F://work_study//algorithm_demo//zidane.jpg";
	cv::Mat src = cv::imread(filepath,cv::IMREAD_GRAYSCALE);
	if (src.empty())
	{
		return -1;
	}

	//注意:大坑!因为CV_16FC1是为了深度学习引入的,所以在后续的其他函数不支持。更改数据类型为CV_32FC1
	cv::Mat dst(src.size(), CV_32FC1);		

	LogGrayTrans(src, dst, 2, 4);
	
	// 保存图片
	cv::imwrite("dst.jpg", dst); 
	
	system("pause");
	return 0;
}

1.2 伽马变换

/*
* @param cv::Mat src	输入图像
* @param cv::Mat& dst	输出图像
* @param float c		常数,用于控制变化幅度
* @param float gamma	指数
* @breif 伽马变换
*/
void GammaLinearGrayTrans(const cv::Mat & src, cv::Mat & dst, float c, float gamma)
{
	//建立灰度映射表
	float grayTable[256];
	for (int i = 0; i < 256; i++)
	{
		grayTable[i] = c*pow(i,gamma);
	}


	//遍历修改灰度值
	//为了防止发生截断(像素值超过255或者小于0),对dst图像进行数据类型转换
	//dst.convertTo(dst, CV_16FC1);
	int temp = 0;
	for (int i = 0; i < src.rows; i++)
		for (int j = 0; j < src.cols; j++)
		{
			temp = src.at<uchar>(i, j);
			dst.at<float>(i, j) = grayTable[temp];
		}
	//将数据缩放到0-255
	cv::normalize(dst, dst, 0, 255, cv::NORM_MINMAX);
	//dst的数据类型还原为CV_8UC1
	dst.convertTo(dst, CV_8UC1);
}

int main()
{
	// 读取图片
	string filepath = "F://work_study//algorithm_demo//zidane.jpg";
	cv::Mat src = cv::imread(filepath,cv::IMREAD_GRAYSCALE);
	if (src.empty())
	{
		return -1;
	}

	//注意:大坑!因为CV_16FC1是为了深度学习引入的,所以在后续的其他函数不支持。更改数据类型为CV_32FC1
	cv::Mat dst(src.size(), CV_32FC1);		

	GammaGrayTrans(src, dst, 2, 4);
	
	// 保存图片
	cv::imwrite("dst.jpg", dst); 
	
	system("pause");
	return 0;
}

总结

本文主要讲解了几种常见的图像变换方法,主要包括线性变换、非线性变换、以及分段变换,关于参数的选择需要通过实验确定,也可以将各种方法组合,比如分段变换不仅仅是线性的。`
因为笔者水平有限,有错误欢迎指出,代码本人均在本地运行实验正确,大家放心使用。

  • 24
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值