【图像处理OpenCV(C++版)】——4.2 对比度增强之线性变换
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
前言
😊😊😊欢迎来到本博客😊😊😊
🌟🌟🌟 本专栏主要结合OpenCV和C++来实现一些基本的图像处理算法并详细解释各参数含义适用于平时学习、工作快速查询等随时更新。
😊😊😊 具体食用方式可以点击本专栏【OpenCV快速查找(更新中)】–>搜索你要查询的算子名称或相关知识点或者通过这篇博客👉通俗易懂OpenCV(C++版)详细教程——OpenCV函数快速查找(不断更新中)]查阅你想知道的知识即可食用。
🎁🎁🎁支持如果觉得博主的文章还不错或者您用得到的话可以悄悄关注一下博主哈如果三连收藏支持就更好啦这就是给予我最大的支持😙😙😙
文章目录
学习目标
- 熟悉线性变换概念及原理
- C++实现线性变换案例
一、概念及原理
图像的线性变换可以用以下公式定义
其中输入图像为I
宽为W
、高为H
输出图像记为O
。
如下图所示当a=1
b=0
时O
为I
的一个副本如果a>1
那么输出图像O
的对比度比I
有所增大如果0<a<1
那么O
的对比度比I
有所减小。而b
值的改变影响的是输出图像的亮度当b>0
时亮度增加当b<0时亮度减小。
举例假设图像的灰度级范围是[50100]通过a=2b=0
的线性变换可以将输出图像的灰度级拉伸到[100200]灰度级范围有所增加从而提高了对比度而如果令a=0.5b=0
则输出图像的灰度级会压缩到[2550]灰度级范围有所减小则降低了对比度。
下面介绍线性变换的代码实现从处理图像的效果上可以更直观地理解线性变换的作用。
二、代码实现
在OpenCV中实现一个常数与矩阵相乘有多种方式。
2.1、方式一
线性变换的第一种方式通过Mat的成员函数
convertTo(OutputArray m,int rtype,double alpha=1,double beta=0)
其中参数m
代表输出矩阵参数rtype
是输出矩阵m的数据类型参数alpha
和beta
分别可以理解为线性变换中的a
和b
。简单案例如下:
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
int main() {
Mat I = (Mat_<uchar>(2,2) << 0, 200, 35, 8);//输入矩阵/原图
Mat O;//输出矩阵
I.convertTo(O, CV_8UC1, 2.0, 0);
cout << "O=:" << O << endl;
return 0;
}
其中输入的I
的数据类型为uchar
当输出矩阵的数据类型是CV_8U
时大于255的值会自动截断为255。
我们可以再用一张图形象显示
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
int main() {
Mat image = imread("D:/VSCodeFile/OpenCV_CSDN/image/logo.jpeg", IMREAD_COLOR);
Mat Outiamge;
image.convertTo(Outiamge, CV_8UC1, 2.0, 5);
imshow("image", image);
imshow("Outiamge【alpha=1.5,beta=0】", Outiamge);
waitKey(0);
return 0;
}
其中通过a=2b=5
的线性变换可以将输出图像的灰度级进行拉伸从而提高了对比度b=5>0
亮度也有所增加。
2.2、方式二
线性变换的第二种方式使用乘法运算符‘ * ’
即
Mat O=4.0*I;
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
int main() {
Mat I = (Mat_<uchar>(2,2) << 0, 200, 35, 8);//输入矩阵/原图
Mat O = 4.0 * I;
cout << "O=:" << O << endl;
return 0;
}
输出矩阵O的值为[[0255][14032]]使用乘法运算符‘ * ’
无论常数是什么数据类型输出矩阵的数据类型总是和输入矩阵的数据类型相同当数据类型是CV_8U
时在返回值中将大于255的值自动截断为255。
同样用一张图形象显示
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
int main() {
Mat image = imread("D:/VSCodeFile/OpenCV_CSDN/image/logo.jpeg", IMREAD_COLOR);
Mat Outiamge=2.0*image+5;
imshow("image", image);
imshow("Outiamge【alpha=1.5,beta=0】", Outiamge);
waitKey(0);
return 0;
}
2.3、方式三
线性变换的第三种方式利用OpenCV提供的函数
convertScaleAbs(InputArray src,OutputArray dst,double alpha=1,double beta=0))
其中dst=alpha*src+beta
dst
的数据类型和输入矩阵src的数据类型是相同的。
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
int main() {
Mat I = (Mat_<uchar>(2,2) << 0, 200, 35, 8);//输入矩阵/原图
Mat O;
convertScaleAbs(I,O, 2.0 ,0);
cout << "O=:" << O << endl;
return 0;
}
同样用一张图形象显示
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
int main() {
Mat image = imread("D:/VSCodeFile/OpenCV_CSDN/image/logo.jpeg", IMREAD_COLOR);
Mat Outiamge;
//Mat Outiamge=2.0*image+5;
convertScaleAbs(image, Outiamge, 2.0, 5);
imshow("image", image);
imshow("Outiamge【alpha=1.5,beta=0】", Outiamge);
waitKey(0);
return 0;
}
以上线性变换是对整个灰度级范围使用了相同的参数有的时候也需要针对不同的灰度级范围进行不同的线性变换这就是常用的分段线性变换。
分段线性变换应用场景经常用于降低较亮或较暗区域的对比度来增强灰度级处于中间范围的对比度或者压低中间灰度级处的对比度来增强较亮或较暗区域的对比度。
线性变换的参数需要根据不同的应用及图像自身的信息进行合理的选择可能需要进行多次测试所以选择合适的参数是相当麻烦的。其实OpenCV有一种基于当前图像情况自动选取a
和b
的值的方法下一节就介绍一种显而易见但却很有效的方法称为直方图正规化。
三、 总结
最后长话短说大家看完就好好动手实践一下切记不能三分钟热度、三天打鱼两天晒网。OpenCV是学习图像处理理论知识比较好的一个途径大家也可以自己尝试写写博客来记录大家平时学习的进度可以和网上众多学者一起交流、探讨有什么问题希望大家可以积极评论交流我也会及时更新来督促自己学习进度。希望大家觉得不错的可以点赞、关注、收藏。