OpenCV线性灰度变换详解:原理、实现与代码示例
创作时间:
作者:
@小白创作中心
OpenCV线性灰度变换详解:原理、实现与代码示例
引用
CSDN
1.
https://m.blog.csdn.net/weixin_45794330/article/details/141782221
实验原理
在OpenCV中,线性灰度变换是一种常见的图像处理技术,用于调整图像的对比度和亮度。这种变换通过简单的线性函数来调整图像中的像素值,从而达到增强或减弱图像对比度的效果。线性灰度变换的基本形式可以表示为:
g(x) = αf(x) + β
其中:
- f(x) 是输入图像中的像素值。
- g(x) 是输出图像中的像素值。
- α 是缩放因子,用于控制对比度。
- β 是偏移量,用于控制亮度。
线性灰度变换的目的
线性灰度变换主要用于以下几个方面:
- 调整对比度:通过调整 α 的值,可以使图像的对比度变强或变弱。
- 调整亮度:通过调整 β 的值,可以使图像整体变得更亮或更暗。
OpenCV中的实现方法
在OpenCV中,可以使用多种方法来实现线性变换,以下是两种常用的方法:
方法一:使用 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)));
}
}
实现细节:
- 数据类型:在进行线性变换时需要注意数据类型。通常情况下,灰度图像的像素值类型为 uchar(无符号8位整数),因此需要确保变换后的值在 [0, 255] 范围内。
- 饱和操作:在手动实现时,需要使用
std::min和std::max函数来确保像素值不会超出有效范围。
实验代码
方法二:灰度图像线性变换
#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
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++) {
resultImage.at<uchar>(i, j) = saturate_cast<uchar>(a * (srcImage.at<uchar>(i, j)) + b);
}
}
return resultImage;
}
int main() {
// 图像获取及验证
cv::Mat srcImage = cv::imread("123.jpg", cv::IMREAD_GRAYSCALE);
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)的问题。
方法二:彩色图像线性变换
#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
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++) {
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++实现灰度图像的线性变换。我们将实现以下功能:
- 读取灰度图像。
- 应用线性变换:通过增加亮度和调整对比度。
- 显示和保存变换后的图像。
#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main() {
// 图像获取及验证
cv::Mat srcImage = cv::imread("09011913.jpeg", cv::IMREAD_GRAYSCALE);
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;
}
代码解释:
- 读取图像:使用
cv::imread函数读取输入图像,并将其转换为灰度图像(IMREAD_GRAYSCALE)。 - 定义线性变换参数:
- alpha:对比度因子,用于调整图像的对比度。alpha > 1 会使图像更亮,alpha < 1 会使图像更暗。
- beta:亮度偏移量,用于增加图像的亮度。beta > 0 会使图像更亮,beta < 0 会使图像更暗。
- 创建输出图像:创建一个新的
cv::Mat对象来存储变换后的图像。 - 应用线性变换:使用
convertTo函数来应用线性变换。convertTo函数的第一个参数是输出图像,第二个参数是深度(-1 表示保持源图像的深度不变),第三个参数是对比度因子(alpha),第四个参数是亮度偏移量(beta)。 - 显示图像:使用
cv::imshow函数显示原始图像和变换后的图像。 - 保存图像:使用
cv::imwrite函数保存变换后的图像到磁盘。
在OpenCV中,线性灰度变换是一种常见的图像处理技术,用于调整图像的对比度和亮度。这种变换通过简单的线性函数来调整图像中的像素值,从而达到增强或减弱图像对比度的效果。通过调整 alpha 和 beta 的值,可以改变图像的对比度和亮度,从而实现不同的线性变换效果。
热门推荐
凤凰古镇+边城三日游攻略,沈从文笔下的湘西风情!
凤凰古城的历史建筑探秘
凤凰古镇摄影打卡攻略:这些地方美到爆!
《蜜蜂与远雷》:恩田陆笔下的古典音乐魅力
2025总台蛇年春晚海外爆红!
断路器跳闸的原因及处理方法是什么
抚恤金能治愈心理创伤吗?
春节穿衣指南:保暖又时尚的10种搭配方案
刘叔遗产纷争背后的抚恤金真相揭秘
一次软件更新如何导致全球电脑崩溃?诸多因素引发连锁反应
幼鸽八个阶段饲养和管理方法
鸽子养殖技术与管理指南
犀浦韭高产栽培技术详解
专业厨师教你:韭菜炒鸡蛋的完美做法
冬季如何挑选新鲜韭菜?这些小妙招让你轻松辨别!
潮州必打卡:潮膳楼&官塘锋记鱼生
潮州古城与韩文公祠:千年文化传承的见证
探秘天涯海角:揭秘各地旅游术语及背后的文化含义
宇宙是如何开始的?早期的宇宙样貌又是如何?
行走拉美手记丨乌斯怀亚:中国,在“世界尽头”遇见你
突发性高血压怎么处理
《樱花校园模拟器》带你体验纯正日式校园生活
《樱花校园模拟器》复活机制全攻略:从NPC复活到最新玩法技巧详解
《樱花校园模拟器》新手速成攻略:从入门到精通
陶瓷锅使用全攻略:从开锅到保养,这些细节你都知道吗?
陶瓷锅烤糊了?7招轻松搞定!
河北承德:迎新春冰雪嘉年华暨承德市第八届冰上龙舟争霸赛燃情开幕
如何增强在恋爱中的个人吸引力?
人口流动大潮下的乡村振兴:挑战与机遇并存
乡村振兴下的农村养老困局与破解之道