【图像处理OpenCV(C++版)】——4.3 对比度增强之直方图正规化
前言:
😊😊😊欢迎来到本博客😊😊😊
🌟🌟🌟 本专栏主要结合OpenCV和C++来实现一些基本的图像处理算法并详细解释各参数含义,适用于平时学习、工作快速查询等,随时更新。
😊😊😊 具体食用方式:可以点击本专栏【OpenCV快速查找(更新中)】–>搜索你要查询的算子名称或相关知识点,或者通过这篇博客👉通俗易懂OpenCV(C++版)详细教程——OpenCV函数快速查找(不断更新中)]查阅你想知道的知识,即可食用。
🎁🎁🎁支持:如果觉得博主的文章还不错或者您用得到的话,可以悄悄关注一下博主哈,如果三连收藏支持就更好啦!这就是给予我最大的支持!😙😙😙
学习目标
- 熟悉直方图正规化概念及原理
- C++实现直方图正规化案例
- 了解各种范数(1-范数、2-范数、∞-范数)
- 理解正规化函数
一、概念及原理
假设输入图像为I
,高为H
、宽为W
,I(r,c)
代表I
的第r行第c列的灰度值,将I
中出现的最小灰度级记为I min
,最大灰度级记为I max
,即I(r,c)∈[I min ,I max ]
,为使输出图像O
的灰度级范围为[O min ,O max ]
,I(r,c)
和O(r,c)
做以下映射关系:
![](https://img-blog.csdnimg.cn/d623a11a3f1d4fa8804e6274f9f31265.png)
其中0 ≤ r < H
,0 ≤ c< W
,O(r,c)
代表O
的第r行第c列的灰度值。这个过程就是常称的直方图正规化。因为0≤(𝐼(𝑟,𝑐)−𝐼 𝑚𝑖𝑛) / (𝐼 𝑚𝑎𝑥−𝑂 𝑚𝑖𝑛)≤1
,所以O(r,c)∈[O min ,O max ]
,一般令O min =0,O max =255
。
所以说,直方图正规化是一种自动选取a和b的值的线性变换方法。那么:
![](https://img-blog.csdnimg.cn/006a790f36b5422ea3cc5cc0776c3d7b.png)
其实原理很简单,更重要得是如何利用到实际案例中。
二、代码实现
在直方图正规化中最核心的步骤之一是计算原图中出现的最小灰度级和最大灰度级,OpenCV提供的函数可以计算矩阵(图像)中最小和最大值:
minMaxLoc(InputArray src,double *minVal,double *maxVal=0,Point *minLoc=0,Point *maxLoc=0,InputArray mask=noArray())
其中:
参数名 | 解释 |
---|---|
src | 输入矩阵(图像) |
minVal | 最小值,double 类型指针 |
maxVal | 最大值,double 类型指针 |
minLoc | 最小值得位置索引,Point 类型指针 |
maxLoc | 最大值得位置索引,Point 类型指针 |
利用minMaxLoc
函数不仅可以计算出矩阵中的最大值和最小值,而且可以求出最大值的位置和最小值的位置。当然,在使用过程中如果只想得到最大值和最小值,则将其他的变量值设为NULL即可。例如:
minMaxLoc(src,&minVal,&maxVal,NULL,NULL)
回到正题,对于直方图正规化的C++实现: 首先利用minMaxLoc
函数计算出原图中的最大值和最小值,然后使用函数convertScaleAbs
或者成员函数converTo
完成直方图正规化中的线性变换步骤。具体代码如下:
#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);
//设置最大最小值 并计算
double ImageMin, ImageMax;
minMaxLoc(image,&ImageMin,&ImageMax,NULL,NULL);
//设置OutImageMin OutImagMax
double OutImageMin=0, OutImagMax=255;
//计算a 和 b
double a = (OutImagMax - OutImageMin) / (ImageMax - ImageMin);
double b = OutImageMin - a*ImageMin;
//设置输出
Mat OutImage;
//线性变换
convertScaleAbs(image,OutImage,a,b);
//显示图
imshow("原图image", image);
imshow("直方图正规化图OutImage", OutImage);
waitKey(0);
return 0;
}
![](https://img-blog.csdnimg.cn/e35ae15ccb5c41319797c07943c146ab.png)
三、范数(1-范数、2-范数、∞-范数)
矩阵src范数一般有三形式,对于每种范数,下面做个简单介绍:
3.1 1-范数
对于1-范数
,其实就是计算矩阵中值的绝对值的和,即:
![](https://img-blog.csdnimg.cn/14631a990074459d893ddf1cdda7a273.png)
例如矩阵:
![](https://img-blog.csdnimg.cn/7592a843874545b2944cff46ad3a6e92.png)
利用函数normalize
的计算输出参数dst
的过程,当参数norm_type=NORM_L1
时,即计算src
的1-范数
:
![](https://img-blog.csdnimg.cn/4cd05831a2e2405a99a26d9963e8b0a8.png)
即dst
为:
![](https://img-blog.csdnimg.cn/a00bad6ad12f4a0ba9974c3a99e671b8.png)
3.2 2-范数
对于2-范数
,其实就是计算矩阵中值的平方和的开方,即:
![](https://img-blog.csdnimg.cn/3e504e987fc04893ab76388bbb647d1d.png)
利用上面得矩阵,当norm_type=NORM_L2
时,即计算src
的2-范数
:
![](https://img-blog.csdnimg.cn/7ee15c28504146f5a09c235d649e88f7.png)
即dst
为:
![](https://img-blog.csdnimg.cn/d8bf1627f3d34f99923a947728d62787.png)
3.3 ∞-范数
对于2-范数
,其实就是计算矩阵中值的绝对值的最大值,即:
![](https://img-blog.csdnimg.cn/46896272ddb6412a85216c0dc94558bf.png)
利用上面得矩阵,当norm_type=NORM_INF
时,即计算src
的∞-范数
:
![](https://img-blog.csdnimg.cn/39164c6e23b44b5fbf54fb7d48df7828.png)
即dst
为:
![](https://img-blog.csdnimg.cn/d4238daba74d4ab09940cce05700dc75.png)
另外:当norm_type=NORM_MINMAX
时,首先计算src
的最小值src min =-25
,src
的最大值src max =200
,dst
的每一个值是按照以下规则计算:
![](https://img-blog.csdnimg.cn/d776c37dd44445408fd149a585b2a234.png)
四、正规化函数
对于图像直方图正规化的操作,OpenCV提供的函数normalize
实现了类似的功能。
void normalize(InputArray src,OutputArray dst,double alpha=1,double beta=0,int norm_type=NORM_L2,int dtype=-1,InputArray mask=noArray())
该函数能够实现多种正规化操作,其中:
参数名 | 解释 |
---|---|
src | 输入矩阵(图像) |
dst | 输出图像/数组 |
alpha | 范围的最小值 |
beta | 范围的最大值(不用于范数归一化) |
intnorm_type | 归一操作的类型,主要有四种,见上面【三、范数(1-范数、2-范数、∞-范数)】 |
dtype | 为负数时,输出数组的类型与输入数组相同,否则只是通道数相同,类型默认为:type = CV_MAT_DEPTH |
mask | 指定操作的区域/空间 |
使用函数normalize
对图像进行对比度增强时,经常令参数norm_type=NORM_MINMAX
,其实和直方图正规化原理详解中提到的计算方法是相同的,参数alpha
相当于Omax
,参数beta
相当于Omin
。
注意:使用normalize
可以处理多通道矩阵,分别对每一个通道进行正规化操作。
使用该函数对图像进行对比度增强的C++代码如下:
#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 dst;
normalize(image,dst,255,0,NORM_MINMAX,CV_8U);
//显示图
imshow("原图image", image);
imshow("normalize图", dst);
waitKey(0);
return 0;
}
![](https://img-blog.csdnimg.cn/1537f743b5dd47ada959a8ed7251c4ce.png)
五、 总结
最后,长话短说,大家看完就好好动手实践一下,切记不能三分钟热度、三天打鱼,两天晒网。OpenCV是学习图像处理理论知识比较好的一个途径,大家也可以自己尝试写写博客,来记录大家平时学习的进度,可以和网上众多学者一起交流、探讨,有什么问题希望大家可以积极评论交流,我也会及时更新,来督促自己学习进度。希望大家觉得不错的可以点赞、关注、收藏。
![](https://img-blog.csdnimg.cn/e7f067b35749483d9b44b346822e2a53.gif)
相关文章
- opencv中图像伪彩色处理(C++ / Python)
- opencv使用convexityDefects计算轮廓凸缺陷
- Android版OpenCV图像处理技术亲自验证[三十一]之图像简单阈值操作(附源码)
- Opencv学习笔记 - 关于OpenCV的UMat 类
- Opencv学习笔记 - OpenCV 4机器学习算法简介
- 【OpenCV-Python】教程:4-9 特征匹配 match
- 成功解决cv2.error: OpenCV(4.1.2) C:projectsopencv-pythonopencvmodulesimgprocsrccolor.cpp:182: err
- OpenCV基于稠密光流跟踪
- 解答私信@被c++折磨头秃的花季美少女 //C++ 编写一个进阶版的进制转换程序,运行功能如下:请选择要输入的数字的进制(2、8、10、16):请输入该数字:请选择要转换成的进制(2、8。。。
- Opencv图像处理:判断图片里某个颜色值占的比例
- 【OpenCV 例程200篇】24. 图像的仿射变换(cv2.warpAffine)
- 【OpenCV 例程 300 篇】105. 湍流模糊退化模型
- 【youcans 的 OpenCV 例程200篇】150. 边缘检测梯度算子
- 【OpenCV 例程300篇】202. 查表快速替换(cv.LUT)
- C++ - Opencv应用实例之仿射变换实现工件角度校正
- Opencv从入门到精通(五):透视图、拼接图片、颜色检测
- 【图像处理OpenCV(C++版)】——5.1 图像平滑之二维离散卷积
- 【图像处理OpenCV(C++版)】——4.2 对比度增强之线性变换
- 【图像处理OpenCV(C++版)】——3.1几何变换之仿射变换
- 【图像处理OpenCV(C++版)】——2.3 灰度/彩色图像数字化
- OpenCV(C++)图像处理基础04:图像混合(线性混合操作)
- OpenCV(C++)图像处理基础01:加载、修改、保存图像