5.3线性(灰度)变换

目录

实验原理

线性灰度变换的目的

OpenCV中的实现方法

实验代码

方法二:灰度图像线性变换

方法二:彩色图像线性变换

运行结果

方法一:Mat::convertTo


实验原理

在OpenCV中,线性灰度变换是一种常见的图像处理技术,用于调整图像的对比度和亮度。这种变换通过简单的线性函数来调整图像中的像素值,从而达到增强或减弱图像对比度的效果。线性灰度变换的基本形式可以表示为:

g(x)=αf(x)+β

其中:
f(x) 是输入图像中的像素值。
g(x) 是输出图像中的像素值。
α 是缩放因子,用于控制对比度。
β 是偏移量,用于控制亮度。

线性灰度变换的目的

线性灰度变换主要用于以下几个方面:

1.调整对比度:通过调整 α 的值,可以使图像的对比度变强或变弱。

2.调整亮度:通过调整 β 的值,可以使图像整体变得更亮或更暗。

OpenCV中的实现方法

在OpenCV中,可以使用多种方法来实现线性变换,以下是两种常用的方法:

方法一:使用 convertTo 函数convertTo 函数可以直接应用于矩阵,对每个像素值进行线性变换。

convertTo 函数可以直接应用于矩阵,对每个像素值进行线性变换。// 读取图像
cv::Mat src = cv::imread("input_image.jpg", cv::IMREAD_GRAYSCALE);

// 定义线性变换参数
double alpha = 1.5; // 对比度因子
double beta = 50;   // 亮度偏移量

// 创建输出图像
cv::Mat dst;

// 应用线性变换
src.convertTo(dst, -1, alpha, beta);

方法二:手动遍历每个像素如果需要更多的控制,可以手动遍历每个像素并应用线性变换。

// 读取图像
cv::Mat src = cv::imread("input_image.jpg", cv::IMREAD_GRAYSCALE);

// 定义线性变换参数
double alpha = 1.5; // 对比度因子
double beta = 50;   // 亮度偏移量

// 创建输出图像
cv::Mat dst = cv::Mat::zeros(src.size(), src.type());

// 遍历每个像素并应用线性变换
for (int y = 0; y < src.rows; y++)
{
    for (int x = 0; x < src.cols; x++)
    {
        dst.at<uchar>(y, x) = std::min(255, std::max(0, (int)(alpha * src.at<uchar>(y, x) + beta)));
//std::min() 和 std::max() 函数在这里的作用是确保像素值保持在有效的范围内。
//在C++标准库中,std::min() 函数返回两个或多个值中的最小值,而 std::max() 返回最大值。
//src.at<uchar>(y, x) 获取源图像 (y, x) 坐标的像素值。
//alpha * src.at<uchar>(y, x) 应用了一个线性变换来调整像素值,这通常用于调整对比度。
//+ beta 用于调整亮度。
//(int) 强制转换确保结果是一个整数。
//由于像素值必须在 0 到 255 之间(对于8位无符号整数),
//因此需要使用 std::max(0, ...) 来确保结果不会小于 0,以及 std::min(255, ...) 来确保结果不会大于 255。
    }
}

实现细节

1. 数据类型:在进行线性变换时需要注意数据类型。通常情况下,灰度图像的像素值类型为 uchar(无符号8位整数),因此需要确保变换后的值在 [0, 255] 范围内。

2. 饱和操作:在手动实现时,需要使用 std::min 和 std::max 函数来确保像素值不会超出有效范围。

实验代码

方法二:灰度图像线性变换

#include "pch.h"
#include <iostream>
#include<opencv2/opencv.hpp>
using namespace cv;  //所有opencv类都在命名空间cv下
using namespace std;
//#pragma comment(lib, "opencv_world450d.lib")  //引用引入库 

// 图像线性变换操作
cv::Mat linearTransform(cv::Mat srcImage, float a, int b)
{
    if(srcImage.empty()){  
        std::cout<< "No data!" <<std::endl;  
    } 
    const int nRows = srcImage.rows;
    const int nCols = srcImage.cols;
    cv::Mat resultImage = 
		cv::Mat::zeros(srcImage.size(), srcImage.type());
    // 图像元素遍历
    for( int i = 0; i < nRows; i++ )
    {
        for( int j = 0; j < nCols; j++ )
        {
           
                // 矩阵at操作,检查下标防止越界
				resultImage.at<uchar>(i, j) = saturate_cast<uchar>(a * (srcImage.at<uchar>(i, j)) + b);
           
//saturate_cast主要是为了防止颜色溢出操作,保证颜色在[0,255]范围内
           
        }
    }
    return resultImage;
}
int main()
{
    // 图像获取及验证
    //cv::Mat srcImage = cv::imread("123.jpg"); 
	cv::Mat srcImage = cv::imread("123.jpg",cv::IMREAD_GRAYSCALE);//由imread()得到的灰度图像
    if(!srcImage.data) 
       return -1;
    cv::imshow("原图", srcImage);
    cv::waitKey(2000);
    // 线性变换
    float a = 1.2;
    int b = 50;
    cv::Mat new_image  = linearTransform(srcImage, a, b);  
    cv::imshow("效果图", new_image);
    cv::waitKey(0);
    return 0;
}
saturate_cast 函数
在 OpenCV 中被用来进行类型转换,同时确保转换后的值不会超出目标类型的表示范围。
这个函数特别适用于图像处理中的像素值转换,以避免溢出或下溢(underflow)的问题。
saturate_cast<uchar>(...) 将计算结果转换为 uchar 类型(即无符号8位整数),并且确保该值在0到255的范围内。

具体来说,saturate_cast 的行为如下:

如果计算结果大于 uchar 类型的最大值(255),则返回 255。
如果计算结果小于 uchar 类型的最小值(0),则返回 0。
如果计算结果在有效范围内,则直接进行转换。

例如:

如果计算结果是 260,saturate_cast<uchar> 会将其截断为 255。
如果计算结果是 -10,saturate_cast<uchar> 会将其截断为 0。

使用 saturate_cast 可以简化代码,并且保证图像处理过程中的像素值总是有效的,
避免了手动使用 std::min 和 std::max 来限制范围的需要。

方法二:彩色图像线性变换

#include "pch.h"
#include <iostream>
#include<opencv2/opencv.hpp>
using namespace cv;  //所有opencv类都在命名空间cv下
using namespace std;
//#pragma comment(lib, "opencv_world450d.lib")  //引用引入库 

// 图像线性变换操作
cv::Mat linearTransform(cv::Mat srcImage, float a, int b)
{
    if(srcImage.empty()){  
        std::cout<< "No data!" <<std::endl;  
    } 
    const int nRows = srcImage.rows;
    const int nCols = srcImage.cols;
    cv::Mat resultImage = 
        cv::Mat::zeros(srcImage.size(), srcImage.type());
    // 图像元素遍历
    for( int i = 0; i < nRows; i++ )
    {
        for( int j = 0; j < nCols; j++ )
        {
            for( int c = 0; c < 3; c++ )//如果源图像是灰度图,那么把这里改为c<1即可
            {
                // 矩阵at操作,检查下标防止越界
                resultImage.at<Vec3b>(i,j)[c] = saturate_cast<uchar>(a * (srcImage.at<Vec3b>(i,j)[c]) + b);
            }
        }
    }
    return resultImage;
}
int main()
{
    // 图像获取及验证
    cv::Mat srcImage = cv::imread("123.jpg"); 
    if(!srcImage.data) 
       return -1;
    cv::imshow("原图", srcImage);
    //cv::waitKey(0);
    // 线性变换
    float a = 1.2;
    int b = 50;
    cv::Mat new_image  = linearTransform(srcImage, a, b);  
    cv::imshow("效果图", new_image);
    cv::waitKey(0);
    return 0;
}

运行结果

方法一:Mat::convertTo

此外利用 Mat::convertTo 函数进行数据类型转换和简单的线性变换。

在OpenCV中,Mat::convertTo 函数用于将一个矩阵(通常是图像)的数据类型转换为另一种数据类型,并且可以选择性地对矩阵中的每个元素进行缩放和偏移。这个函数非常有用,特别是在需要改变图像数据类型、调整像素值范围或进行线性变换的时候。

函数原型
void Mat::convertTo(OutputArray m, int rtype, double alpha=1, double beta=0) const;

参数说明
OutputArray m:目标矩阵。如果在调用该函数之前目标矩阵的尺寸或类型不合适,那么该矩阵会被重新分配内存。
int rtype:期望的目标矩阵类型或深度。这里“深度”指的是每个元素的数据类型(如 CV_8U、CV_32F 等)。通道数保持不变。如果 rtype 是负数,则目标矩阵将具有与源矩阵相同的类型。
double alpha:可选的比例因子,默认值为 1。该参数用于缩放矩阵中的每个元素。
double beta:可选的偏移量,默认值为 0。该参数用于给缩放后的每个元素加上一个常数值。


工作原理
Mat::convertTo 方法根据提供的参数对矩阵中的每个元素执行以下操作:

1.每个元素先乘以 alpha。
2.然后加上 beta。
3.最后,将结果转换为目标类型 rtype,并且使用 saturate_cast<> 函数确保结果值不会超出目标类型的有效范围。

转换公式:
m(x,y)=saturate_cast<rType>(α⋅src(x,y)+β)
这里的 saturate_cast<> 函数的作用是将结果裁剪到目标类型能够表示的最小值和最大值之间,以避免溢出。

例题

下面是一个简单的示例,演示如何使用OpenCV和C++实现灰度图像的线性变换。我们将实现以下功能:

1. 读取灰度图像。

2. 应用线性变换:通过增加亮度和调整对比度。

3. 显示和保存变换后的图像。

#include "pch.h"
#include <iostream>
#include<opencv2/opencv.hpp>
using namespace cv;  //所有opencv类都在命名空间cv下
using namespace std;
//#pragma comment(lib, "opencv_world450d.lib")  //引用引入库 

int main()
{
	// 图像获取及验证
	//cv::Mat srcImage = cv::imread("123.jpg"); 
	cv::Mat srcImage = cv::imread("09011913.jpeg", cv::IMREAD_GRAYSCALE);//由imread()得到的灰度图像
	if (!srcImage.data)
		return -1;

	//显示变换前的原图
	namedWindow("原图", WINDOW_NORMAL);
	cv::imshow("原图", srcImage);
	
	
	// 定义线性变换的参数
	double alpha= 1.5;//对比度因子
	double beta= 50;//亮度偏移量
	
	//创建输出图像
	cv::Mat dst_image;
	//应用线性变换
	srcImage.convertTo(dst_image, -1, alpha, beta);

	//显示变换后的图像
	namedWindow("效果图", WINDOW_NORMAL);
	cv::imshow("效果图", dst_image);

	cv::waitKey(0);
	return 0;
}

代码解释

1. 读取图像:使用cv::imread函数读取输入图像,并将其转换为灰度图像(IMREAD_GRAYSCALE)。

2. 定义线性变换参数:

•alpha:对比度因子,用于调整图像的对比度。alpha > 1会使图像更亮,alpha < 1会使图像更暗。

•beta:亮度偏移量,用于增加图像的亮度。beta > 0会使图像更亮,beta < 0会使图像更暗。

3. 创建输出图像:创建一个新的cv::Mat对象来存储变换后的图像。

4. 应用线性变换:使用convertTo函数来应用线性变换。convertTo函数的第一个参数是输出图像,第二个参数是深度(-1 表示保持源图像的深度不变),第三个参数是对比度因子(alpha),第四个参数是亮度偏移量(beta)。

5. 显示图像:使用cv::imshow函数显示原始图像和变换后的图像。

6. 保存图像:使用cv::imwrite函数保存变换后的图像到磁盘。

在OpenCV中,线性灰度变换是一种常见的图像处理技术,用于调整图像的对比度和亮度。这种变换通过简单的线性函数来调整图像中的像素值,从而达到增强或减弱图像对比度的效果。通过调整alpha和beta的值,可以改变图像的对比度和亮度,从而实现不同的线性变换效果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值