前言:
欢迎来到本博客
本专栏主要结合OpenCV和C++来实现一些基本的图像处理算法并详细解释各参数含义,适用于平时学习、工作快速查询等,随时更新。
具体食用方式:可以点击本专栏【OpenCV快速查找(更新中)】–>搜索你要查询的算子名称或相关知识点,或者通过这篇博客通俗易懂OpenCV(C++版)详细教程——OpenCV函数快速查找(不断更新中)]查阅你想知道的知识,即可食用。
支持:如果觉得博主的文章还不错或者您用得到的话,可以悄悄关注一下博主哈,如果三连收藏支持就更好啦!这就是给予我最大的支持!
采集高质量的图像有各种各样的方法,但是有的图像还是不够好,需要通过图像增强技术提高其质量,这里要介绍的对比度增强或者称为对比度拉伸就是图像增强技术的一种,主要解决由于图像的灰度级范围较小造成的对比度较低的问题,目的就是将输出图像的灰度级放大到指定的程度,使得图像中的细节看起来更加清晰。对比度增强有几种常用的方法,如线性变换、分段线性变换、伽马变换、直方图正规化、直方图均衡化、局部自适应直方图均衡化等,这些方法的计算代价较小,但是却产生了较
为理想的效果。
在数字图像处理中,灰度直方图是一种计算代价非常小但却很有用的工具,它概括了一幅图像的灰度级信息。灰度直方图是图像灰度级的函数,用来描述每个灰度级在图像矩阵中的像素个数或者占有率。举一个简单的例子,假设有如下图像矩阵:
图像矩阵中我们可以看到,灰度值1在I
中出现的次数为1,值6出现的次数为1……值20出现的次数为4……值255出现的次数为0,然后将得到的每个数值按照直方图的可视化方式表示出来即可,横坐标代表灰度级,纵坐标代表对应的每一个灰度级出现的次数,如下图所示。用占有率(或称归一化直方图、概率直方图)表示就是灰度值1在I
中的占有率为1/16
,灰度值6在I
中的占有率为1/16
,灰度值20在I
中的占有率为4/16
,…,灰度值255在I
中的占有率为0/16
。
了解了灰度直方图的定义后,接下来介绍计算灰度直方图的C++实现。
OpenCV提供了函数calcHist来实现直方图的构建,但是在计算8位图的灰度直方图时,它使用起来略显复杂。可以定义函数calcGrayHist
来计算灰度直方图,其中输入参数为8位图,将返回的灰度直方图存储为一个1行256列的Mat类型。代码如下:
#include
#include
#include
#include
using namespace std;
using namespace cv;
Mat calcGrayHist(const Mat & image) {
Mat histogram = Mat::zeros(Size(256, 1), CV_32SC1);
int rows = image.rows;
int cols = image.cols;
//计算每个灰度级个数
for (int r = 0; r < rows; r++)
{
for (int c = 0; c < cols; c++)
{
int index = int(image.at<uchar>(r, c));
histogram.at<int>(0, index) += 1;
}
}
return histogram;
}
int main() {
//输入原图
Mat image = imread("D:/VSCodeFile/OpenCV_CSDN/image/logo.jpg", CV_LOAD_IMAGE_GRAYSCALE);
if (!image.data)
{
return -1;
}
calcGrayHist(image);
return 0;
}
OpenCV提供了函数:
void calcHist(const Mat* images, int nimages,
const int* channels, InputArray mask,
OutputArray hist, int dims, const int* histSize,
const float** ranges, bool uniform = true, bool accumulate = false);
其中:
images
:输入的图像;
nimages
:输入的图像个数;
channels
:统计直方图第几通道;
mask
:可选的操作掩码;
hist
:输出的直方图数组;
dims
:需要统计直方图通道的个数;
histSize
:直方图分成多少个区间;
ranges
:像素值区间;
uniform
:是否进行归一化处理;
accumulate
:在多个图像时是否计算像素值个数;
#include
#include
#include
#include
using namespace std;
using namespace cv;
int main() {
Mat img = imread("D:/VSCodeFile/OpenCV_CSDN/image/img2.jpg");
if (img.empty()) {
cout << "请确认输入的图片路径是否正确" << endl;
return -1;
}
Mat gray;
cvtColor(img, gray, COLOR_BGR2GRAY);
//设置提取直方图的相关变量
Mat hist;//用于存放直方图计算结果
const int channels[1] = { 0 };//通道索引
float inRanges[2] = { 0,255 };
const float*ranges[1] = { inRanges };//像素灰度值范围
const int bins[1] = { 256 };//直方图的维度,其实就是像素灰度值的最大值
calcHist(&img, 1, channels, Mat(), hist, 1, bins, ranges);//计算图像直方图
//准备绘制直方图
int hist_w = 512;
int hist_h = 400;
int width = 2;
Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);
for (int i = 1; i <= hist.rows; ++i) {
rectangle(histImage, Point(width*(i - 1), hist_h - 1),
Point(width*i - 1, hist_h - cvRound(hist.at<float>(i - 1) / 20)),
Scalar(255, 255, 255), -1);
}
namedWindow("histImage", WINDOW_AUTOSIZE);
imshow("histImage", histImage);
imshow("gray", gray);
waitKey(0);
return 0;
}
图像对比度是通过灰度级范围来度量的,而灰度级范围可通过观察灰度直方图得到,灰度级范围越大代表对比度越高;反之,对比度越低,低对比度的图像在视觉上给人的感觉是看起来不够清晰,所以通过算法调整图像的灰度值,从而调整图像的对比度是有必要的。最简单的一种对比度增强方法是通过灰度值的线性变换来实现的,下一节将介绍什么是线性变换。
最后,长话短说,大家看完就好好动手实践一下,切记不能三分钟热度、三天打鱼,两天晒网。OpenCV是学习图像处理理论知识比较好的一个途径,大家也可以自己尝试写写博客,来记录大家平时学习的进度,可以和网上众多学者一起交流、探讨,有什么问题希望大家可以积极评论交流,我也会及时更新,来督促自己学习进度。希望大家觉得不错的可以点赞、关注、收藏。