《学习OpenCV》第7章 直方图与匹配
4.OpenCV-Python——模版匹配、直方图

4.OpenCV-Python——模版匹配、直⽅图⼀、模版匹配1、模版匹配 模板匹配和卷积原理很像,模板在原图像上从原点开始滑动,计算模板与(图像被模板覆盖的地⽅)的差别程度,这个差别程度的计算⽅法在opencv⾥有6种,然后将每次计算的结果放⼊⼀个矩阵⾥,作为结果输出。
假如原图形是AxB⼤⼩,⽽模板是axb⼤⼩,则输出结果的矩阵是(A-a+1)x(B-b+1)。
TM_SQDIFF:计算平⽅不同,计算出来的值越⼩,越相关TM_CCORR:计算相关性,计算出来的值越⼤,越相关TM_CCOEFF:计算相关系数,计算出来的值越⼤,越相关TM_SQDIFF_NORMED:计算归⼀化平⽅不同,计算出来的值越接近0,越相关TM_CCORR_NORMED:计算归⼀化相关性,计算出来的值越接近1,越相关TM_CCOEFF_NORMED:计算归⼀化相关系数,计算出来的值越接近1,越相关1# *******************模版匹配**********************开始2import cv23import numpy as np4import matplotlib.pyplot as plt56# 模板匹配7 img = cv2.imread('lena.jpg', 0)8 template = cv2.imread('face.jpg', 0)910 h, w = template.shape[:2]1112 methods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR',13'cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED']1415# 匹配⽅法16 res = cv2.matchTemplate(img, template, cv2.TM_SQDIFF)17print(res.shape)18# 匹配结果返回19 min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)20print(min_val,max_val,min_loc,max_loc)2122# 6种不同⽅法⽐较23for meth in methods:24 img2 = img.copy()2526# 匹配⽅法的真值27 method = eval(meth)28print (method)29 res = cv2.matchTemplate(img, template, method)30 min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)3132# 如果是平⽅差匹配TM_SQDIFF或归⼀化平⽅差匹配TM_SQDIFF_NORMED,取最⼩值33if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:34 top_left = min_loc35else:36 top_left = max_loc37 bottom_right = (top_left[0] + w, top_left[1] + h)3839# 画矩形40 cv2.rectangle(img2, top_left, bottom_right, 255, 2)4142 plt.subplot(121), plt.imshow(res, cmap='gray')43 plt.xticks([]), plt.yticks([]) # 隐藏坐标轴44 plt.subplot(122), plt.imshow(img2, cmap='gray')45 plt.xticks([]), plt.yticks([])46 plt.suptitle(meth)47 plt.show()48# *******************模版匹配**********************结束六种⽅法的匹配结果:2、多个匹配1# *******************膜版匹配-多个匹配**********************开始2import cv23import numpy as np4import matplotlib.pyplot as plt56 img_rgb = cv2.imread('mario.jpg')7 img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)8 template = cv2.imread('mario_coin.jpg', 0)9 h, w = template.shape[:2]1011 res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)12 threshold = 0.813# 取匹配程度⼤于%80的坐标14 loc = np.where(res >= threshold)15for pt in zip(*loc[::-1]): # *号表⽰可选参数16 bottom_right = (pt[0] + w, pt[1] + h)17 cv2.rectangle(img_rgb, pt, bottom_right, (0, 0, 255), 2)1819 cv2.imshow('img_rgb', img_rgb)20 cv2.waitKey(0)21# *******************膜版匹配-多个匹配**********************结束⼆、直⽅图cv2.calcHist(images,channels,mask,histSize,ranges)images: 原图像图像格式为 uint8 或 float32。
图像处理技术中的直方图匹配方法介绍

图像处理技术中的直方图匹配方法介绍直方图匹配是图像处理技术中常用的一种方法,它可以用来改变图像的亮度分布,使之符合特定的标准。
本文将介绍直方图匹配的原理、方法和应用。
直方图是图像中各灰度级的统计信息,它可以反映图像的亮度分布。
直方图匹配的目标是通过对比两个图像的直方图,调整一个图像的像素值,使其直方图与另一个图像的直方图相匹配。
直方图匹配的原理是将原始图像的亮度分布映射到目标图像的亮度分布上。
具体过程包括以下步骤:计算原始图像和目标图像的直方图。
直方图可以通过统计每个灰度级的像素个数计算得出。
将原始图像的直方图进行归一化处理,以使得图像的亮度范围保持一致。
计算原始图像和目标图像的累积直方图。
累积直方图反映了每个灰度级及其前面所有灰度级的像素个数累加值。
接着,根据原始图像和目标图像的累积直方图,计算像素值映射表。
该映射表可以通过将原始图像上的每个灰度级映射到目标图像上对应的灰度级来实现直方图匹配。
使用像素值映射表将原始图像的像素值映射到目标图像上,完成直方图匹配。
在图像处理中,直方图匹配有多种应用。
其中一个主要应用是图像增强。
通过将一幅图像的直方图匹配到另一幅具有良好亮度分布的图像上,可以增强原始图像的对比度和细节,改善图像的视觉效果。
直方图匹配也可以用于图像配准。
在医学影像、遥感影像等领域,图像配准是一个重要的任务。
通过直方图匹配,可以使两幅图像在亮度上具有一致性,从而提高图像配准的准确性。
直方图匹配还可以用于图像分类和目标检测。
通过将图像的直方图与训练样本的直方图进行匹配,可以实现图像的自动分类和目标的自动检测。
需要注意的是,直方图匹配虽然可以改善图像的亮度分布,但也可能导致图像的颜色失真。
因此,在应用直方图匹配时需要谨慎,根据具体情况进行权衡和调整。
总结来说,直方图匹配是图像处理中常用的方法,可以通过调整图像的亮度分布实现图像增强、图像配准、图像分类和目标检测。
在实际应用中,需要充分考虑图像的特点和需求,谨慎选择合适的参数和方法,以达到最佳效果。
opencv中的直方图与匹配

opencv中的直方图与匹配灰度直方图是灰度级的函数,描述的是图像中具有该灰度级的像素的个数:其横坐标是灰度级,纵坐标是该灰度出现的频率(像素的个数)。
在opencv中可以通过cvCreateHist()来生成直方图CvHistogram* cvCreateHist(int dims,int* sizes,int type,float** ranges=NULL,int uniform=1)dims//直方图包含的维数sizes//数组的长度等于dims,数组中每个整数表示分配给对应维数的的bin的个数type//表示存储类型,CV_HIST_ARRAy表示用密集多维矩阵结构存储直方图,CV_HIST_SPARSE表示数据已稀疏矩阵方式存储ranges=NULL,//浮点数对的构成的数组,每个浮点数对表示对应维数的bin的区间的上下界uniform=1//非0表示均匀直方图,为NULL表示未知,即在后面可以设置。
CvHistogram* cvCreateHist(使用cvCalcHist()函数来计算直方图void cvCalcHist(IplImage** image,CvHistogram* hist,int accmulate=0,const CvArr* mask=NULL)image //是一个指向数组的IplImage*类型的指针,着允许利用多个图像通道hist //要计算的直方图accmulate //非0时,表示直方图hist在读入图像之前没有被清零mask //如果为非NULL,则只有与mask非零元素对应的像素点会被包含在计算直方图中。
1.单通道图像的直方图#include "stdafx.h"#include <highgui.h>#include <math.h>#include <cv.h>int main(){IplImage* sourceImage=0;//以单通道读入图像if(!(sourceImage=cvLoadImage("YAYA.jpg",0))) return -1;int hdims=51; //分配给对应维数的bin的个数float rangesArray[]={0,255};float* ranges[]={rangesArray};float maxValue;CvHistogram* histogram=0;histogram=cvCreateHist(1,&hdims,CV_HIST_ARR AY,ranges,1);IplImage* histImage; //用来显示直方图histImage=cvCreateImage(cvGetSize(sourceImage),8, 3);cvZero(histImage);//计算直方图cvCalcHist(&sourceImage,histogram,0,0);//获取最大值cvGetMinMaxHistValue(histogram,0,&maxValue,0 ,0);cvConvertScale(histogram->bins,histogram->bins, maxValue?255./maxValue:0,0);float binsWidth;binsWidth=histImage->width/hdims;CvScalar color=CV_RGB(255,255,255);for(int i=0;i<hdims;i++){doublevalue=(cvGetReal1D(histogram->bins,i)*histImage-> height/255);cvRectangle(histImage,cvPoint(i*binsWidth,histImage->height),cvPoint((i+1)*binsWidth,(int)(histImage->hei ght-value)),color,1,8,0);}//显示cvNamedWindow("sourceImage",0);cvNamedWindow("histImage",0);cvShowImage("sourceImage",sourceImage);cvShowImage("histImage",histImage);//释放资源cvDestroyAllWindows();cvReleaseImage(&sourceImage);cvReleaseImage(&histImage);cvReleaseHist(&histogram);cvWaitKey(-1);return 0;}运行结果:多通道图像的直方图因为ccCalHist()只接受单通道图像,所以在调用cvCalcHist()之前,首先用cvSplit()将多通道图像分解为单通道图像。
详解pythonOpenCV学习笔记之直方图均衡化

详解pythonOpenCV学习笔记之直⽅图均衡化本⽂介绍了python OpenCV学习笔记之直⽅图均衡化,分享给⼤家,具体如下:考虑⼀个图像,其像素值仅限制在特定的值范围内。
例如,更明亮的图像将使所有像素都限制在⾼值中。
但是⼀个好的图像会有来⾃图像的所有区域的像素。
所以你需要把这个直⽅图拉伸到两端(如下图所给出的),这就是直⽅图均衡的作⽤(⽤简单的话说)。
这通常会改善图像的对⽐度。
建议阅读关于直⽅图均衡的wikipedia页⾯,了解更多有关它的详细信息。
它给出了⼀个很好的解释,给出了⼀些例⼦,这样你就能在读完之后理解所有的东西。
同样,我们将看到它的Numpy实现。
之后,我们将看到OpenCV函数。
import numpy as npimport cv2 as cvfrom matplotlib import pyplot as pltimg = cv.imread('wiki.jpg', 0)hist, bins = np.histogram(img.flatten(), 256, [0,256])cdf = hist.cumsum()cdf_normalized = cdf*float(hist.max())/cdf.max()plt.plot(cdf_normalized, color = 'b')plt.hist(img.flatten(),256,[0,256], color = 'r')plt.xlim([0,256])plt.legend(('cdf','histogram'), loc = 'upper left')plt.show()你可以看到,直⽅图位于更亮的区域。
我们需要完整的频谱。
为此,我们需要⼀个转换函数,它将更亮区域的输⼊像素映射到全区域的输出像素。
这就是直⽅图均衡所做的。
opencv-python图像配准(匹配和叠加)的实现

opencv-python图像配准(匹配和叠加)的实现图像配准需是指对不同条件下得到的两幅或多幅图像进⾏匹配、叠加的过程。
最简单的做法就是求得原图像到⽬标图像之间的透视变换矩阵,将原图像按照矩阵进⾏变换,就可以得到和⽬标图像相似的效果。
透视变换是将成像投影到⼀个新的视平⾯,也称作投影映射。
透视变换实质上是将⼆维的图⽚变换到三维的坐标系中之后再变换到另⼀个⼆维坐标系,与仿射变换相⽐透视变换实现的效果要多⼀些。
求解精确矩阵和透视变换可以很容易地在opencv-python中实现。
import cv2 as cvimport numpy as npimport matplotlib.pyplot as pltoriginal_image = cv.imread("Image A.jpg")target_image = cv.imread("Image B.jpg")# ⽣成透视矩阵src_points = np.array([[957, 1655], [2177, 1170], [2676, 24], [2487, 1931]], dtype=np.float32)den_points = np.array([[687, 1150], [2000, 996], [2757, 18], [2098, 1819]], dtype=np.float32)# getPerspectiveTransform可以得到从点集src_points到点集den_points的透视变换矩阵T = cv.getPerspectiveTransform(src_points, den_points)# 进⾏透视变换# 注意透视变换第三个参数为变换后图⽚⼤⼩,格式为(⾼度,宽度)warp_imgae = cv.warpPerspective(original_image, T, (target_image.shape[1], target_image.shape[0]))plt.imshow(warp_imgae)plt.show()进⾏四点变换前后的结果为opencv-python也可以计算超过四个点的两数组点之间的变换矩阵。
基础学习笔记之opencv:直方图使用学习

目的:直方图在cv领域到处可见,因为其功能在cv算法的实现中必不可少。
Opencv库中也集成了关于直方图的不少函数,比如直方图的计算,均衡,归一化,相似度比较等等。
为了体验这些函数,做了个小实验,功能是:打开摄像头,鼠标选定一个框,框内图像作为标准图像,计算出其直方图并显示出来;然后继续鼠标选定框,该框内的图像的直方图与标准图像的进行相似度计算,计算结果在终端输出,数值越大表示相似度越大。
工程环境:opencv2.3.1+vs2010。
工程代码:1// hist_test.cpp : 定义控制台应用程序的入口点。
2//34 #include "stdafx.h"5 #include <opencv2/core/core.hpp>6 #include <opencv2/imgproc/imgproc.hpp>7 #include <opencv2/highgui/highgui.hpp>8 #include <iostream>9 #include <stdio.h>1011usingnamespace cv。
12usingnamespace std。
1314int nFrame_num=0。
15bool pause=false。
16bool tracking=false。
17 Rect preselectROI,selectROI。
//用于存放手选的矩形18bool comp=true。
1920Mat rhist,ghist,bhist。
21int channels[]={0,1,2}。
22//const int histsize[]={256,256,256}。
23constint histsize[]={16,16,16}。
24constint histsize1=16。
25float rranges[]={0,255}。
图像处理基础(8):图像的灰度直方图、直方图均衡化、直方图规定化(匹配)

图像处理基础(8):图像的灰度直⽅图、直⽅图均衡化、直⽅图规定化(匹配)本⽂主要介绍了灰度直⽅图相关的处理,包括以下⼏个⽅⾯的内容:利⽤OpenCV 计算图像的灰度直⽅图,并绘制直⽅图曲线直⽅图均衡化的原理及实现直⽅图规定化(匹配)的原理及实现图像的灰度直⽅图⼀幅图像由不同灰度值的像素组成,图像中灰度的分布情况是该图像的⼀个重要特征。
图像的灰度直⽅图就描述了图像中灰度分布情况,能够很直观的展⽰出图像中各个灰度级所占的多少。
图像的灰度直⽅图是灰度级的函数,描述的是图像中具有该灰度级的像素的个数:其中,横坐标是灰度级,纵坐标是该灰度级出现的频率。
不过通常会将纵坐标归⼀化到[0,1]区间内,也就是将灰度级出现的频率(像素个数)除以图像中像素的总数。
灰度直⽅图的计算公式如下:p (r k )=n kMN其中,r k 是像素的灰度级,n k 是具有灰度r k 的像素的个数,MN 是图像中总的像素个数。
OpenCV 灰度直⽅图的计算直⽅图的计算是很简单的,⽆⾮是遍历图像的像素,统计每个灰度级的个数。
在OpenCV 中封装了直⽅图的计算函数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 );该函数能够同时计算多个图像,多个通道,不同灰度范围的灰度直⽅图.其参数如下:images ,输⼊图像的数组,这些图像要有相同⼤⼤⼩,相同的深度(CV_8U CV_16U CV_32F ).nimages ,输⼊图像的个数channels ,要计算直⽅图的通道个数。
直方图匹配原理

直方图匹配是一种基于图像的机器视觉技术,在安防、过程控制、机
器人等行业领域得到广泛应用。
主要用于解决待识别物体的大小、形状、位置等特征识别问题。
直方图匹配的基本原理是通过分析从图像中获取的所有像素点的亮度
分布,用一个合适的直方图模型描述,然后再根据图像特定值来进行
直方图匹配。
在直方图匹配过程中,会得到匹配度,根据匹配度,就
可以对对象进行判断。
直方图匹配一般使用曼哈顿距离作为相似度度量公式。
曼哈顿距离是
两点距离的绝对值,称为曼哈顿距离,它表示两点之间的距离和所有
维度的坐标差之和。
根据这个绝对距离的相等性,任何变化的量纲都
不会影响距离的计算结果:对于任意误差,正距离和负距离也能够抵消。
曼哈顿距离又叫城市区块距离,它表示由笛卡尔坐标系中两点之间的
曼哈顿距离,曼哈顿距离有效地利用了像素点的亮度值,能有效应用
在图像处理过程中。
曼哈顿距离可以根据两个直方图的相对密集程度,
来评估两个图像的相似程度,可给出一个较精准的结果。
直方图匹配的价值不仅仅体现在一般的图像处理领域中,还可以应用
于机器人、建筑自动化、人类识别分析等。
如通过识别不同的建筑物
形状,颜色等特征,为自动导航提供相应的定位,或者通过自动对不
同人员形象特征进行匹配,进行安防处理。
可以总结,直方图匹配技术可以根据图像中所有像素点的亮度分布,
使用曼哈顿距离给出最相似或者定位或者识别的结果,具有极大的价值,在很多行业得到了广泛应用。
OpenCV学习(七)---计算直方图

利用OpenCV的库函数计算直方图#include<cv.h>#include<highgui.h>int main(){IplImage* src=cvLoadImage("c:\\test11.jpg",0);//加载图片的路径int size=256;float range[]={0,255};float* ranges[]={range};//这里定义一个指针干嘛用的//cvCreateHist()返回一个CvHistogram类型的指针CvHistogram* hist=cvCreateHist(1,&size,CV_HIST_ARRAY,ranges,1);//计算src的直方图cvCalcHist(&src,hist,0,NULL);float max=0;//计算最大最小灰度,minvalue不需要用到,第二个,置为NULL即可cvGetMinMaxHistValue(hist,NULL,&max,NULL,NULL);//将直方图的面板做好IplImage* dst=cvCreateImage(cvSize(400,300),8,3);//设置好直方图面板的背景,cvScalarAll(255)是指的白色吧?cvSet(dst,cvScalarAll(255),0);//每个bin所占的宽度,总宽度是,一共有个bin,so,每个bin占。
double bin_width=(double)dst->width/size;//类似于单位宽度,这里是y轴方向上的单位尺度double bin_unith=(double)dst->height/max;for(int i=0;i<size;i++){CvPoint p0=cvPoint(i*bin_width,dst->height);//定义好cvRectangle需要的两个点CvPoint p1=cvPoint((i+1)*bin_width,dst->height-cvGetReal1D(hist->bins,i)*bin_unith);cvRectangle(dst,p0,p1,cvScalar(0,255),-1,8,0);}cvNamedWindow("src",1);cvShowImage("src",src);cvNamedWindow("dst",1);cvShowImage("dst",dst);cvWaitKey(0);cvDestroyAllWindows();cvReleaseImage(&src);cvReleaseImage(&dst);return 0;}自己计算直方图#include<cv.h>#include<highgui.h>int main(){IplImage* src=cvLoadImage("c:\\test11.jpg",0);int width=src->width;int height=src->height;int step=src->widthStep;//好好体会下IplImage里这个widthStep参数uchar* data=(uchar *)src->imageData;//不懂int hist[256]={0};for(int i=0;i<height;i++){for(int j=0;j<width;j++){hist[data[i*step+j]]++;}}int max=0;for(i=0;i<256;i++){if(hist[i]>max){max=hist[i];//256个灰度等级中,比较哪个等级中像素点最多}}IplImage* dst=cvCreateImage(cvSize(400,300),8,3);cvSet(dst,cvScalarAll(255),0);double bin_width=(double)dst->width/256;//计算x轴方向单位宽度double bin_unith=(double)dst->height/max;//计算y轴方向单位宽度for(i=0;i<256;i++){CvPoint p0=cvPoint(i*bin_width,dst->height);//定义cvRectangle()需要的两个点CvPoint p1=cvPoint((i+1)*bin_width,dst->height-hist[i]*bin_unith);cvRectangle(dst,p0,p1,cvScalar(0,255),-1,8,0);}cvNamedWindow("src",1);cvShowImage("src",src);cvNamedWindow("dst",1);cvShowImage("dst",dst);cvWaitKey(0);cvDestroyAllWindows();cvReleaseImage(&src);cvReleaseImage(&dst);return 0;}彩色直方图#include<cv.h>#include<highgui.h>#include<iostream>using namespace std;int main( int argc, char** argv ){IplImage * src;if (!(src = cvLoadImage("c:\\cat.jpg"))){cout << "没有找到源文件" << endl;return -1;}IplImage* hsv = cvCreateImage( cvGetSize(src), 8, 3 );IplImage* h_plane = cvCreateImage( cvGetSize(src), 8, 1 );IplImage* s_plane = cvCreateImage( cvGetSize(src), 8, 1 );IplImage* v_plane = cvCreateImage( cvGetSize(src), 8, 1 );IplImage* planes[] = { h_plane, s_plane };/** H 分量划分为个等级,S分量划分为个等级*/int h_bins = 16, s_bins = 8;int hist_size[] = {h_bins, s_bins};/** H 分量的变化范围*/float h_ranges[] = { 0, 180 };/** S 分量的变化范围*/float s_ranges[] = { 0, 255 };float* ranges[] = { h_ranges, s_ranges };/** 输入图像转换到HSV颜色空间*/cvCvtColor( src, hsv, CV_BGR2HSV );cvNamedWindow( "hsv", 1 );cvShowImage( "hsv", hsv );cvCvtPixToPlane( hsv, h_plane, s_plane, v_plane, 0 );cvNamedWindow( "h_plane", 1 );cvShowImage( "h_plane", h_plane );cvNamedWindow( "s_plane", 1 );cvShowImage( "s_plane", s_plane );cvNamedWindow( "v_plane", 1 );cvShowImage( "v_plane", v_plane );/** 创建直方图,二维, 每个维度上均分*/CvHistogram * hist = cvCreateHist( 2, hist_size, CV_HIST_ARRAY, ranges, 1 );/** 根据H,S两个平面数据统计直方图*/cvCalcHist( planes, hist, 0, 0 );/** 获取直方图统计的最大值,用于动态显示直方图*/float max_value;cvGetMinMaxHistValue( hist, 0, &max_value, 0, 0 );/** 设置直方图显示图像*/int height = 240;int width = (h_bins*s_bins*6);IplImage* hist_img = cvCreateImage( cvSize(width,height), 8, 3 );cvZero( hist_img );/** 用来进行HSV到RGB颜色转换的临时单位图像*/IplImage * hsv_color = cvCreateImage(cvSize(1,1),8,3);IplImage * rgb_color = cvCreateImage(cvSize(1,1),8,3);int bin_w = width / (h_bins * s_bins);for(int h = 0; h < h_bins; h++){for(int s = 0; s < s_bins; s++){int i = h*s_bins + s;/** 获得直方图中的统计次数,计算显示在图像中的高度*/float bin_val = cvQueryHistValue_2D( hist, h, s );int intensity = cvRound(bin_val*height/max_value);/** 获得当前直方图代表的颜色,转换成RGB用于绘制*/cvSet2D(hsv_color,0,0,cvScalar(h*180.f / h_bins,s*255.f/s_bins,255,0));cvCvtColor(hsv_color,rgb_color,CV_HSV2BGR);CvScalar color = cvGet2D(rgb_color,0,0);cvRectangle( hist_img, cvPoint(i*bin_w,height), cvPoint((i+1)*bin_w,height - intensity),color, -1, 8, 0 );}}cvNamedWindow( "Source", 1 );cvShowImage( "Source", src );cvNamedWindow( "H-S Histogram", 1 );cvShowImage( "H-S Histogram", hist_img );cvWaitKey(0);}。
opencv之直方图处理

opencv之直⽅图处理直⽅图是图像处理过程中的⼀种⾮常重要的分析⼯具。
是图像内灰度值的统计特性与灰度值之间的函数,直⽅图统计图像内各个灰度级出现的次数需要注意三个概念:DIMS : 表⽰绘制直⽅图时,收集的参数的数量,⼀般情况下,直⽅图中收集的数据只有⼀种,就是灰度级,因此该值为1 RANGE :表⽰统计的灰度级的范围,⼀般为[0 . 255] . 0对应的时⿊⾊,255对应的时⽩⾊BINS :参数⼦集的数⽬,在处理数据的过程中,有时需要将众多的数据划分为若⼲个组,在进⾏分析该图中,BINS为6,RANGE为[2,6]python 的模块matplotlib.pyplot中的hist()函数能⽅便的绘制直⽅图,函数形式为matplotlib.pyplot.hist( x , BINS)x,为数据源,必须是⼀维的,图像通常都是⼆维的,可以通过函数ravel()来将⼆维数组降成⼀维的例如:图像x233414546323452576对其使⽤函数ravel()y = x.ravel()得到y为:233414546323452576BINS为灰度级的分组情况绘制图像的直⽅图1import cv22import matplotlib.pyplot as plt3 o = cv2.imread("/home/miao/dog.jpg")4 cv2.imshow("original" , o)5 plt.hist(o.ravel() , 256)6 cv2.waitKey()7 cv2.destroyAllWindows()8 plt.show()这⾥要有函数plt.show()才会显⽰出直⽅图图像直⽅图将灰度级划分为16个⼦集opencv提供了函数,cv2.calcHist() ⽤来计算图像的统计直⽅图,函数形式:hist = cv2.calcHist( images , channels , mask , histSize , ranges , accumulate)hist 返回统计直⽅图,是⼀个⼀维数组,数组内的元素时各个灰度级的个数images 原始图像需要⽤ [ ] 括起来channels 指定通道编号,也需要⽤[ ] 括起来,灰度图像即为 [ 0 ] , 对于彩⾊图像即为 [ 0 ] [ 1 ] [ 2 ] 对应的即为 B G R 通道mask掩模图像,不需要时则设置为NonehistSize BINS值需要⽤[ ] 括起来ranges像素值范围,例如8位灰度图像范围为 [ 0 , 256 ]accumulate 累计默认值为False ,如果设置为True时,计算的是多个直⽅图的累计结果plot()函数绘制图像的直⽅图 color = 'b' 表⽰曲线是蓝⾊的 color = ' g' 表⽰曲线为绿⾊ color = 'r'表⽰曲线为红⾊1import cv22import matplotlib.pyplot as plt3 o = cv2.imread("/home/miao/dog.jpg")4 histb = cv2.calcHist([o] , [0] , None , [256] , [0,255])5print(type[histb])6print(histb.shape)7 peitn(histb.size)8 plt.plot(histb , color = 'b')9 plt.show()<class'numpy.ndarray'>(256, 1)256返回类型为ndarray数据为256列 1⾏有256个元素使⽤掩模绘制直⽅图1import cv22import numpy as np3import matplotlib.pyplot as plt4 image = cv2.imread("/home/miao/dog.jpg" , cv2.IMREAD_GRAYSCALE)5 mask = np.zeros( image.shape , np.uint8)6 mask[100:200 , 50:150] = 2557 histImage = cv2.calcHist([image] , [0] , None , [256] , [0,255] )8 histMi = cv2.calcHist( [image] , [0] , mask , [256] , [0,255])9 plt.plot(histImage)10 plt.plot(histMi)11 plt.show()掩模之前有描述过就不再多说直⽅图的均衡化⽬地主要是将原始图像的灰度级均匀的映射到整个灰度级范围内,得到⼀个灰度级均匀的图像实现⽅法为,将该灰度级出来的概率累计之前灰度级的概率之和,然后乘以最⼤灰度值,所得即为均衡化图像 1import cv22import matplotlib.pyplot as plt3 img = cv2.imread("/home/miao/dog.jpg" , cv2.IMREAD_GRAYSCALE)4 equ = cv2.equalizeHist(img)5 cv2.imshow("original" , img)6 cv2.imshow("result" , equ)7 plt.figure("原始图像直⽅图")8 plt.hist(img.ravel() , 256)9 plt.figure("均衡化结果直⽅图")10 plt.hist(equ.ravel() , 256)11 plt.show()12 cv2.waitKey()13 cv2.destroyAllWindows()原图直⽅图均衡化处理原始图像直⽅图均衡化结果直⽅图可以看出原图左侧⽐较密集整体较⾼,在均衡化处理之后左侧变得稀疏,右侧密集,整体来看是⽐较均衡的函数matplotlib.pyplot.subplot( nrows , ncols , index)例如:subplot(2,3,5) 表⽰在两⾏三列的窗⼝上在第4个位置上,添加⼀个⼦窗⼝。
OpenCV.直方图均衡CLAHE算法学习

OpenCV.直⽅图均衡CLAHE算法学习前⾔ 图像识别⼯程开发中需要增强图像对⽐度,便于后续处理,接触到了CLAHE(Contrast Limited Adaptive Histogram Equalization),记录⼀下其中的学习过程。
1.直⽅图均衡1.1灰度直⽅图 灰度图中像素值的分布为0-255,以灰度值为横坐标,纵坐标为该灰度值对应的像素点数⽬/⽐例,则得到了灰度图像的直⽅图,体现的是图像中灰度的整体分布情况。
OpenCV中提供了相应的计算函数calcHist(),可以得到相应分布范围的像素点数;将其绘制出来观察,更为直观。
下图为某输⼊图像和其灰度直⽅图分布。
⼀般性规律:对于灰度图像,以个⼈观察意愿将其分为前景和背景区域,前景是我们所感兴趣的区域,背景则反之。
若前景和背景的灰度差异⼤,则易于⼈们观察,否则不易观察。
⼀般来说若图像的灰度直⽅图集中在某个区域,其整体对⽐度较差,不易于我们区分前景和背景;反之若灰度直⽅图分布较为均匀,则整体对⽐度较好,易于我们区分前景和背景。
1.2直⽅图均衡化(Histogram Equalization, HE)1)效果 直⽅图均衡化就是⼀种使图像的灰度直⽅图分布更佳均匀的变换⽅法。
OpenCV中的equalizeHist()实现了该功能左侧为原始灰度图,中间上⽅为其灰度分布;右侧为HE处理后得到的图像,中间下⽅为其灰度分布;对⽐灰度分布可知右⽅图像的灰度分布更为均匀,图像效果上来看结果图像对⽐度更强。
2)数学原理先说概率分布与概率密度函数,看⼀下下图中的题⽬回想⼀下以前的数学知识。
接下来对概率密度函数的变换做⼀些数学推导,输⼊公式⽐较⿇烦,截图为图像粘贴进来。
这⾥可以看到转换函数T()为单调递增函数,不过结果图的直⽅图分布并不是理想的⼀条⽔平线;原因在于我们是在连续分布上推导得到转换函数,作⽤于离散分布,且不允许产⽣⾮整数形式的新结果。
不过整体看来该转换函数使新的分布具有展开直⽅图分布的效果,增强了整体的对⽐度。
opencv学习笔记(六)直方图比较图片相似度

opencv学习笔记(六)直⽅图⽐较图⽚相似度opencv学习笔记(六)直⽅图⽐较图⽚相似度 opencv提供了API来⽐较图⽚的相似程度,使我们很简单的就能对2个图⽚进⾏⽐较,这就是直⽅图的⽐较,直⽅图英⽂是histogram, 原理就是就是将图⽚转换成直⽅图,然后对直⽅图进⾏⽐较,在某些程度,真实地反映了图⽚的相似度。
代码如下:1 #include <iostream>2 #include <cv.h>3 #include <highgui.h>4using namespace std;5using namespace cv;67int main(void)8 {9 Mat pic1 = imread("pic1.jpg");10 Mat pic2 = imread("pic2.jpg");11//计算相似度12if (pic2.channels() == 1) {//单通道时,13int histSize = 256;14float range[] = { 0, 256 };15const float* histRange = { range };16bool uniform = true;17bool accumulate = false;1819 cv::Mat hist1, hist2;2021 cv::calcHist(&pic2, 1, 0, cv::Mat(), hist1, 1, &histSize, &histRange, uniform, accumulate);22 cv::normalize(hist1, hist1, 0, 1, cv::NORM_MINMAX, -1, cv::Mat());2324 cv::calcHist(&pic1, 1, 0, cv::Mat(), hist2, 1, &histSize, &histRange, uniform, accumulate);25 cv::normalize(hist2, hist2, 0, 1, cv::NORM_MINMAX, -1, cv::Mat());2627double dSimilarity = cv::compareHist(hist1, hist2, CV_COMP_CORREL);//,CV_COMP_CHISQR,CV_COMP_INTERSECT,CV_COMP_BHATTACHARYYA CV_COMP_CORREL 2829 cout << "similarity = " << dSimilarity << endl;30 }31else {//三通道时32 cv::cvtColor(pic2, pic2, cv::COLOR_BGR2HSV);33 cv::cvtColor(pic1, pic1, cv::COLOR_BGR2HSV);3435int h_bins = 50, s_bins = 60;36int histSize[] = { h_bins, s_bins };37float h_ranges[] = { 0, 180 };38float s_ranges[] = { 0, 256 };39const float* ranges[] = { h_ranges, s_ranges };40int channels[] = { 0, 1 };4142 cv::MatND hist1, hist2;4344 cv::calcHist(&pic2, 1, channels, cv::Mat(), hist1, 2, histSize, ranges, true, false);45 cv::normalize(hist1, hist1, 0, 1, cv::NORM_MINMAX, -1, cv::Mat());4647 cv::calcHist(&pic1, 1, channels, cv::Mat(), hist2, 2, histSize, ranges, true, false);48 cv::normalize(hist2, hist2, 0, 1, cv::NORM_MINMAX, -1, cv::Mat());4950double dSimilarity = cv::compareHist(hist1, hist2, CV_COMP_CORREL); //,CV_COMP_CHISQR,CV_COMP_INTERSECT,CV_COMP_BHATTACHARYYA CV_COMP_CORREL 5152 cout << "similarity = " << dSimilarity << endl;53 }54 waitKey(0);55return1;5657 } pic1: pic2: 使⽤相关系数法(CV_COMP_CORREL)进⾏图⽚相似度⽐较时,取值范围为[-1,1];越接近1说明两幅图⽚越相似; ⽐较pic1与pic2得到的结果为: similarity =0.926247 pic与本⾝进⾏⽐较时, similarity =1。
直方图处理(均衡化与匹配)解析

0.11
直方图均衡化结果
pr(rk)
0.25 0.20 0.15 0.10 0.05 0
1 7 2 7 3 7
4 7
Sk
0.25 0.21 0.19 0.16 0.08 0.06 0.03
6 7
1.00 0.80 0.60 0.40 0.02
1
0.89 0.81 0.95 0.98 0.65 0.44
(3) 计算原始直方图各概率:pk=nk/N; (4) 计算累计直方图:sk=Σpk; (5) 取整Sk=int{(L-1)sk+0.5}; (6) 确定映射对应关系:rksk;
(7) 统计新直方图各灰度级像素nk';
(8) 用pk (sk) =nk'/N计算新直方图。
其中L是灰度层次数, N是图幅总像素数。
c) 作图
建立直角坐标系,横轴表示rk 的取值,纵轴表示pr (rk )的取值, 作pr (rk )的函数图
练习:试求如图所 示一幅10×10, 8级灰度图像的灰 度直方图。
a)将图像的灰度级归一化
0 1 1 2
0 1 1 2
0 1 1 2
0 1 1 2
0 1 1 2
0 1 1 2
0 1 1 2
0 1 1 2
直方图均衡化的优点是能自动地增强整个图像 的对比度,但它的具体增强效果不易控制,处理 的结果总是得到全局均衡化的直方图。实际中有 时需要变换直方图使之成为某个特定的形状,从 而有选择地增强某个灰度值范围内的对比度。
s=T(r) Pr(r) Pz(z) s=T(r) v=G(z) z=G-1[T(r)]
z
两者经直方图均衡化处理后应有相同的直方图,因此 规定化后的的图像灰度级为:
直方图匹配

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%直方图匹配%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%function funZG()clc;clear;I=rgb2gray(imread('e:\2.bmp'));figure,subplot(321),imshow(I);title('Ô-ͼ');New=I;L=256; %灰度值Pj=zeros(L,1);RH2=zeros(L,1);[m1 n1]=size(I); %计算图像数据举证的行列数H=zeros(L,1); % 存储源图像直方图数据for i = 1:m1for j = 1:n1H(I(i,j)+1)=H(I(i,j)+1)+1; %获取像素灰度级endend% 计算直方图概率统计Pi=zeros(L,1);% 存储原图像直方图概率数据for k=1:LPi(k)=H(k)/(m1*n1);endsubplot(323),plot(Pi);title('Ô-ͼµÄÖ±·½Í¼Pi');% 计算累积直方图RH=zeros(L,1);% 存储原图像累积直方图数据RH(1)=Pi(1);for k=2:LRH(k)=RH(k-1)+Pi(k);end%subplot(325),plot(RH);%title('原图累积直方图RH');% 匹配直方图J=rgb2gray(imread('e:\1012.bmp'));subplot(322),imshow(J);title('匹配图');[m2 n2]=size(J);H2=zeros(L,10); % 存储原图像直方图数据for i = 1:m2for j = 1:n2H2(J(i,j)+1)=H2(J(i,j)+1)+1; % 获取像素灰度级endend% 计算直方图概率统计Pj=zeros(L,1);% 存储原图像直方图概率数据for k=1:LPj(k)=H2(k)/(m1*n1);endsubplot(324),plot(Pj);title('匹配图的直方图Pj');% 计算累积直方图RH2=zeros(L,1);% 存储原图像累积直方图数据RH2(1)=Pj(1);for k=2:LRH2(k)=RH2(k-1)+Pj(k);end%subplot(326),plot(RH2);%title('匹配图累积直方图RH2');% 计算原图像与目标图像累积直方图数值的差的绝对值double ScMin=zeros(256,256);for y=1:Lfor x=1:LScMin(x,y)=abs(RH(y)-RH2(x));endend%figure,plot(ScMin);%title('ScMin');% 建立映射HisM=zeros(L:1);for k=1:Lmin = 0;minV=ScMin(1,k);for t=1:Lif(minV>ScMin(t,k))minV=ScMin(t,k);min = t;endendHisM(k)= min;end% 将原图的每个像素灰度转换为直方图均衡化后的灰度for x = 1:m1for y = 1:n1Num = double( I(x,y))+1;if Num==iNew(x,y)=HisM(i);endendend% 计算直方图匹配后的直方图for i = 1:m1for j= 1:n1NN = double( New(i,j))+1;H2(NN) = H2(NN)+1;endendsubplot(325),imshow(New),title('匹配后图像'); subplot(326),plot(Pj),title('匹配后直方图');运行结果是:。
opencv直方图均衡化算法及实现

opencv直⽅图均衡化算法及实现opencv直⽅图均衡化算法及实现1、为什么要直⽅图均衡化很多时候,我们的图⽚看起来的效果不是那么的清晰,这时候可以对图像进⾏⼀些处理来扩⼤图像像素值显⽰的范围。
例如有些图像整体像素值偏低,图像中的⼀些特征看的不是很清晰,只是隐约看到⼀些轮廓痕迹,这时可以经过图像直⽅图均衡化之后使得图像看起来亮⼀些,也便于后续的处理。
直⽅图均衡化是灰度变换的⼀个重要应⽤,它⾼效且易于实现,⼴泛应⽤于图像增强处理中。
图像的像素灰度变化是随机的,直⽅图的图形⾼低不齐,直⽅图均衡化就是⽤⼀定的算法使直⽅图⼤致平和的⽅法。
2、opencv中直⽅图均衡化算法opencv中直⽅图均衡化算法的输⼊图像需为⼋位单通道图像,也就是灰度图像。
若想要处计算彩⾊图像的均衡化图,可以先将图像⽤split函数进⾏通道分离,分别处理每⼀个通道的图像,在⽤merge函数进⾏合并。
算法实现步骤如下:第⼀步:依次扫描原始灰度图像的每⼀个像素,计算出图像的直⽅图H。
’第⼆步:进⾏归⼀化处理,即将0~255像素值的每⼀个像素值在图像中出现的次数除以图像的⼤⼩,得到归⼀化直⽅图。
第三步:计算直⽅图积分,公式:第四步:以H’作为查询表进⾏图像变换dst(x,y)=H’(src(x,y))#include <opencv2\opencv.hpp>#include <iostream>using namespace cv;int main(){Mat srcImg,grayImg;//声明原始图和灰度度srcImg = imread("1.jpg");//载⼊原始图if(!srcImg.data){std::cout<<"请确认路径下存在图⽚";return -1;}imshow("原始图",srcImg);//显⽰原始图cvtColor(srcImg,grayImg,CV_RGB2GRAY);//将rgb图像转化为灰度图int rowNumber = grayImg.rows;//得到⾏int colNumber = grayImg.cols;//得到列int sumNumber = rowNumber*colNumber;//得到图像整个像素个数Mat dstImg(rowNumber,colNumber,CV_8UC1,Scalar(0,0,0));//初始化直⽅图均衡化后的图double hist[256] = {0.00};//直⽅图double dhist[256] = {0.00};//直⽅图归⼀化图double Dhist[256] = {0.00};//直⽅图积分图,每⼀个像素点for(int i = 0;i<rowNumber;i++)//遍历原始图像,得到直⽅图{uchar* data = grayImg.ptr<uchar>(i);for(int j = 0;j<colNumber;j++){int temp = data[j];//得到图像像素值hist[temp] = hist[temp]+1;//将相应像素值在直⽅图中加1}}for(int i = 0;i<256;i++)//遍历直⽅图,得到归⼀化直⽅图和积分图{dhist[i] = hist[i]/sumNumber;//得到归⼀化图for(int j = 0;j<=i;j++){Dhist[i] = Dhist[i] + dhist[j]; //得到积分图}}for(int i = 0;i<rowNumber;i++)//以积分图为查找表得到均衡化后的图{uchar* data1 = dstImg.ptr<uchar>(i);uchar* data2 = grayImg.ptr<uchar>(i);for(int j = 0;j<colNumber;j++){int temp1 = data2[j]; //查找到原始图相应位置的像素值int temp2 = (int)(Dhist[temp1]*255); //在积分图中找到相应像素值的映射值 data1[j] = temp2;//将映射值赋值给⽬标图像相应值}}imshow("均衡化后的图",dstImg);waitKey(0);return0;}。
OpenCV直方图均衡化

OpenCV直⽅图均衡化⼀、直⽅图均衡步骤 1.加载原图 2.将BGR⾊彩空间转换为YCrCb 3.拆分原图为单个通道(本例我们均衡Y分量),使⽤YCrCb⾊彩空间 4.均衡Y分量 5.合并三个通道(此时Y分量已被均衡过) 6.将YCrCb颜⾊空间转换为BGR 7.输出最终均衡后的结果⼆、具体代码如下:⾥⾯有详细的注释,这⾥不再赘述/*** 图像颜⾊均衡(直⽅图均衡化)* @param inputImagePath 原始图像路径* 图像均衡试图获得具有均匀分布值的直⽅图。
均衡的结果是图像对⽐度增加。
均衡能够使对⽐度⽐较低的局部区域获得⾼对⽐度,从⽽分散最频繁的强度。
* 当图像⾮常暗或者⾮常亮,并且背景和前景之间存在⾮常⼩的差异时,此⽅法⾮常有⽤。
通过使⽤直⽅图均衡化,可以增加对⽐度,并且提升暴露过度或暴露不⾜的细节。
* 该技术在医学图像中⾮常有⽤(如:X射线)** 缺点:* 背景噪声的增加以及随之⽽来的有⽤信号的减少。
*/void showEqualizeImage(char *inputImagePath) {//原图Mat src = imread(inputImagePath);//定义⼀个最终显⽰结果的矩阵Mat result;//将BGR图像转换为YCBCRMat ycrcb;cvtColor(src, ycrcb, COLOR_BGR2YCrCb);//将ycrcb拆分成三个不同的通道,可以单独拿到Y分量vector<Mat> channels;split(ycrcb, channels);//直⽅图均衡,只均衡Y分量equalizeHist(channels[0], channels[0]);//将均衡后的y分量合并到Ycrcb图像中merge(channels, ycrcb);//将ycrcb转换为BGRcvtColor(ycrcb, result, COLOR_YCrCb2BGR);//显⽰原图imshow("src", src);//显⽰均衡后的图像imshow("equalizeHist", result);src.release();ycrcb.release();result.release();waitKey(0);destroyWindow("equalizeHist");}三、原图和均衡后的Y分量后的图像做对⽐。
基于opencv和c++的图像处理:直方图匹配

基于opencv和c++的图像处理:直方图匹配在冈萨雷斯的那本《数字图像处理》中提到了一种神奇的变换:直方图匹配变换(Histogram Matching), 输入两幅图A和B,A和B 的直方图不同,直方图匹配变换是这样的一个变换s = F(r), 使得变换之后,A的直方图和B的直方图一样。
也就是它们的颜色分布变成一样。
比如下面两幅图:一个沙漠,一个海滩,它们的RGB直方图显然是不一样的。
但是执行直方图匹配变换后,沙漠那张图就变成这样了和海滩那张图的直方图比一下,会发现上图的直方图与之几乎是一样的。
沙漠图也就带上了海滩的味道。
这个变换的神奇之处在于,假设海滩那种图中的每个像素点都是可以自由移动的,在经过某次神奇的移动之后,海滩变成了沙漠,但是他们视觉上的色彩效果是一致的,不同的是像素点在不同的位置所造成的结构上的差异。
细看之后,海滩化后的沙漠怎么还有一个地方是沙子的颜色呢?其实是海滩上的沙子移过来的。
当然,这个变换其实是近似的,主要是因为其中用到了一个变换的反变换,而该变换并不是双射,所以其反变换是近似的,这个也是代码中比较复杂的地方。
详细的算法细节可以参考冈萨雷斯的那本数字图像处理,当然最好是看英文版,那本中文版我是根本没看懂。
相关代码:[cpp] view plaincopy1.bool GFImage::HistogramMatching(const GFImage& anoImage)2.{3.assert(GetChannel() == anoImage.GetChannel());4.//r->s5.vector<vector<uchar> > vRSMap;6.CalculateMapFunByHisEq(vRSMap);7.//z->s8.vector<vector<uchar> > vZSMap;9.anoImage.CalculateMapFunByHisEq(vZSMap);10.11.vector<vector<uchar> > vRZMap;12.vRZMap.resize(GetChannel());13.for(int ch = 0; ch < GetChannel(); ch++)14.{15.vRZMap[ch].resize(256);16.}17.18.for (int ch = 0; ch < GetChannel(); ch++)19.{20.vector<int> vSZMap;21.vSZMap.resize(256);22.for (int i = 0;i < 256;i++)23.{24.vSZMap[i] = -1;25.}26.for (int z = 255; z>=0; z--)27.{28.vSZMap[vZSMap[ch][z]] = z;29.}30.vector<int> vSIndex;31.//加前哨32.vSIndex.push_back(-1);33.for (int s = 0; s< 256 ;s++)34.{35.if (vSZMap[s] != -1)36.{37.vSIndex.push_back(s);38.}39.}40.//加后哨41.vSIndex.push_back(256);42.for (int i = 0; i < vSIndex.size() - 1; i++)43.{44.int startIdx = vSIndex[i] + 1;45.int endIdx = vSIndex[i + 1] - 1;46.47.int lowerIdx = vSIndex[i];48.int upperIdx = vSIndex[i + 1];49.50.if (i == 0)51.{52.lowerIdx = upperIdx;53.}54.if ( i == vSIndex.size() - 2)55.{56.upperIdx = lowerIdx;57.}58.59.int nLen = endIdx - startIdx + 1;60.int nMidIdx = startIdx + nLen / 2;61.for (int j = startIdx; j < nMidIdx; j++)62.{63.vSZMap[j] = vSZMap[lowerIdx];64.}65.for (int j = nMidIdx; j <= endIdx ; j++)66.{67.vSZMap[j] = vSZMap[upperIdx];68.}69.}70.71.for (int r = 0; r < 256; r++)72.{73.vRZMap[ch][r] = vSZMap[vRSMap[ch][r]];74.}75.}76.77.for (int ch = 0; ch < GetChannel(); ch++)78.{79.uchar * pData = GetData();80.for (int r = 0;r < GetHeight(); r++)81.{82.uchar * pLine = pData + r * GetWidthStep();83.for (int c = 0; c < GetWidth(); c++)84.{85.uchar val = pLine[GetChannel() * c + ch];86.pLine[GetChannel() * c + ch] = vRZMap[ch][val];87.}88.}89.}90.return true;91.92.}完整代码可参考这里。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
这里的hist表示直方图,factor表示直方图归一化后的数
值(通常情况下设为1)。注意,factor是一个double类 型的数据,尽管函数CvHistogram()的内部数据类型通 常都是float——这进一步说明了OpenCV是一个不断改 进的项目! 接下来的一个很方便的函数是阈值函数:
目录
• • • • • 直方图的基本数据结构 访问直方图 直方图的基本操作 一些更复杂的策略 练习
直方图的基本数据结构
首先直接查看CvHistogram的数据结构。
typedef struct CvHistogram { int type; CvArr* bins; float thresh[CV_MAX_DIM][2]; for uniform histograms float** thresh2; for nonuniform histograms CvMatND mat; embedded matrix header } for array histograms
CvHistogram* cvMakeHistHeaderForArray( int dims, int* sizes, CvHistogram* hist, float* data, float** ranges = NULL, int uniform = 1 );
在这种情况下,hist是指向CvHistogram数据结构的指针, data是指向存储直方图bins的大小为 sizes[0]*sizes[1]*..*sizes[dims-1]的区域的指针。注意, data是浮点数指针,因为直方图的内部数据类型描述
图7-1:方向梯度的局部直方图,用以寻找手及其特征(姿态)。这里“胜出” 的姿态(最长的垂直条)就是正确识别的“L”(向左移动)
测感兴趣的色彩区域,然后计算这些感兴趣区域周围的 边缘梯度方向,将得到的边缘梯度方向放到一个方向 直方图相应的bin中,然后将该直方图与手势模板进行 匹配,从而识别出各种手势。图7-1的垂直条显示不同 手势的匹配程度。灰色的水平线为可接受阈值,表示 对应某一手势模型胜出的垂直条。 直方图广泛应用于很多计算机视觉应用中。通过标记帧 与帧之间显著的边缘和颜色的统计变化,直方图被用 来检测视频中场景的变换。通过为每个兴趣点设置一 个有相近特征的直方图所构成的“标签”,用以确定 图像中的兴趣点。边缘、色彩、角等直方图构成了可 以被传递给目标识别分类器的一个通用特征类型。色 彩和边缘的直方图序列还可以用来识别网络视频是否 被复制等。直方图是计算机视觉中最经典的工具之一。
的点太多,就会丧失分布的结构。如果网格太窄(右 上),则没有足够的点来准确表示分布而且我们会得 到小而尖锐的单元。 OpenCV有表征直方图的数据类型。该直方图数据结构能 够以一维或者多维的方式表示直方图,并且包含所有 可能跟踪的均匀或非均匀的bin中的数据。并且,如我 们所期待的,它可以配属各种有用的函数,使得我们 能够在直方图上容易地进行各种常见操作。
void cvClearHist( CvHistogram* hist ); void cvReleaseHist( CvHistogram** hist );
通常,这些释放函数通过一个指针被调用,该指针指向 一个直方图的指针,后者取自创建直方图的函数。一
旦直方图被释放,直方图指针便被设置为NULL。 另外一个有用的函数是根据已给出的数据创建直方图:
或者基于效率原因想直接访问bin,在这种情况下,我们 可以利用hist->mat.data.fl(对于密集型直方图来说)来访 问。访问直方图的其他原因包括想知道直方图的维数 或每个单独的bin表示的区域等。对这类信息,我们使 用下面的小技巧来访问CvHistogram数据结构中的实际 数据,或者访问嵌入在CvMatND数据结构中的信息来 获得。
第7章 直方图与匹配
在分析图像、物体和视频信息的过程中,我们常常想把 眼中看到的对字用直方图(histogram)表示。直方图 可以用来描述各种不同的事情,如物体的色彩分布、 物体的边缘梯度模板[Freeman95],以及表示目标位置 的当前假设(目标当前位置的假设?)的概率分布。 图7-1显示了利用直方图进行快速姿态识别。从“上”, “右”,“左”,“停”和“OK”等手势中得到边缘 梯度。然后设置一个摄像机,该摄像机观察人的各种 手势以控制网络视频。在每帧中,从输入的视频中检
float* cvGetHistValue_1D(
CvHistogram* hist, int idx0 ); float* cvGetHistValue_2D( CvHistogram* hist, int idx0, int idx1 ); float* cvGetHistValue_3D( CvHistogram* hist, int idx0, int idx1, int idx2 ); float* cvGetHistValue_nD( CvHistogram* hist,
变量dims表示直方图包含的维数。sizes变量必须为整数 数组,数组长度等于dims。数组中的每一个整数表示 分配给对应维数的bin的个数。type既可以是 CV_HIST_ARRAY,用来表示使用密集多维矩阵结构 (如CvMatND)存储多维直方图,也可以是
CV_HIST_SPARSE,当数据以稀疏矩阵(CvSparseMat)方 式存储时。变量rangs可以是两个形式中的任一种。对 均匀直方图来说,rangs是浮点数对构成的数组,数组 的个数等于维数。而对非均匀直方图来说,则用包含 分割非均匀bin的数据所构成的数组来代替均匀直方图 所使用的数据对。如果某维数有N个bin,那么这个子 数组有N+1个元素。每个数组的值均起始于最低bin的 底边,终结于最高bin的顶边。布尔类型变量uniform 说明直方图是否有均匀的bin,因此也说明了rangs的 值该如何解析;如果设置为非0值,则直方图是均匀 的。也可以设置rangs为NULL,这时意味rangs是“未 知的”(它们也可以在后面使用特殊函数 cvSetHistBinRangs()来设置)。很明显,最好在使用直 方图之前给rangs设置数值。
cvThreshHist(CvHistogram* hist, double factor);
变量factor是一个开关阈值。进行直方图阈值化处理之 后,小于给定阈值的各个bin的值都被设为0。回忆图 像阈值函数cvThreshold(),直方图阈值函数与参数 threshold_type设置为CV_THRESH_TOZERO的图像阈值 函数类似。不幸的是,没有方便的直方图阈值函数来 提供其他threshold类型的类似操作。然而,实际上函 数cvThreshHist()或许是最常用的函数,因为我们在使 用实数类型数据的时候常常将包含极少数据点的bin去
这个定义看起来很简单但并非如此,因为直方图的很多
内部数据都被存储于CvMatND结构中。我们用下面的程 序创建一个新的直方图:
CvHistogram* cvCreateHist( int dims, int* sizes, int type, float** ranges = NULL, int uniform = 1 );
double cvQueryHistValue_3D( CvHistogram* hist, int idx0, int idx1, int idx2 ); double cvQueryHistValue_nD( CvHistogram* hist, int* idxN );
每个函数都返回相应bin中的值的浮点数。同样地,可以 利用函数返回的bin的指针(不是bin的值)来设置 (或者获得)直方图的bin的值。
访问直方图
访问直方图数据的方式有好几种。最直接的是使用 OpenCV的访问函数:
double cvQueryHistValue_1D( CvHistogram* hist, int idx0 ); double cvQueryHistValue_2D( CvHistogram* hist, int idx0, int idx1 );
简单地说,直方图就是对数据进行统计,将统计值组织 到一系列事先定义好的bin中。bin中的值是从数据中 计算出的特征的统计量,这些数据可以是诸如梯度、 方向、色彩或任何其他特征。无论如何,直方图获得 的是数据分布的统计图。通常直方图的维数要低于原 始数据。图7-2刻画了一个典型的情况。图中显示了一 个二维分布的点集(左上),施加一个网格(右上) 并且统计每一个网格单元的数据点,然后产生一个一
维直方图(右下)。由于原始数据点可以表征任何事情, 直方图实际上是一个方便表示图像特征的手段。 表示连续分布的直方图通过隐式计算每个网格单元中的 均值来实现前面的功能。这就会产生一个问题,如图 7-3所示。如果网格太宽(左上),则参与计算平均值
图7-3:直方图的正确性依赖于网格大小:如果网格太宽,则直方图统计中有太多的空间 平均(左),如果网格太窄,则因太小的平均产生尖锐和单个效果(右)
void cvSetHistBinRanges(
CvHistogram* hist, float** ranges, int uniform = 1 );
cvSetHistRanges()中的变量与cvCreateHist()中的相应变量 完全一致。如果想重用直方图,可以对其进行清零操 作(即设置所有bins为0),或者使用通常的释放函数 释放直方图。
int* idxN );
这些函数与cvGetReal*D和cvPtr*D等系列函数非常相似, 事实上,它们几乎相同。在函数里传入的矩阵hist>bins被调用的方式本质上与其被直接的矩阵访问模式 是一样的。类似地,稀疏直方图函数继承了它所对应 的稀疏矩阵函数的一些行为。在稀疏直方图中,如果 想利用函数GetHist*()来访问不存在的bin,这个不存 在的bin会被自动创建,并且其值被设为0。注意,函 数QueryHist*()不会创建不存在的bin。 这使我们转向访问直方图的更一般论题。在许多情况下, 对于密集直方图来说,我们想直接访问直方图的bin成 员。当然,我们可以将它视为数据访问的一部分。例 如,我们想依次访问密集直方图中所有的数据元素,