OpenCV4入门系列教程42:对数变换

索引地址:系列教程索引地址

上一篇:OpenCV4入门系列教程41:极坐标变换

对数变换将图像的低灰度值部分扩展,将其高灰度值部分压缩,以达到强调图像低灰度部分的目的;同时可以很好的压缩像素值变化较大的图像的动态范围,目的是突出我们需要的细节。反对数变换则与对数函数不同的是,强调的是图像的高灰度部分,对数变换公式如下

s=c log(1+r)s=c\ log(1+r)

实现方法有三种方式,详细的看程序,logTransform1基于源图像,logTransform2()和logTransform3()直接对目标进行操作。

测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
// 功能:代码 3-22 对数变换的三种实现方法
// 作者:朱伟 zhu1988wei@163.com
// 来源:《OpenCV图像处理编程实例》
// 博客:http://blog.csdn.net/zhuwei1988
// 更新:2016-8-1
// 说明:版权所有,引用或摘录请联系作者,并按照上面格式注明出处,谢谢。//

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;

// 对数变换方法1
cv::Mat logTransform1(cv::Mat srcImage, int c) {
// 输入图像判断
if (srcImage.empty())
std::cout << "No data!" << std::endl;
cv::Mat resultImage = cv::Mat::zeros(srcImage.size(), srcImage.type());
// 计算 1 + r
cv::add(srcImage, cv::Scalar(1.0), srcImage);
// 转换为32位浮点数
srcImage.convertTo(srcImage, CV_32F);
// 计算 log(1 + r)
log(srcImage, resultImage);
resultImage = c * resultImage;
// 归一化处理
cv::normalize(resultImage, resultImage, 0, 255, cv::NORM_MINMAX);
cv::convertScaleAbs(resultImage, resultImage);
return resultImage;
}

// 对数变换方法2
cv::Mat logTransform2(Mat srcImage, float c) {
// 输入图像判断
if (srcImage.empty())
std::cout << "No data!" << std::endl;
cv::Mat resultImage = cv::Mat::zeros(srcImage.size(), srcImage.type());
double gray = 0;
// 图像遍历分别计算每个像素点的对数变换
for (int i = 0; i < srcImage.rows; i++) {
for (int j = 0; j < srcImage.cols; j++) {
gray = (double)srcImage.at<uchar>(i, j);
gray = c * log((double)(1 + gray));
resultImage.at<uchar>(i, j) = saturate_cast<uchar>(gray);
}
}
// 归一化处理
cv::normalize(resultImage, resultImage, 0, 255, cv::NORM_MINMAX);
cv::convertScaleAbs(resultImage, resultImage);
return resultImage;
}

// 对数变换方法3
cv::Mat logTransform3(Mat srcImage, float c) {
// 输入图像判断
if (srcImage.empty())
std::cout << "No data!" << std::endl;
cv::Mat resultImage = cv::Mat::zeros(srcImage.size(), srcImage.type());
srcImage.convertTo(resultImage, CV_32F);
resultImage = resultImage + 1;
cv::log(resultImage, resultImage);
resultImage = c * resultImage;
cv::normalize(resultImage, resultImage, 0, 255, cv::NORM_MINMAX);
cv::convertScaleAbs(resultImage, resultImage);
return resultImage;
}

int main() {
// 读取灰度图像及验证
cv::Mat srcImage = cv::imread("lena.jpg", 0);
if (!srcImage.data)
return -1;
cv::imshow("srcImage", srcImage);
float c = 1.1;
cv::Mat resultImage;
resultImage = logTransform1(srcImage, c);//方法一
cv::imshow("resultImage1", resultImage);
resultImage = logTransform2(srcImage, c);//方法二
cv::imshow("resultImage2", resultImage);
resultImage = logTransform3(srcImage, c);//方法三
cv::imshow("resultImage3", resultImage);
cv::waitKey(0);
return 0;
}

测试效果:

log

下一篇:OpenCV4入门系列教程43:距离变换