灰度变换原理
通过变换函数T将原图像像素灰度值r映射为灰度值s:
s=T(r)
灰度反转
灰度反转:将图像亮暗对调,可以增强图像中的暗色区域细节。
s=T(r)=L−1−r
其中 L 为图像灰度级,0~255 灰度图像的灰度级为 256
进行 s=T(r)=256−1−r 代码:
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
| #include <opencv2/opencv.hpp> #include <iostream>
int main() { cv::Mat image = cv::imread("src/test.jpg"); cv::Mat output_image, image_gray; cv::cvtColor(image, image_gray, cv::COLOR_BGR2GRAY);
cv::namedWindow("before", cv::WINDOW_NORMAL); cv::imshow("before", image_gray);
output_image = image_gray.clone();
for (int i = 0; i < image_gray.rows; ++ i) for (int j = 0; j < image_gray.cols; ++ j) output_image.at<uchar>(i, j) = 255 - image_gray.at<uchar>(i, j);
cv::namedWindow("after", cv::WINDOW_NORMAL); cv::imshow("after", output_image);
cv::waitKey(0);
return 0; }
|
效果展示:

对数变换
对数变换:扩展图像中的暗像素值,压缩高灰度值。
s=T(r)=clog(1+r)
其中有一个图像归一化的过程,使用函数:
1 2 3 4 5
| void normalize( InputArray src, InputOutputArray dst, double alpha = 1, double beta = 0, int norm_type = NORM_L2, int dtype = -1, InputArray mask = noArray())
|
参数如下:
-
src:输入数组;
-
dst:与输入数组一样大的输出数组;
-
alpha:范数值,在范围归一化的情况下归一化到或较低的范围边界,即下限。
-
beta: 在范围归一化的情况下的上范围边界,即上限;它不用于范数归一化,只用于NORM_MINMAX中。
-
norm_type:规范化选择的公式类型类型。
-
dtype:如果为负,则输出在大小、深度、通道数都等于输入;否则,它具有与src相同的通道数,深度不同,深度=CV_MAT_DEPTH。
-
mask:掩码。选择感兴趣区域,选定后只能对该区域进行操作。
而归一化选择的数学公式(norm_type)有,设数组元素为A1,…,An:
- NORM_L1
P=∑AiAi×alpha
- NORM_INF
P=maxAiAi×alpha
- NORM_L2
P=Ai2Ak×alpha
- NORM_MINMAX:AK∈/maxAi,minAi。 当 AK=maxAi 时, p=1 ;当 Ak=minAi时, p=0
P=maxAi−minAiAk×∣alpha−beta∣+min(alpha,beta)
同时需要注意的是alpha和beta的取值顺序与归一化结果无关。即alpha=255,beta=0和alpha=0,beta=255最后的归一化结果是相同的。
与之相关还有一个函数,其常用于将CV_16S、CV_32F等其他类型的输出图像转变成CV_8U型的图像:
1 2 3
| void convertScaleAbs(InputArray src, OutputArray dst, double alpha = 1, double beta = 0)
|
参数如下:
-
src:输入数组。
-
dst:输出数组。
-
alpha:可选比例系数。
-
beta:添加到缩放值的可选增量,即偏移量。
该函数也可用于对整个图像数组中的每一个元素进图像增强等相关先行操作的快速运算:
dsti=saturateuchar(∣alpha×srci+beta∣)
进行 s=T(r)=4log(1+r) 的代码:
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
| #include <opencv2/opencv.hpp> #include <iostream>
int main() { cv::Mat image = cv::imread("src/test.jpg"); cv::Mat output_image, image_gray; cv::cvtColor(image, image_gray, cv::COLOR_BGR2GRAY);
cv::namedWindow("before", cv::WINDOW_NORMAL); cv::imshow("before", image_gray);
output_image = image_gray.clone();
for (int i = 0; i < image_gray.rows; ++ i) for (int j = 0; j < image_gray.cols; ++ j) output_image.at<uchar>(i, j) = 4 * log((double) image_gray.at<uchar>(i, j)) + 1;
cv::normalize(output_image, output_image, 0, 255, cv::NORM_MINMAX); cv::convertScaleAbs(output_image, output_image);
cv::namedWindow("after", cv::WINDOW_NORMAL); cv::imshow("after", output_image); cv::waitKey(0);
return 0; }
|
效果展示:

幂律(伽马变换)
伽马变换:与对数函数变换类似。
s=T(r)=c×rγ
进行s=T(r)=4×r0.9 代码:
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
| #include <opencv2/opencv.hpp> #include <iostream>
int main() { cv::Mat image = cv::imread("src/test.jpg"); cv::Mat output_image, image_gray; cv::cvtColor(image, image_gray, cv::COLOR_BGR2GRAY);
cv::namedWindow("before", cv::WINDOW_NORMAL); cv::imshow("before", image_gray);
output_image = image_gray.clone();
for (int i = 0; i < image_gray.rows; ++ i) for (int j = 0; j < image_gray.cols; ++ j) output_image.at<uchar>(i, j) = 4 * pow((double)image_gray.at<uchar>(i, j), 0.9);
cv::normalize(output_image, output_image, 0, 255, cv::NORM_MINMAX); cv::convertScaleAbs(output_image, output_image); cv::namedWindow("after", cv::WINDOW_NORMAL); cv::imshow("after", output_image);
cv::waitKey(0);
return 0; }
|
效果展示:
