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 的值,可以改变图像的对比度和亮度,从而实现不同的线性变换效果。
热门推荐
各国法律法规如何监管声音内容和平台
海外公司市值怎么查询?全球公司市值查询方法大揭秘!
手脚冰凉怎么调理?6个实用方法让你暖起来
AI在运维实践中的价值提升
云南蒙自南湖公园,风景秀美,古迹众多,是一处被低估的宝藏地
如何提升供应链管理的透明度?
经济法押卷题三:解密考试命题规律与应试技巧
最新全球票房榜前10,中国有3部,第1名110亿,不过输给了沈腾
中科院1区期刊发文:墨旱莲提取物治疗多发性骨髓瘤新机制
从工业到养老,一次聊透具身智能的落地应用
炒ST股票的注意事项与投资策略
如何选择环保又实用的家庭木门?七大要点助你轻松挑选
比特币基金与比特币:投资结构、管理方式与风险特征全解析
青少年为何容易沉迷手机?心理咨询师解析背后的“心理密码”
AI数字人陷阱:中老年人如何应对“深情”带货骗局?
选择手机壳的材质要点(如何根据需求和风格选择最适合的手机壳)
代谢废物也是宝!3篇高分文献解析乳酸化在炎症和免疫领域研究中的应用!
被冤枉是否触犯法律:探究我国法律对冤假错案的规定和处理
冤案证据搜集:如何揭示真相
肋骨是什么骨
短管内衬置换修复技术:管道非开挖修复的新选择
独立董事制度在中国的发展与现状分析
独立董事价值、责任、履职能力|资本市场
抑郁症患者都是怎么复查的
夫妻八字是否合看什么,夫妻八字合不合查询表
岐黄名医:傅青主
银行存款利率解析:如何选择最合适的存款方案
分享几道春季适宜的清香茶饮
手机与电脑连接技巧:数据传输与网络共享全攻略
自我认知的镜子:通过反思与自我评估促进孩子的自我成长