1  图像直方图

1.1  定义

  统计各个像素值,在整幅图像中出现次数的一个分布函数。

      

1.2  标准化

$\quad p_r(r_k) = \frac{n_k}{MN} \qquad k = 0, 1, 2, ..., L -1 $

  $r_{k}$ - 第 k 个像素灰度值;  $n_{k}$ - 像素灰度值为 rk 的像素数目;

  MN - 图像中总的像素个数;  [0, L-1] - 像素灰度值的范围

1.3  直方图均衡化

1.3.1  定义 

直方图均衡化,是将给定图像的直方图改造成均匀分布的直方图,从而扩大像素灰度值的动态范围,达到增强图像对比度的效果。

$\quad s_k = \frac{(L - 1)}{MN} \sum\limits_{j=0}^k n_j \qquad k = 0, 1, 2, ..., L - 1 $

       

       

1.3.2  实例

一幅灰度值范围是[0, 7],64行64列的数字图像,其灰度分布如下表所示,求直方图均衡化之后的灰度分布。

  r(k)  n(k)  P(rk)
 r(0) = 0  790   0.19
 r(1) = 1  1023  0.25
 r(2) = 2  850  0.21
 r(3) = 3  656  0.16
 r(4) = 4  329  0.08
 r(5) = 5  245  0.06
 r(6) = 6  122  0.03
 r(7) = 7  81  0.02

根据上述公式得, s(0)=1.33≈1,s(1)=3.08≈3,s(2)≈5,s(3)≈6,s(4)≈6,s(5)≈7,s(6)≈7,s(7)≈7

因为 r(k) -> s(k),所以 s(0)=1 对应有790个像素值。因为r(3), r(4) 分别对应 s(3), s(4),且 s(3)=s(4)=6,

故像素值为6的像素数为 (656+329)个,同理可计算像素值为7的像素数。

将不同像素值对应的的像素数除以MN(图像的像素总数),便得到均衡化之后的灰度直方图,如下所示:

2  四个参数

  H1 和 H2 为两个待比较的直方图。1) 和 2) 的值越大,二者越匹配;而 3) 和 4) 的值越小,两者越匹配。

1) Correlation

2) Intersection

3) Chi-square

4) Bhattacharyya distance

3  OpenCV中的函数

3.1  equalizeHist

void equalizeHist (
   InputArray src, // 输入图像
   OutputArray dst // 输出图像
);

源码:

void cv::equalizeHist( InputArray _src, OutputArray _dst )
{
CV_Assert( _src.type() == CV_8UC1 ); if (_src.empty())
return; CV_OCL_RUN(_src.dims() <= && _dst.isUMat(),
ocl_equalizeHist(_src, _dst)) Mat src = _src.getMat();
_dst.create( src.size(), src.type() );
Mat dst = _dst.getMat(); Mutex histogramLockInstance; const int hist_sz = EqualizeHistCalcHist_Invoker::HIST_SZ;
int hist[hist_sz] = {,};
int lut[hist_sz]; EqualizeHistCalcHist_Invoker calcBody(src, hist, &histogramLockInstance);
EqualizeHistLut_Invoker lutBody(src, dst, lut);
cv::Range heightRange(, src.rows); if(EqualizeHistCalcHist_Invoker::isWorthParallel(src))
parallel_for_(heightRange, calcBody);
else
calcBody(heightRange); int i = ;
while (!hist[i]) ++i; int total = (int)src.total();
if (hist[i] == total)
{
dst.setTo(i);
return;
} float scale = (hist_sz - .f)/(total - hist[i]);
int sum = ; for (lut[i++] = ; i < hist_sz; ++i)
{
sum += hist[i];
lut[i] = saturate_cast<uchar>(sum * scale);
} if(EqualizeHistLut_Invoker::isWorthParallel(src))
parallel_for_(heightRange, lutBody);
else
lutBody(heightRange);
}

3.2  calcHist

void cv::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 )

3.3  compareHist

double cv::compareHist (
InputArray H1,
InputArray H2,
int method
)

4  实例

4.1  直方图计算

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgcodecs/imgcodecs.hpp"
#include "opencv2/imgproc/imgproc.hpp" using namespace cv; int main( int, char** argv )
{
Mat src, dst; // 1) Load image
src = imread("left.png");
if(src.empty()) {
return -;
} // 2) Separate the image in 3 places ( B, G and R )
std::vector<Mat> bgr_planes;
split( src, bgr_planes ); // 3) Establish the number of bins
int histSize = ; // 4) Set the ranges (for B,G,R)
float range[] = { , } ;
const float* histRange = { range }; bool uniform = true;
bool accumulate = false; Mat b_hist, g_hist, r_hist; // 5) Compute the histograms
calcHist( &bgr_planes[], , , Mat(), b_hist, , &histSize, &histRange, uniform, accumulate );
calcHist( &bgr_planes[], , , Mat(), g_hist, , &histSize, &histRange, uniform, accumulate );
calcHist( &bgr_planes[], , , Mat(), r_hist, , &histSize, &histRange, uniform, accumulate ); // 6) Draw the histograms for B, G and R
int hist_w = ;
int hist_h = ;
int bin_w = cvRound( (double) hist_w/histSize ); Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( ,,) ); // 7) Normalize the result to [ 0, histImage.rows ]
normalize(b_hist, b_hist, , histImage.rows, NORM_MINMAX, -, Mat() );
normalize(g_hist, g_hist, , histImage.rows, NORM_MINMAX, -, Mat() );
normalize(r_hist, r_hist, , histImage.rows, NORM_MINMAX, -, Mat() ); // 8) Draw for each channel
for( int i = ; i < histSize; i++ )
{
line( histImage, Point( bin_w*(i-), hist_h - cvRound(b_hist.at<float>(i-)) ) ,
Point( bin_w*(i), hist_h - cvRound(b_hist.at<float>(i)) ),
Scalar( , , ), , , );
line( histImage, Point( bin_w*(i-), hist_h - cvRound(g_hist.at<float>(i-)) ) ,
Point( bin_w*(i), hist_h - cvRound(g_hist.at<float>(i)) ),
Scalar( , , ), , , );
line( histImage, Point( bin_w*(i-), hist_h - cvRound(r_hist.at<float>(i-)) ) ,
Point( bin_w*(i), hist_h - cvRound(r_hist.at<float>(i)) ),
Scalar( , , ), , , );
} // 9) Display
imshow("calcHist Demo", histImage ); waitKey();
}

4.2  直方图均衡化

#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h> using namespace cv;
using namespace std; int main( int, char** argv )
{
Mat src, dst; const char* source_window = "Source image";
const char* equalized_window = "Equalized Image"; // Load image
src = imread( argv[], ); if( src.empty() )
{ cout<<"Usage: ./Histogram_Demo <path_to_image>"<<endl;
return -;
} // Convert to grayscale
cvtColor( src, src, COLOR_BGR2GRAY ); // Apply Histogram Equalization
equalizeHist( src, dst ); // Display results
namedWindow( source_window, WINDOW_AUTOSIZE );
namedWindow( equalized_window, WINDOW_AUTOSIZE ); imshow( source_window, src );
imshow( equalized_window, dst ); // Wait until user exits the program
waitKey(); return ; }

4.3  直方图比较

#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h> using namespace std;
using namespace cv; /**
* @function main
*/
int main( int argc, char** argv )
{
Mat src_base, hsv_base;
Mat src_test1, hsv_test1;
Mat src_test2, hsv_test2;
Mat hsv_half_down; /// Load three images with different environment settings
if( argc < )
{
printf("** Error. Usage: ./compareHist_Demo <image_settings0> <image_setting1> <image_settings2>\n");
return -;
} src_base = imread( argv[], );
src_test1 = imread( argv[], );
src_test2 = imread( argv[], ); /// Convert to HSV
cvtColor( src_base, hsv_base, COLOR_BGR2HSV );
cvtColor( src_test1, hsv_test1, COLOR_BGR2HSV );
cvtColor( src_test2, hsv_test2, COLOR_BGR2HSV ); hsv_half_down = hsv_base( Range( hsv_base.rows/, hsv_base.rows - ), Range( , hsv_base.cols - ) ); /// Using 50 bins for hue and 60 for saturation
int h_bins = ; int s_bins = ;
int histSize[] = { h_bins, s_bins }; // hue varies from 0 to 179, saturation from 0 to 255
float h_ranges[] = { , };
float s_ranges[] = { , }; const float* ranges[] = { h_ranges, s_ranges }; // Use the o-th and 1-st channels
int channels[] = { , }; /// Histograms
MatND hist_base;
MatND hist_half_down;
MatND hist_test1;
MatND hist_test2; /// Calculate the histograms for the HSV images
calcHist( &hsv_base, , channels, Mat(), hist_base, , histSize, ranges, true, false );
normalize( hist_base, hist_base, , , NORM_MINMAX, -, Mat() ); calcHist( &hsv_half_down, , channels, Mat(), hist_half_down, , histSize, ranges, true, false );
normalize( hist_half_down, hist_half_down, , , NORM_MINMAX, -, Mat() ); calcHist( &hsv_test1, , channels, Mat(), hist_test1, , histSize, ranges, true, false );
normalize( hist_test1, hist_test1, , , NORM_MINMAX, -, Mat() ); calcHist( &hsv_test2, , channels, Mat(), hist_test2, , histSize, ranges, true, false );
normalize( hist_test2, hist_test2, , , NORM_MINMAX, -, Mat() ); /// Apply the histogram comparison methods
for( int i = ; i < ; i++ )
{
int compare_method = i;
double base_base = compareHist( hist_base, hist_base, compare_method );
double base_half = compareHist( hist_base, hist_half_down, compare_method );
double base_test1 = compareHist( hist_base, hist_test1, compare_method );
double base_test2 = compareHist( hist_base, hist_test2, compare_method ); printf( " Method [%d] Perfect, Base-Half, Base-Test(1), Base-Test(2) : %f, %f, %f, %f \n", i, base_base, base_half , base_test1, base_test2 );
} printf( "Done \n" ); return ;
}

参考资料

<Digital Image Processing> 3rd

OpenCV Tutorials / Image Processing (imgproc module) / Histogram Calculation

OpenCV 之 直方图处理的更多相关文章

  1. 【计算机视觉】OpenCV中直方图处理函数简述

    计算直方图calcHist 直方图是对数据集合的统计 ,并将统计结果分布于一系列提前定义的bins中.这里的数据不只指的是灰度值 ,统计数据可能是不论什么能有效描写叙述图像的特征. 如果有一个矩阵包括 ...

  2. opencv——图像直方图与反向投影

    引言 在图像处理中,对于直方图这个概念,肯定不会陌生.但是其原理真的可以信手拈来吗? 本文篇幅有点长,在此列个目录,大家可以跳着看: 分析图像直方图的概念,以及opencv函数calcHist()对于 ...

  3. opencv 比较直方图方式 进行人脸检测对比

    完整opencv(emgucv)人脸.检测.采集.识别.匹配.对比 //成对几何直方图匹配               public static string MatchHist()         ...

  4. 【OpenCV】直方图

    今天写直方图,学了几个相关函数 1. mixChannels void mixChannels(const Mat* src, int nsrc, Mat* dst, int ndst, const ...

  5. Opencv——灰度直方图

    灰度直方图是灰度级的函数,它表示图像中具有某种灰度级的像素的个数,反映了图像中某种灰度出现的频率. 如果将图像总像素亮度(灰度级别)看成是一个随机变量,则其分布情况就反映了图像的统计特性,这可用pro ...

  6. OpenCV处理直方图

    直方图可以用来描述各种不同的事物,如物体的色彩分布.物体边缘梯度模板,以及表示目标位置的当前假设. 简单的说,直方图就是对数据进行统计,将统计值组织到一系列事先定义好的bin中.bin中的数值是从数据 ...

  7. 【Opencv】直方图函数 calchist()

    calchist函数需要包含头文件 #include <opencv2/imgproc/imgproc.hpp> 函数声明(三个重载 calchist函数): //! computes t ...

  8. opencv图像直方图均衡化及其原理

    直方图均衡化是什么有什么用 先说什么是直方图均衡化,通俗的说,以灰度图为例,原图的某一个像素为x,经过某个函数变为y.形成新的图.新的图的灰度值的分布是均匀的,这个过程就叫直方图均衡化. 图像直方图均 ...

  9. opencv 7 直方图与匹配

    图像直方图概述 直方图的计算与绘制 计算直方图:calcHist()函数 找寻最值:minMaxLoc()函数 示例程序:绘制H-S直方图 #include "opencv2/highgui ...

随机推荐

  1. 【转】Python 列表生成式

    原文:https://blog.csdn.net/heartyhu/article/details/50988007 1. 生成列表 要生成list [1, 2, 3, 4, 5, 6, 7, 8, ...

  2. python全局变量被覆盖的问题

    下面的情况,foo全局变量会被局部变量覆盖掉,这样在其它地方使用的值就是空值. g_foo = '' #全局变量 def set(): g_foo = 'abc' # 给全局变量赋值 def use_ ...

  3. 转:x64与x86的改变

    http://tieba.baidu.com/p/1250470248 x64与x86的改变 硬件要求就是64位的CPU.操作系统也必须是64位的,如果在64位的CPU上安装了32位的操作系统,就算编 ...

  4. SGU167 I-country

    嗯以前在某个DP专题了发过这道题,但是当时没码代码,现在重发一篇题解 思考阶段如何划分:由已经处理的行数向下扩展,但是仅有行数我们无法描述状态空间那我们再加入已经选过的格子数,这样我们似乎可以确定我们 ...

  5. Spring 概念详解

    一.Spring的IoC(Inversion of Control). 这是Spring中得有特点的一部份.IoC又被翻译成“控制反转”,也不知道是谁翻译得这么别扭,感觉很深奥的词.其实,原理很简单, ...

  6. 【Vijos 1607】【NOI 2009】植物大战僵尸

    https://vijos.org/p/1607 vijos界面好漂亮O(∩_∩)O~~ 对于一个植物x,和一个它保护的植物y,连一条边<x,y>表示x保护y,对于每个植物再向它左方的植物 ...

  7. HDU 2255 奔小康赚大钱(KM算法)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=2255 [题目大意] 求最大匹配 [题解] KM模板 [代码] #include <cstdi ...

  8. 【计算几何】【分类讨论】Gym - 101243I - Land Division

    题意:给你一个n个点的凸包,让你切一刀,使得它变成一个m边形和一个K边形,问你切的这一刀最短是多少. 如果m+K==n+4,那么一定切在两条边上,但是由于两个线段间的最短距离,至少会经过一条线段的一个 ...

  9. 【动态规划】POJ3280- Cheapest Palindrome

    [题目大意] 给出一个字符串,可以删除或添加一些字符,它们各自会消耗价值.问最少消耗多少价值,可以使得字符串变成回文的. [思路] 事实上删除或添加字符的价值只需要保持较小的那一个.假设当前要将(j, ...

  10. 20162325金立清 实验四 Android程序设计 实验报告

    实验四 Android程序设计 实验报告 代码托管地址 码云链接 实验内容 安装使用Android Stuidio Activity测试 UI测试 布局测试 事件处理测试 Android程序设计-1 ...