灰度变换和空间滤波基础
灰度变换(灰度反转,对数变换,幂律变换)
灰度变换原理
变换原理:通过变换函数T将原图像像素灰度值r映射为灰度值s:
$s=T(r)$
灰度反转
原理:
灰度反转:将图像亮暗对调,可以增强图像中暗色区域细节
$s=T(r)=L-1-r$
其中L为图像灰度级,0~255灰度图像的灰度级为256.
代码
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
| #include<iostream> #include<opencv2/opencv.hpp>
using namespace cv; using namespace std;
int main() { Mat image1, output_image, image1_gray; image1 = imread("fire.jpg"); if (image1.empty()) { cout << "读取错误" << endl; return -1; }
cvtColor(image1, image1_gray, COLOR_BGR2GRAY); imshow(" image1_gray", image1_gray);
output_image = image1_gray.clone(); for (int i = 0; i < image1_gray.rows; i++) { for (int j = 0; j < image1_gray.cols; j++) { output_image.at<uchar>(i, j) = 255 - image1_gray.at<uchar>(i, j); } } imshow("output_image", output_image);
waitKey(0); return 0; }
|
输出
对数变换
原理
对数变换:扩展图像中的暗像素值,压缩高灰度值。
$s=T(r)=c*log(1+r)$
$log(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 30 31 32 33 34 35
| #include<iostream> #include<opencv2/opencv.hpp>
using namespace cv; using namespace std;
int main() { Mat image1, output_image, image1_gray; image1 = imread("fire.jpg"); if (image1.empty()) { cout << "读取错误" << endl; return -1; }
cvtColor(image1, image1_gray, COLOR_BGR2GRAY); imshow(" image1_gray", image1_gray);
output_image = image1_gray.clone(); for (int i = 0; i < image1_gray.rows; i++) { for (int j = 0; j < image1_gray.cols; j++) { output_image.at<uchar>(i, j) = 6 * log((double)(image1_gray.at<uchar>(i, j)) + 1); } } normalize(output_image, output_image, 0, 255, NORM_MINMAX); convertScaleAbs(output_image, output_image); imshow(" output_image", output_image);
waitKey(0); return 0; }
|
输出
幂律(伽马变换)
原理
幂律变换与对数变换类似:
$s=T(r)=c*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 30 31 32 33 34 35
| #include<iostream> #include<opencv2/opencv.hpp>
using namespace cv; using namespace std;
int main() { Mat image1, output_image, image1_gray; image1 = imread("lena.png"); if (image1.empty()) { cout << "读取错误" << endl; return -1; }
cvtColor(image1, image1_gray, COLOR_BGR2GRAY); imshow(" image1_gray", image1_gray);
output_image = image1_gray.clone(); for (int i = 0; i < image1_gray.rows; i++) { for (int j = 0; j < image1_gray.cols; j++) { output_image.at<uchar>(i, j) =6*pow((double)image1_gray.at<uchar>(i, j),0.5); } } normalize(output_image, output_image, 0, 255, NORM_MINMAX); convertScaleAbs(output_image, output_image); imshow(" output_image", output_image);
waitKey(0); return 0; }
|
输出
直方图处理(直方图均衡化,直方图匹配(规定化))
直方图显示了每个像素值在整幅图像中出现的频率或数量,从而帮助我们理解图像的亮度分布情况。
图像直方图
非归一化直方图:
$h(r_k)=n_k$
归一化直方图:
$p(r_k)={n_k \over MN}$
其中MN为图像行数和列数,常说的图像直方图就是归一化直方图。
获取图像直方图示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| #include<iostream> #include<opencv2/opencv.hpp> using namespace cv; using namespace std;
int main() { Mat image, image_gray, hist; image = imread("fire.jpg"); if (image.empty()) { cout << "读取错误" << endl; return -1; }
cvtColor(image, image_gray, COLOR_BGR2GRAY); imshow(" image_gray", image_gray);
|
1 2 3 4 5
| int histsize = 256; float ranges[] = { 0,256 }; const float* histRanges = { ranges }; calcHist(&image_gray, 1, 0, Mat(), hist, 1, &histsize, &histRanges, true, false);
|
这段代码用于计算图像的直方图,下面是对这段代码的详细解释:
histsize = 256: 这里定义了直方图的大小为256,表示直方图的横轴范围,通常对应着图像可能的像素值范围(0到255)。
ranges[] = {0, 256}: 这里定义了直方图可能的像素值范围为0到256,用于指定直方图中每个像素值的范围。
const float histRanges = {ranges};* 这一行用于将ranges数组转换为指向常量浮点数的指针,供calcHist函数使用。
calcHist(&image_gray, 1, 0, Mat(), hist, 1, &histsize, &histRanges, true, false):
- &image_gray: 这是输入的灰度图像,表示要计算直方图的原始图像。
- 1: 表示要计算的图像数量。
- 0: 表示直方图要计算的通道索引,0表示灰度图像。
- Mat(): 这里是一个掩码图像,用于指定要计算直方图的区域;在这里没有使用,因此为空。
- hist: 这是用于存储计算后直方图的Mat对象。
- 1: 直方图的维数,对于灰度图像是1维。
- &histsize: 这是包含直方图大小(256)的指针。
- &histRanges: 指向直方图范围的指针。
- true: 指示直方图是否均一化,即在范围0到255内对直方图进行归一化处理。
- false: 指示直方图是否累积,即表示直方图是否累积计算。
通过这段代码,可以通过calcHist函数计算图像image_gray的直方图,并将结果存储在hist对象中。直方图的范围是0到255之间,且进行了归一化处理。这能够帮助我们了解图像的像素值分布情况,为后续的图像处理和分析提供数据支持。希望这个解释对您有帮助,如果您有任何其他问题,请随时告诉我!
1 2 3 4 5
| int hist_h = 300; int hist_w = 512; int bin_w = hist_w / histsize; Mat histImage(hist_h, hist_w, CV_8UC3, Scalar(0, 0, 0));
|
1 2 3 4 5 6 7 8 9 10 11 12
| normalize(hist, hist, 0, hist_h, NORM_MINMAX, -1, Mat()); for (int i = 1; i < histsize; i++) { line(histImage, Point((i - 1) * bin_w, hist_h - cvRound(hist.at<float>(i - 1))), Point((i)*bin_w, hist_h - cvRound(hist.at<float>(i))), Scalar(255, 0, 0), 2, 8, 0); } imshow("histImage", histImage);
waitKey(0); return 0; }
|
这段代码是用于将归一化后的直方图数据绘制成直方图图像的过程。下面是对代码的详细解释:
for
循环:
- 这段代码使用
for
循环遍历直方图的每个条,从第2个条开始到最后一个条。
i
从1开始,因为第0个条通常代表背景,可以跳过不绘制。
line()
函数:
line()
函数用于在histImage
上绘制直方图的条。
Point((i - 1) * bin_w, hist_h - cvRound(hist.at<float>(i - 1)))
表示当前条的起始点位置,前一个条的结束点位置。
Point((i)*bin_w, hist_h - cvRound(hist.at<float>(i)))
表示当前条的终点位置。
Scalar(255, 0, 0)
指定绘制直线的颜色为蓝色。
2
表示线的粗细为2个像素。
8
表示线的类型为8-connected。
0
表示线的偏移值为0。
绘制直方图条:
- 通过计算每个直方图条的起始和终止点,使用
line()
函数在histImage
上绘制直方图条。
cvRound()
用于将浮点值四舍五入为最接近的整数,确保直方图能够正确映射到图像上。
直方图均衡化
(我感觉差不多了,我去做考核咯~)