OpenCV 学习笔记
直方图(HIstogram)介绍
直方图又称质量分布图,表示变量分布的统计图。可以将数据的概率分布精确地显示出来。通过将整个范围的数据区间分成固定数量的颜色值,然后计算在该颜色值的个数来创建直方图。
在图像中应用直方图即图像直方图,图像直方图拥有计算代价小,且具有图像平移、旋转、缩放不变性等优点。它用于表示图像的亮度分布,描绘了每个亮度值的像素个数,即变量为亮度值。
图像均衡化
图像均衡化即通过对其直方图的分布作一定的处理,使图像的对比度增高,增强其纹理。均衡化允许低对比度区域获得高对比度,扩展亮度。均衡化操作主要针对于太亮、太暗以及那些图像整体差异不大的图像。但这个方法也存在一些缺点,如增加背景噪声等。
1. split(const Mat& src,Mat *mv);
这是一个使 多通道图像 分离成 单通道图像 的函数 ,一般将BGR三通道分离。
第一个参数 src表示的是需要进行通道分离的图像;
第二个参数 mv用来储存分离出来的通道,它可以是Mat数组的首地址,或者一个vector<Mat>对象
我们会发现,分离出的单通道图像一般为黑白图像,而不是代表B、G、R的蓝、绿、红图像,原因在于分离之后的单通道图像中的另外两个通道均被赋值为该通道的值,而不是为0,所以显示的图像为黑白。
2. merge(const Mat* mv, int count, Mat output_Img);
这是一个使 单通道图像 合并成 多通道图像 的函数,显然,与split函数是相对的。
第一个参数 mv是储存的多个单通道图像,同split函数中的mv参数;
第二个参数 count为通道的个数;
第三个参数为需要生成的多通道图像 output_Img
3. calcHist();
// calcHist()函数的定义如下
void calcHist( const Mat* arrays,
int count,
const int* channels,
InputArray mask,
OutputArray hist,
int dims,
const int* histSize,
const float** ranges,
bool uniform =true,
bool accumulate = false );
这是一个计算直方图的函数
第一个参数 arrays是输入图像的指针,可以是多个同样深度的图像;
第二个参数 count为输入图像的个数;
第三个参数 channels为用来计算直方图的通道数组;
第四个参数 mask为掩膜 ;
第五个参数 hist为输出的直方图;
第六个参数 dims为需要统计的直方图的通道个数;
第七个参数 histSize为直方图分成的区间个数;
第八个参数 ranges为直方图像素值的区间;
第九个参数 uniform表示是否对直方图数组进行归一化处理;
第十个参数 accumulate表示是否从多个阵列中计算单个直方图或在特定时间更新直方图
关于 mask( 掩膜 )的详细内容请参考链接 :https://blog.csdn.net/bitcarmanlee/article/details/79132017
4.normalize( const Mat& src , Mat& dst , double alpha , double beta , int normalType );
这是一个归一化函数,将数据进行处理限制在一定的范围内,保证程序运行时收敛加快。
第一个参数 src为输入的图像;
第二个参数 dst为输出的与src相同大小的图像;
第三个参数 alpha为规定范围的下限;
第四个参数 beta为规定范围的上限;
第五个参数 normalType为归一化所用到的方法
关于第五个参数的方法类型如下:
- NORM_MINMAX: 数组的值被缩放到一个指定范围内,即(MIN —— MAX)
- NORM_INF: 归一化数组的 L
∞
\infty
∞范数,即 切比雪夫距离( 向量空间中的一种度量,表示为两点坐标值的差的最大值 )
D = m a x ( a b s ( x 2 − x 1 ) , a b s ( y 2 − y 1 ) ) D=max(abs(x2-x1) , abs(y2-y1)) D=max(abs(x2−x1),abs(y2−y1)) - NORM_L1: 归一化数组的 L1-范数,即曼哈顿距离 ( 表示为两点轴距离差之和 )
D = a b s ( x 2 − x 1 ) + a b s ( y 2 − y 1 ) D=abs(x2-x1) + abs(y2-y1) D=abs(x2−x1)+abs(y2−y1) - NORM_L2: 归一化数组的 L2-范数,即欧几里德距离 ( 表示为两点之间的直线距离 )
D = s q r t ( ( x 2 − x 1 ) 2 + ( y 2 − y 1 ) 2 ) D=sqrt((x2-x1)^2 + (y2-y1)^2) D=sqrt((x2−x1)2+(y2−y1)2)
5.line( Mat& img , Point pt1 , Point pt2, const Scalar& color, int thickness=1, int lineType=8 , int shift=0 )
这是一个画直线的函数,从起始点pt1到终点pt2画一条直线。
第一个参数 img为需要绘制线段的图像;
第二个参数 pt1表示的是画线的起始点;
第三个参数 pt2表示的是画线的终点;
第四个参数 color表示的是线段的颜色,为Scalar类型;
第五个参数 thickness表示的是线段的厚度,默认为1;
第六个参数 lineType表示的是线段的类型,默认为8,即邻接连接线;
第七个参数 shift表示为坐标点小数点的位数,默认为1
6.equalizeHist( InputArray src , OutputArray dst );
这是一个直方图均衡化的函数,用以提升图像质量。
第一个参数 src为输入的图像,且是单通道图像;
第二个参数 dst为输出的图像,与src拥有同样的格式
代码演示如下:
#CMakeLists.txt文件内容
cmake_minimum_required(VERSION 2.8)
project(test10)
set(CMAKE_CXX_FLAGS "-std=c++11")
include_directories(${OpenCV_INCLUDE_DIRS})
find_package( OpenCV 3 REQUIRED )
add_executable( test10 test10.cpp)
target_link_libraries( test10 ${OpenCV_LIBS})
// test10.cpp 文件内容
#include<iostream>
#include<string>
#include<cmath>
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
const char*key = {
"{ help h ? | | print this message}"
"{ @image | | image to process}"
};
//定义图片对象img
Mat img;
int main ( int argc , char ** argv)
{
//声明回调函数
void showHistogramCallback(int state, Mat img);
void equalizeHistogramCallback(int state , Mat img);
CommandLineParser parser( argc , argv , key );
parser.about("This is Opencv project");
//查询是否需要帮助消息
if(parser.has("help")||parser.has("h")||parser.has("?")){
parser.printMessage();
return 0;
}
//获取输入的参数
String imgfile = parser.get<String>(0);
//检查参数是否正确
if(!parser.check()){
parser.printErrors();
return 0;
}
//加载图像
img = imread(imgfile);
//创建窗口
namedWindow("Image",0);
//显示图片
imshow("Image",img);
//显示直方图
showHistogramCallback(1,img);
//显示均衡化图像
equalizeHistogramCallback(1,img );
waitKey(0);
return 0;
}
//显示图像直方图的函数
void showHistogramCallback(int state , Mat img)
{
//把图像分成三个通道B、G、R
vector<Mat> bgr;
split(img,bgr);
//创建一个能够显示0-255灰度值的直方图
int num = 256;
//设置范围
float range[] = { 0 , 256 }; //不包含256
const float*histrange = { range };
//定义三个单通道图像
Mat b_hist , g_hist , r_hist;
//计算直方图
calcHist( &bgr[0] , 1 , 0 , Mat() , b_hist , 1 , &num , &histrange);
calcHist( &bgr[1] , 1 , 0 , Mat() , g_hist , 1 , &num , &histrange);
calcHist( &bgr[2] , 1 , 0 , Mat() , r_hist , 1 , &num , &histrange);
//直方图的大小设置
int width = 512;
int height = 300;
//创建以灰色会底的图像
Mat histImage( height , width , CV_8UC3 , Scalar(20,20,20));
//从0到图像的高度归一化处理
normalize(b_hist , b_hist , 0 , height ,NORM_MINMAX );
normalize(g_hist , g_hist , 0 , height ,NORM_MINMAX );
normalize(r_hist , r_hist , 0 , height ,NORM_MINMAX );
//每个像素值区间的步长
int binStep = cvRound((float)width/(float)num);
for(int i=1 ; i<num ; i++){
// 绘制通道b的直方图
line( histImage ,
Point(binStep*(i-1) , height-cvRound( b_hist.at<float>(i-1) ) ) ,
Point(binStep*(i) , height-cvRound( b_hist.at<float>(i) ) ) ,
Scalar( 255 , 0 , 0 ) );
//绘制通道g的直方图
line( histImage ,
Point(binStep*(i-1) , height-cvRound( g_hist.at<float>(i-1) ) ) ,
Point(binStep*(i) , height-cvRound( g_hist.at<float>(i) ) ) ,
Scalar( 0 , 255 , 0 ) );
//绘制通道r的直方图
line( histImage ,
Point(binStep*(i-1) , height-cvRound( r_hist.at<float>(i-1) ) ) ,
Point(binStep*(i) , height-cvRound( r_hist.at<float>(i) ) ) ,
Scalar( 0 , 0 , 255 ) );
}
//显示绘制好的直方图
imshow("Histogram" , histImage );
}
//显示图像色彩均衡化的函数
void equalizeHistogramCallback(int state ,Mat img )
{
//用来储存结果图像
Mat result;
//将RGB图像转为YCrCb图像,Y表示亮度,CrCb代表色彩
Mat ycrcb;
cvtColor( img , ycrcb , COLOR_BGR2YCrCb );
//图像通道分离
vector<Mat> channels;
split( ycrcb , channels );
//只对Y(亮度)通道进行均衡操作
equalizeHist( channels[0] , channels[0] );
//合并通道
merge( channels , ycrcb );
//将YCrCb图像转为RGB图像
cvtColor( ycrcb , result , COLOR_YCrCb2BGR );
//显示图像
imshow( "Equalized" , result );
}
演示结果如下
先展示文件目录结构
然后使用命令行来输入图片信息
$ ./test lena.jpeg
左侧为测试图像,右侧为直方图
左侧为均衡化后的图像