opencv笔记(二十一)——关于直方图的几个操作

一、直方图均衡化

考虑四种图像。

在暗色图像中,直方图的组成成分集中在灰度级低的一侧。

明亮图像的直方图倾向于灰度级高的一侧。

低对比度图像的直方图窄而集中于灰度级的中部。

高对比度图像的直方图的成分覆盖了灰度级很宽的范围。

在遇到前三种图像的时候,可能我们需要直方图均衡化,用来使一幅图像的像素占有全部可能的灰度级并且分布均匀,这样的图像有高对比度和多变的灰度色调。

OpenCV中,我们使用equalizeHist来对灰度图像进行直方图均衡化:

 equalizeHist(InputArray src, OutputArray dst)

src一般为8位单通道的图像。

dst和src有相同的尺寸和类型。

二、如果一幅图像是三通道的,我们要对每个通道进行直方图的统计,那么该如何做呢?

分析一段OpenCV的实例代码我们便知:

// 使用split函数,将BGR三通道分开

vector<Mat> bgr_planes;

split(src, bgr_planes); // src is the source image we read into Mat before

// 使用calcHist函数进行直方图的统计,这个函数的使用关键在于它的参数的设置。它的参数设置比较复杂。

/// Establish the number of bins
int histSize = 256;

/// Set the ranges ( for B,G,R) )
float range[] = { 0, 256 } ;
const float* histRange = { range };

bool uniform = true;

bool accumulate = false;

Mat b_hist, g_hist, r_hist; // 这三个参数分别用来记录bgr的直方图

/// Compute the histograms:
calcHist( &bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate );
calcHist( &bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate );
calcHist( &bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate );

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 acculate=false)

对照上边calcHist函数的实例,我们可以看出

image是待统计直方图的图像的输入,类型为指针,可以让我们给数组或者vector,支持多个image处理。我们这里只要处理一个,所以直接给地址。输入的图像如果有多个,则他们应该尺寸和深度都相同。

nimages说明输入的个数。

channels应该也是一个数组,我们这里只要处理一幅单通道的输入,应该给入int channels[] = { 0 },这里直接给0也行,不知道为什么。

mask是掩膜,如果mask非空,则mask需要跟输入有相同尺寸,mask为1的位置计入直方图。我们这里给Mat()。

hist是输出。

dims是直方图的维度。这里是1。就是一维直方图。还有三维直方图,返回三维的cv::Mat实例。

histSize是直方图的尺寸,这里是256.

histRange是每个维度的直方图的范围。

三、将直方图归一化:

接上例:

/// Normalize the result to [ 0, histImage.rows ]
normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );

normalize的第一个参数是输入,第二个参数是输出,在第五个参数为NORM_MINMAX的情况下,第三个参数和第四个参数分别为下限和上限。第六个参数为负,说明输入和输出的类型相同。第七个参数为掩膜。

四、绘制直方图:

接上例:

int hist_w = 512; int hist_h = 400;

int bin_w = cvRound( (double) hist_w/histSize );

Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) );

/// Draw for each channel
for( int i = 1; i < histSize; i++ )
{
  line( histImage, Point( bin_w*(i-1), hist_h - cvRound(b_hist.at<float>(i-1)) ) ,
  Point( bin_w*(i), hist_h - cvRound(b_hist.at<float>(i)) ),
  Scalar( 255, 0, 0), 2, 8, 0 );
  line( histImage, Point( bin_w*(i-1), hist_h - cvRound(g_hist.at<float>(i-1)) ) ,
  Point( bin_w*(i), hist_h - cvRound(g_hist.at<float>(i)) ),
  Scalar( 0, 255, 0), 2, 8, 0 );
  line( histImage, Point( bin_w*(i-1), hist_h - cvRound(r_hist.at<float>(i-1)) ) ,
  Point( bin_w*(i), hist_h - cvRound(r_hist.at<float>(i)) ),
  Scalar( 0, 0, 255), 2, 8, 0 );
}

五、直方图的比较

有了几个直方图,我们就可以比较直方图之间的差别。

要比较直方图,我们首先要设定比较的尺度或者方法,一般有四种:

  1. Correlation ( CV_COMP_CORREL )  范围从0到1。1为完全相关,0为完全不相关。

    where

    and  is the total number of histogram bins.

  2. Chi-Square ( CV_COMP_CHISQR )  范围从0到正无穷。0为完全相似,数字越大,直方图差别越大。(数字幅度变化较大)

  3. Intersection ( method=CV_COMP_INTERSECT )  范围从0到正无穷,数字越大,表示越相似,因为直方图交集越多。数字越小,表示差别越大。(数字幅度变化较小)

  4. Bhattacharyya distance ( CV_COMP_BHATTACHARYYA )  范围从0到1。0表示完全相似。1表示完全不同。

一般在比较直方图之前,要先对直方图归一化处理,使用上一步所说的normalize函数,把上限改为1就好了。

在OpenCV的例子中,给了三幅图,是分别在不同的角度和光线下,对一只手掌拍摄的照片。然后比较这几张照片的HSV格式的H-S两维的直方图,忽略V。

对比直方图的方法是compareHist,是这么用的:

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

H1和H2是待对比的两幅直方图

method是对比的方法,从0到3分别是CV_COMP_CORREL, CV_COMP_CHESQR, CV_COMP_INTERSECT, CV_COMP_BHATTACHARYYA。

六、反投影直方图 Back Projection

反投影直方图简单说来,就是我们首先有了一份样本的直方图,然后拿到一幅图片,我们计算这幅图片上每个像素属于这个直方图的概率值。就叫反投影。

void calcBackProject(const Mat* images, int nimages, const int* channels, const SparseMat& hist, OutputArray backProject, const float** ranges, double scale=1, bool uniform=true)

image 待投影的图像,可以多个,但是要有一样的depth

nimages 图像个数

channels 用来投影的通道

hist 直方图(这个比较重要)

backProject 输出的图像

ranges 直方图的范围

时间: 2024-07-28 13:10:08

opencv笔记(二十一)——关于直方图的几个操作的相关文章

马哥学习笔记二十一——LVS DR模型

kernel parameter: arp_ignore: 定义接收到ARP请求时的响应级别: 0:只要本地配置的有相应地址,就给予响应: 1:仅在请求的目标地址配置请求到达的接口上的时候,才给予响应: arp_announce:定义将自己地址向外通告时的通告级别: 0:将本地任何接口上的任何地址向外通告: 1:试图仅向目标网络通告与其网络匹配的地址: 2:仅向与本地接口上地址匹配的网络进行通告: curl命令选项: --cacert <file> CA证书 (SSL) --capath &l

《Programming in Lua 3》读书笔记(二十一)

日期:2014.8.1 PartⅣ The C API 25 An Overview of the C API Lua是一种嵌入式语言.这就意味着Lua不是单独存在的,而是可以通过一系列的标准库将lua的特性嵌入至其他应用模块中. Lua以Lua interpreter(lua的解释器?)来解决了其不是独立程序,我们直到现在却又能独立使用Lua的问题.这个解释器是一个小型的程序(不超过500行代码),使用lua的标准库来实现独立解释程序,这个程序将处理与用户的交互等操作交给lua的标准库,这些库

Android学习笔记二十一.使用ContentProvider实现数据共享(四).操作系统(联系人)的ContentProvider

Android系统本身提供了大量的ContentProvider,例如联系人信息.系统的多媒体信息等,我们开发的应用程序主要是通过ContentResolver来调用系统的ContentProvider提供的query().insert().update()和delete()方法来获取Android内部的数据. 一.如何使用ContentResolver操作系统ContentProvider暴露的内部数据? 1.调用Activity的getContentResolver()获取ContentRe

(转)【D3D11游戏编程】学习笔记二十一:Cube Mapping及其应用之一:天空盒的实现

(注:[D3D11游戏编程]学习笔记系列由CSDN作者BonChoix所写,转载请注明出处:http://blog.csdn.net/BonChoix,谢谢~) 这一节讨论有关纹理映射的进阶内容:Cube Mapping. 1. 简介 单从名字上,就大概可以看出点端倪了,翻译成中文为立方体映射,因此肯定跟立方体有关系.确实,Cube Mapping就是使用六张正方形的图片来进行纹理映射的.这六张图片分别对应了一个立方体中的六个面.由于这个立方体是轴对齐的,因此每个面可以用坐标系中的六个轴方向来惟

Linux学习笔记&lt;二十一&gt;——busybox制作小系统

制作流程: kernel->initrd(busybox)->rootfs(busybox) kernel:直接利用/boot/vmlinuz-`uname -r`内核镜像或手动编译生成 initrd:编译busybox,在busybox的基础上建立initrd rootfs:同样在busybox的基础上建立rootfs 一.为小系统上的新硬盘建立分区并挂载在宿主机的相应目录,以便创建修改文件. /dev/hda1    100M    boot分区    挂载在/mnt/boot /dev/

Java笔记二十一.深入解析I/O编程之节点流

深入解析I/O编程之节点流 转载请表明出处:http://blog.csdn.net/u012637501(嵌入式_小J的天空) 在上一节我们说到IO流主要分为两个大类:节点流类和过滤流类(也称包装类).程序用于直接操作目标设备所对应的类叫节点流类;为更加灵活方便地读写各种类型的数据,程序也可用通过一个间接流类去调用节点流类而这个简介流类即为过滤流类(也称为包装类). 总之,无论是节点流类还是过滤流类,它们都属于字节流或字符流其中的一种.下面我们介绍一下常见的节点流类有哪些. 字****节***

OpenCV笔记(十一)——图像的阈值操作(一种分割的方法)

对图像进行阈值的操作,可以认为是一种简单的分割前景和背景的方法. 这种分割的方法一般用在前景像素和背景像素的强度值反差比较明显的情况下,如下图: 我们可以看到这幅苹果的图像,代表前景的是苹果,代表背景的是白色部分.这幅图像前景背景分明,所以可以取一个阈值,如200.在图像中,凡是灰度低于200的像素,我们认作是前景,将其值设为255,凡是灰度不低于200的像素,我们认作是背景,将其值设为0.获得一张新的Mask,将原始的图像与这张Mask做与(&)运算,就能够得到分割好的图像. 一般来说,阈值化

kvm虚拟化学习笔记(二十一)之KVM性能优化学习笔记

本学习笔记系列都是采用CentOS6.x操作系统,KVM虚拟机的管理也是采用virsh方式,网上的很多的文章都基于ubuntu高版本内核下,KVM的一些新的特性支持更好,本文只是记录了CentOS6.x系列操作系统下KVM优化的点,有很多都是默认支持开启了的,除了采用virtio方式的磁盘IO,与网络IO接口优化之外,其它真是无需太多优化. 1. CPU性能优化 (1) 服务器或宿主机主板BIOS中开启Intel Virtualization Technology(简称VT), 如果主板支持In

Java基础学习笔记二十一 多线程

多线程介绍 学习多线程之前,我们先要了解几个关于多线程有关的概念.进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程.一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序. 简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程 什么是多线程呢?即就是一个程序中有多个线程在同时执行.通过下图来区别单线程程序与

过滤器(web基础学习笔记二十一)

一.过滤器简介 二.在Eclipse中创建过滤器 三.使用过滤器设置全部web字符编码 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // TODO Auto-generated method stub // place your code here // pass the reques