首页 > 其他分享 >【OpenCV】直方图计算 & 均衡化直方图

【OpenCV】直方图计算 & 均衡化直方图

时间:2023-02-14 17:02:44浏览次数:65  
标签:Mat int 均衡化 OpenCV 直方图 灰度 bins


开头一叙: 最近把一部电视剧《天才基本法》看完了,学了一句话:“一以贯之的努力,不得懈怠的人生”,今天学直方图均衡化的时候,书上只介绍直方图均衡化后的效果,并没有讲解直方图。面向百度之后,也知道为什么书上不介绍了,理解有点困难。不过我还是花费一段时间啃啃了,哈哈~


文章目录

  • ​​直方图均衡化​​
  • ​​1、直方图均衡化的概念和特点​​
  • ​​2、实现直方图均衡化:equalizeHist()函数​​
  • ​​4、示例程序​​
  • ​​直方图的计算以及绘制​​
  • ​​1 相关的概念以及函数:​​
  • ​​2 计算图像直方图:calcHist()函数​​
  • ​​3 一维灰度直方图​​
  • ​​4 不均匀灰度直方图​​
  • ​​原图的直方图与均衡化的直方图对比​​

直方图均衡化

说明:从如下的图和直方图可以看出,图像的亮度主要集中在中间,两边比较淡,导致直方图中间的点集中比较多。

【OpenCV】直方图计算 & 均衡化直方图_图像处理

1、直方图均衡化的概念和特点

定义:直方图均衡化是通过拉伸像素强度分布范围来增强图像对比度的一种方法。

均衡化处理后的图像只能是近似均匀分布。均衡化图像的动态范围扩大了,但其本质是扩大了量化间隔,而量化级别反而减少了,所以原来灰度不同的像素经过处理后可能变得接近相同,形成一片相同的灰度区域,各区域之间有明显的边界,从而出现轮廓。

原理: 在原始图像对比度很高的情况下,如果再均衡化则灰度调和,对比度会降低。在泛白缓和的图像中,均衡化会合并一些像素灰度,从而增大对比度。若是对已经均衡化的图片再对其均衡化,图像不会发生太大变化。如下,经过均衡化的图像,其频谱更加舒展。

【OpenCV】直方图计算 & 均衡化直方图_计算机视觉_02

2、实现直方图均衡化:equalizeHist()函数

void equalizeHist(InputArray src,OutputArray dst)
  • 第一个参数:输入图像
  • 第二个参数:输出图像,和源图片有一样的尺寸和类型

采用如下步骤对输入图像进行直方图均衡化

1)计算输出图像的直方图 H

2)进行直方图归一化,直方图的组距的和为255

3)计算直方图积分:

【OpenCV】直方图计算 & 均衡化直方图_图像处理_03

4)以H’作为查询表进行图像变换
【OpenCV】直方图计算 & 均衡化直方图_计算机视觉_04
总之:如下表格例子:

说明:先把每个灰度级进行归一化处理,求每种灰度的累计分布,得到一个映射的灰度映射表,然后根据相应的灰度值来修正原图中的每个像素。

【OpenCV】直方图计算 & 均衡化直方图_#include_05

4、示例程序

#include<opencv2/opencv.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<iostream>
using namespace std;
using namespace cv;
int main()
{
Mat srcImage, dstImage;
srcImage = imread("E:\\Pec\\cat.jpg");
//转化为灰度图
cvtColor(srcImage, srcImage, COLOR_BGR2GRAY);
imshow("【原始图】", srcImage);
//进行直方图均衡化
equalizeHist(srcImage, dstImage);
//显示结果
imshow("【经过直方图均衡化后的图】", dstImage);
waitKey(0);
}

【OpenCV】直方图计算 & 均衡化直方图_opencv_06


接下来难点来了


直方图的计算以及绘制

1 相关的概念以及函数:

  • dims:需要统计特征的数目,灰度图–dims=1,RGB值------dims=3
  • bins:每个特征空间子区域段的数目,也可称为组距(简单理解为直方图分成几个柱子)
  • range:每个特征空间的取值范围,灰度值[0,255]
  • 计算直方图函数:calcHist()

2 计算图像直方图:calcHist()函数

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)
  • const Mat* images:输入图像
  • int nimages:输入图像的个数
  • const int* channels:需要统计直方图的第几通道
  • InputArray mask:掩膜,,计算掩膜内的直方图 …Mat()统整幅图像的直方图就把它设为None,但如果想统整幅图像某一部分的直方图就制作一个掩膜图像并使用它。
  • OutputArray hist:输出的直方图数组(Mat类型)
  • int dims:需要统计直方图通道的个数
  • const int* histSize:指的是直方图分成多少个区间,,,就是 bin的个数
  • const float** ranges: 统计像素值得区间,[0,255]
  • bool uniform=true:是否对得到的直方图数组进行归一化处理
  • bool accumulate=false:在多个图像时,是否累计计算像素值得个数

下面使用OpenCV函数 ​​calcHist​​ 计算直方图的例子:

calcHist(&rgb_planes[0], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate);

参数说明:

  • &rgb_planes[0]: 输入数组(或数组集)
  • 1: 输入数组的个数 (这里我们使用了一个单通道图像,我们也可以输入数组集 )
  • 0: 需要统计的通道 (dim)索引 ,这里我们只是统计了灰度 (且每个数组都是单通道)所以只要写 0 就行了。
  • Mat(): 掩码( 0 表示忽略该像素), 如果未定义,则不使用掩码
  • r_hist: 储存直方图的矩阵
  • 1: 直方图维数
  • histSize: 每个维度的bin数目
  • histRange: 每个维度的取值范围
  • uniformaccumulate: bin大小相同,清楚直方图痕迹

3 一维灰度直方图

#include<opencv2/opencv.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<iostream>
using namespace std;
using namespace cv;
int main()
{
Mat img = imread("E:\\Pec\\car.jpg",0);//以灰度方式打开
imshow("src", img);
Mat dstHist;//定义存储直方图变量
int dims = 1;//统计特征数目
float hranges[] = { 0,256 };
const float* ranges = { hranges };
int bins = 256;
int channels = 0;
//计算直方图
//calcHist(&img, 1, 0, Mat(), dstHist, dims, &size, ranges, true, false);
calcHist(&img, 1, &channels, Mat(), dstHist, dims, &bins, &ranges, true, accumulate);
//上述计算得到的结果都存入dstHist中
int scale = 1;
//创建一个高和宽的图像,初始像素是0
Mat dstImage(bins * scale, bins * 3, CV_8UC3, Scalar(0));

double minValue = 0;
double maxValue = 0;
//统计最大值、最小值以及返回位置
minMaxLoc(dstHist, &minValue, &maxValue, 0, 0);
//saturate_cast函数在OpenCV中的作用是防数据溢出,我们在直接操作像素点的时候,
//如果数值结果是赋值或者超过了255的话,在图片中是没办法显示的,这就是防数据溢出的作用,那么什么时候会有数据溢出的风险呢,这种情况在图像卷积操作的时候比较常见。
int pht = saturate_cast<int>(0.9*bins);//设置最大值防止溢出
int j = 0;
for (int i = 0; i < 256; i=i+2)
{
//src.at<uchar>(i,j); //取灰度图像中第i行第j列的点
//src.at<Vec3b>(i,j)[K] 取彩色图像中第i行第j列第K通道的点
float binValue = dstHist.at<float>(i);
int realValue = saturate_cast<int>(binValue*pht / maxValue);//归一化,等变量变小了
cout << "i= " << i << "---value= " << realValue << endl;
//画图的地方,起点,终点,线的颜色,线宽,线型
//line(dstImage, Point(i*scale, bins - 1), Point(i*scale, bins - realValue), Scalar(0, 255, 0), 1, 8);
//花矩形的方式
rectangle(dstImage, Point(j*scale, bins - 1), Point((j + 2)*scale - 1, bins - realValue), Scalar(0, 255, 0),-1);

j = j + 3;
}
imshow("Histogram", dstImage);
waitKey(0);
}

【OpenCV】直方图计算 & 均衡化直方图_计算机视觉_07

4 不均匀灰度直方图

#include<opencv2/opencv.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<iostream>
using namespace std;
using namespace cv;
int main()
{
Mat img = imread("E:\\Pec\\car.jpg",0);//以灰度方式打开
imshow("src", img);
Mat dstHist;//定义存储直方图变量
int dims = 1;//统计特征数目
int histSize[1] = { 5 };
float hranges[6] = {0, 50,100,150,200,256 };
const float* ranges[1] = { hranges };
int bins = 256;
int channels = 0;
int size = 256;
//计算直方图
calcHist(&img, 1, &channels, Mat(), dstHist,1, histSize, ranges, false);
//上述计算得到的结果都存入dstHist中
int scale = 1;
//创建一个高和宽的图像,初始像素是0
Mat dstImage(bins * scale, bins, CV_8UC3, Scalar(0));

double minValue = 0;
double maxValue = 0;
//统计最大值、最小值以及返回位置
minMaxLoc(dstHist, &minValue, &maxValue, 0, 0);
//saturate_cast函数在OpenCV中的作用是防数据溢出,我们在直接操作像素点的时候,
//如果数值结果是赋值或者超过了255的话,在图片中是没办法显示的,这就是防数据溢出的作用,那么什么时候会有数据溢出的风险呢,这种情况在图像卷积操作的时候比较常见。
int pht = saturate_cast<int>(0.9*bins);//设置最大值防止溢出
int j = 0;
for (int i = 0; i < 5; i=i+1)
{
//src.at<uchar>(i,j); //取灰度图像中第i行第j列的点
//src.at<Vec3b>(i,j)[K] 取彩色图像中第i行第j列第K通道的点
float binValue = dstHist.at<float>(i);
int realValue = saturate_cast<int>(binValue*pht / maxValue);//归一化,等变量变小了
cout << "i= " << i << "---value= " << realValue << endl;
//画图的地方,起点,终点,线的颜色,线宽,线型
//line(dstImage, Point(i*scale, bins - 1), Point(i*scale, bins - realValue), Scalar(0, 255, 0), 1, 8);
//花矩形的方式
rectangle(dstImage, Point(j*scale, bins - 1), Point((j + 20)*scale - 1, bins - realValue), Scalar(0, 255, 0),-1);

j = j + 35;
}
imshow("Histogram", dstImage);
waitKey(0);
}

【OpenCV】直方图计算 & 均衡化直方图_直方图_08

原图的直方图与均衡化的直方图对比

#include<opencv2/opencv.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<iostream>
using namespace std;
using namespace cv;
Mat equalize(Mat src)
{
Mat img ;
src.copyTo(img);
Mat dstHist;//定义存储直方图变量
int dims = 1;//统计特征数目
float hranges[] = { 0,256 };
const float* ranges = { hranges };
int bins = 256;
int channels = 0;
//计算直方图
calcHist(&img, 1, &channels, Mat(), dstHist, dims, &bins, &ranges, true, accumulate);
//上述计算得到的结果都存入dstHist中
int scale = 1;
//创建一个高和宽的图像,初始像素是0
Mat dstImage(bins * scale, bins * 3, CV_8UC3, Scalar(0));

double minValue = 0;
double maxValue = 0;
//统计最大值、最小值以及返回位置
minMaxLoc(dstHist, &minValue, &maxValue, 0, 0);
int pht = saturate_cast<int>(0.9*bins);//设置最大值防止溢出
int j = 0;
for (int i = 0; i < 256; i = i + 1)
{
float binValue = dstHist.at<float>(i);
int realValue = saturate_cast<int>(binValue*pht / maxValue);//归一化,等变量变小了
//画图的地方,起点,终点,线的颜色,线宽,线型
line(dstImage, Point(i*scale, bins - 1), Point(i*scale, bins - realValue), Scalar(rand() % 255, rand() % 255, rand() % 255), 1, 8);

j = j + 3;
}
return dstImage;

}
int main()
{
Mat src, dst;
src = imread("E:\\Pec\\cat.jpg",0);
imshow("【原始图】", src);
//进行直方图均衡化
equalizeHist(src, dst);
//显示结果
imshow("【经过直方图均衡化后的图】", dst);
Mat dstImage1=equalize(src);
imshow("【未均衡化的直方图】", dstImage1);
Mat dstImage2 = equalize(dst);
imshow("【均衡化的直方图】", dstImage2);
waitKey(0);
}

【OpenCV】直方图计算 & 均衡化直方图_图像处理_09


标签:Mat,int,均衡化,OpenCV,直方图,灰度,bins
From: https://blog.51cto.com/u_14935708/6057324

相关文章

  • 【OpenCV】-查找并绘制轮廓
    文章目录​​1寻找轮廓:findContours()函数​​​​2绘制轮廓:drawContours()函数​​​​3示例程序​​1寻找轮廓:findContours()函数说明:findContours()函数是在二值图像......
  • 【OpenCV】- 分水岭算法
    文章目录​​什么是图像分割​​​​分水岭算法​​​​1、实现分水岭算法:watershed()函数​​​​2、处理流程(视频)​​​​3、示例程序(书中)​​什么是图像分割将图像中像素......
  • 【opencv c++】实现yolov5部署onnx模型完成目标检测
    总代码#include<fstream>#include<sstream>#include<iostream>#include<opencv2/dnn.hpp>#include<opencv2/imgproc.hpp>#include<opencv2/highgui.hpp>usin......
  • OpenCV连续显示类似视频一样
    cv::VideoCapturevideo=VideoCapture(); video.open("D:\\Temp\\Videos\\黄原胶.mp4");//读取视频 if(!video.isOpened()){ printf("couldnotreadthisvideofil......
  • OpenCV-Python扩充数据集
    在深度学习中,数据集规模直接影响模型训练后的性能。当我们数据集较少的时候可以通过不同的手段对现有的数据进行扩充。比如裁切,翻转,旋转,加入噪点,调整亮度等手段进行数据集......
  • 使用opencv库,从摄像机捕获视频并在窗口中显示视频帧
    使用opencv库,从摄像机捕获视频并在窗口中显示视频帧#导入opencv库,用于图像处理和计算机视觉任务。importcv2#设置显示视频的显示窗口的宽度和高度(以像素为单位)dispW......
  • 关于全景(360)图片拼接的方法(Opencv3.0 Stitcher)
    PS:要转载请注明出处,本人版权所有。PS:这个只是基于《我自己》的理解,如果和你的原则及想法相冲突,请谅解,勿喷。前置说明  本文作为本人csdnblog的主站的备份。(BlogID......
  • 关于全景(360)图片拼接的方法(Opencv3.0 Stitcher)----续(一)
    PS:要转载请注明出处,本人版权所有。PS:这个只是基于《我自己》的理解,如果和你的原则及想法相冲突,请谅解,勿喷。前置说明  本文作为本人csdnblog的主站的备份。(BlogID......
  • opencv对鱼眼图像畸变矫正
         //=========================对原始图像畸变矫正========================== doublefx=355.0974745605948; doublefy=355.47832693......
  • opencv中的读写视频和图片中有中文路径
    importcv2#表示参数是视频文件路径则打开视频video=cv2.VideoCapture("D:/Temp/测试/1.mp4")#循环读取每一帧i=1while(video.isOpened()):  ret,frame=video......