1.直方图均衡化API
输入输出图像必须是单通道8位的图像!!! 可以在输入图像上直接进行操作;
2.单通道图像直方图均衡化
实验代码:
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv
;
using namespace std
;
int main()
{
Mat img
= imread("E:/image/flower2.jpg");
if (img
.empty())printf("Load Image Error");
Mat img_gray
,dst
;
cvtColor(img
, img_gray
, CV_BGR2GRAY
);
equalizeHist(img_gray
, dst
);
imshow("src", img_gray
);
imshow("result", dst
);
waitKey(0);
}
运行结果:
3.彩色图像直方图均衡化
因为API只能输入输出单通道的图像,所以: 分离-均衡化-合并 1.首先将彩色图分离成3个通道(cv::split) 2.再分别对三个通道进行直方图均衡化; 3.最后再将3个均衡化之后的单通道图像合并;
实验代码:
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv
;
using namespace std
;
int main()
{
Mat dst
,img
= imread("E:/image/bubble.jpg");
if (img
.empty())printf("Load Image Error");
行均衡化
vector
<Mat
>channels
;
split(img
, channels
);
Mat blue
, green
, red
;
blue
= channels
.at(0);
green
= channels
.at(1);
red
= channels
.at(2);
equalizeHist(blue
, blue
);
equalizeHist(green
, green
);
equalizeHist(red
, red
);
merge(channels
, dst
);
imshow("src", img
);
imshow("result", dst
);
waitKey(0);
}
运行结果:
4.绘制直方图
4.1计算直方图
相关API
4.2绘制直方图
4.2.1实验代码
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv
;
using namespace std
;
int main()
{
Mat dst
, img
= imread("E:/image/girl2.jpg");
if (img
.empty())printf("Load Image Error");
vector
<Mat
> Channel
;
split(img
, Channel
);
int histsize
= 128;
float range
[] = { 0, 256 };
const float *histRanges
[] = { range
};
Mat b_hist
, g_hist
, r_hist
;
calcHist(&Channel
[0], 1, 0, Mat(), b_hist
, 1, &histsize
, histRanges
, true, false);
calcHist(&Channel
[1], 1, 0, Mat(), g_hist
, 1, &histsize
, histRanges
, true, false);
calcHist(&Channel
[2], 1, 0, Mat(), r_hist
, 1, &histsize
, histRanges
, true, false);
int sum
=0;
for (int k
= 0; k
< 128; k
++)
{
sum
+= b_hist
.at
<float>(k
);
cout
<< b_hist
.at
<float>(k
) << endl
;
}
cout
<< "----------------------------------" << endl
;
cout
<< img
.rows
*img
.cols
<< endl
;
cout
<< "----------------------------------" << endl
;
cout
<< sum
<< endl
;
int hist_h
= 400;
int hist_w
= 512;
int bin_w
= hist_w
/ histsize
;
Mat
histImage(hist_h
, hist_w
, CV_8UC3
, Scalar(0, 0, 0));
normalize(b_hist
, b_hist
, 0, hist_h
, NORM_MINMAX
, -1, Mat());
normalize(g_hist
, g_hist
, 0, hist_h
, NORM_MINMAX
, -1, Mat());
normalize(r_hist
, r_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(b_hist
.at
<float>(i
- 1))),
Point((i
)*bin_w
, hist_h
- cvRound(b_hist
.at
<float>(i
))), Scalar(255, 0, 0), 2, CV_AA
);
line(histImage
, Point((i
- 1)*bin_w
, hist_h
- cvRound(g_hist
.at
<float>(i
- 1))),
Point((i
)*bin_w
, hist_h
- cvRound(g_hist
.at
<float>(i
))), Scalar(0, 255, 0), 2, CV_AA
);
line(histImage
, Point((i
- 1)*bin_w
, hist_h
- cvRound(r_hist
.at
<float>(i
- 1))),
Point((i
)*bin_w
, hist_h
- cvRound(r_hist
.at
<float>(i
))), Scalar(0, 0, 255), 2, CV_AA
);
}
imshow("src", img
);
imshow("result", histImage
);
waitKey(0)
}
4.2.2运行结果
当然想画成下面这样也是可以的:
line(histImage
, Point((i
-1)*bin_w
, hist_h
),Point((i
-1)*bin_w
, hist_h
- cvRound(b_hist
.at
<float>(i
))), Scalar(255, 0, 0), 2, CV_AA
);
line(histImage
, Point((i
- 1)*bin_w
, hist_h
- cvRound(b_hist
.at
<float>(i
))),Point((i
)*bin_w
, hist_h
- cvRound(b_hist
.at
<float>(i
))), Scalar(255, 0, 0), 2, CV_AA
);
line(histImage
, Point((i
)*bin_w
, hist_h
- cvRound(b_hist
.at
<float>(i
))),Point((i
)*bin_w
, hist_h
), Scalar(255, 0, 0), 2, CV_AA
);
5.根据直方图比较两幅图像的相似度
5.1相关API
注意: 1.两个输入图像的大小必须相同! 2.四种method,如下: 第一种:cv::COMP_CORREL(相关性比较)
值越大,匹配度越高;完美匹配值为1,完全不匹配值为-1,值为0时表示不相关; 第二种:cv::COMP_CHISQR_ALT(卡方比较)
值越小,匹配度越高;完美匹配值为0,完全不匹配值为1; (前提:图像直方图均衡化后的结果已进行归一化) 第三种:cv::COMP_INTERSECT(十字交叉)
值越大,匹配度越高;完美匹配值为1,完全不匹配值为0; (前提:图像直方图均衡化后的结果已进行归一化) 第四种:cv::COMP_BHATTACHARYYA(巴氏距离)
值越小,匹配度越高;完美匹配值为0,完全不匹配值为1; 直方图匹配方法示意图:
5.2步骤
1.将输入图像转换为HSV色彩空间; 2.计算直方图,归一化; 3.比较直方图;
我的第一个疑问:为什么要将图像转换到HSV色彩空间呢?
首先我弱弱的查了一下什么是HSV色彩空间…
参考链接:https://zhuanlan.zhihu.com/p/67930839
然后又看了一下参考手册,大概意思就是说RGB对图像的亮度非常敏感,但是在HSV空间中能够很好的避开亮度的影响,如下图是OpenCV参考手册中的一个示意图: The left column shows images of a hand in an indoor environment, a shaded outdoor environment, and a sunlitoutdoor environment.
In the middle column are the blue, green, and red (BGR) histograms corresponding to the observed flesh tone of the hand. In the right column are the corresponding HSV histograms, where the vertical axis is V (value), the radius is S (saturation), and the angle is H (hue). Notice that indoors is the darkest, outdoors in shadow is a bit brighter, and outdoors in the sun is the brightest. Note also that the colors shift somewhat as a result of the changing color of the illuminating light.
——摘自Learning OpenCV3参考手册原文
5.3实验代码
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv
;
using namespace std
;
string
convertToString(double d
);
int main()
{
Mat base
, test1
, test2
;
Mat hsvbase
, hsvtest1
, hsvtest2
;
base
= imread("E:/image/dog.jpg");
test1
= imread("E:/image/dog0.jpg");
test2
= imread("E:/image/dog1.jpg");
if (base
.empty() || test1
.empty() || test2
.empty())
{
printf("Load Image Error");
return -1;
}
cvtColor(base
, hsvbase
, CV_BGR2HSV
);
cvtColor(test1
, hsvtest1
, CV_BGR2HSV
);
cvtColor(test2
, hsvtest2
, CV_BGR2HSV
);
int h_bins
= 50;
int s_bins
= 60;
int histsize
[] = { h_bins
, s_bins
};
float h_ranges
[] = { 0, 180 };
float s_ranges
[] = { 0, 256 };
const float*histRanges
[] = { h_ranges
, s_ranges
};
int channels
[] = { 0, 1 };
MatND hist_base
;
MatND hist_test1
;
MatND hist_test2
;
calcHist(&hsvbase
, 1, channels
, Mat(), hist_base
, 2, histsize
, histRanges
, true, false);
calcHist(&hsvtest1
, 1, channels
, Mat(), hist_test1
, 2, histsize
, histRanges
, true, false);
calcHist(&hsvtest2
, 1, channels
, Mat(), hist_test2
, 2, histsize
, histRanges
, true, false);
normalize(hist_base
, hist_base
, 0, 1, NORM_MINMAX
, -1, Mat());
normalize(hist_test1
, hist_test1
, 0, 1, NORM_MINMAX
, -1, Mat());
normalize(hist_test2
, hist_test2
, 0, 1, NORM_MINMAX
, -1, Mat());
double basebase
= compareHist(hist_base
, hist_base
, CV_COMP_BHATTACHARYYA
);
double basetest1
= compareHist(hist_base
, hist_test1
, CV_COMP_BHATTACHARYYA
);
double basetest2
= compareHist(hist_base
, hist_test2
, CV_COMP_BHATTACHARYYA
);
putText(base
, convertToString(basebase
), Point(50, 50), CV_FONT_HERSHEY_COMPLEX
, 1, Scalar(255, 0, 255), 2, CV_AA
);
putText(test1
, convertToString(basetest1
), Point(50, 50), CV_FONT_HERSHEY_COMPLEX
, 1, Scalar(255, 0, 255), 2, CV_AA
);
putText(test2
, convertToString(basetest2
), Point(50, 50), CV_FONT_HERSHEY_COMPLEX
, 1, Scalar(255, 0, 255), 2, CV_AA
);
namedWindow("base", CV_WINDOW_AUTOSIZE
);
namedWindow("test1", CV_WINDOW_AUTOSIZE
);
namedWindow("test2", CV_WINDOW_AUTOSIZE
);
imshow("base", base
);
imshow("test1", test1
);
imshow("test2", test2
);
waitKey(0);
return 0;
}
string
convertToString(double d
)
{
ostringstream os
;
if (os
<< d
)
return os
.str();
return "invalid conversion";
}
5.4运行结果
下图中的数字就是示例图像与原图(最左边)比较的结果;采用的的是巴氏距离的方法,所以是值越小匹配度越高;
6.给图像添加椒盐噪声
顺便学习了一下怎么在图像中椒盐噪声,方便平时的测试使用,这里的椒噪声指黑色像素点0,盐噪声指的是白色像素点255;
基本思路就是选取随机像素点然后改变其像素值为0或255即可;
6.1实验代码
Mat
addSaltNoise(const Mat srcImage
, int n
)
{
Mat dstImage
= srcImage
.clone();
for (int k
= 0; k
< n
; k
++)
{
int i
= rand() % dstImage
.rows
;
int j
= rand() % dstImage
.cols
;
if (dstImage
.channels() == 1)
{
dstImage
.at
<uchar
>(i
, j
) = 255;
}
else
{
dstImage
.at
<Vec3b
>(i
, j
)[0] = 255;
dstImage
.at
<Vec3b
>(i
, j
)[1] = 255;
dstImage
.at
<Vec3b
>(i
, j
)[2] = 255;
}
}
for (int k
= 0; k
< n
; k
++)
{
int i
= rand() % dstImage
.rows
;
int j
= rand() % dstImage
.cols
;
if (dstImage
.channels() == 1)
{
dstImage
.at
<uchar
>(i
, j
) = 0;
}
else
{
dstImage
.at
<Vec3b
>(i
, j
)[0] = 0;
dstImage
.at
<Vec3b
>(i
, j
)[1] = 0;
dstImage
.at
<Vec3b
>(i
, j
)[2] = 0;
}
}
return dstImage
;
}
6.2运行结果
参考文章链接: 1.https://blog.csdn.net/zhu_hongji/article/details/81663161 2.https://blog.csdn.net/qq_34784753/article/details/69379135