您的位置:首页 > 运维架构

OPENCV中画图像直方图(带刻度并可以通过滚动条调节直方图中直方条的个数)

2015-12-14 17:15 323 查看

OPENCV中画图像直方图(带刻度并可以通过滚动条调节直方图中直方条的个数)

本文是在《OpenCV教程基础篇》例题5-11的基础上进行的修改。

本文亮点:

(1)可以通过调节滚动条,来实现调节直方图中输出直方条的个数;

(2)在输出的直方图中添加了横纵坐标刻度,并且这些刻度可以随着滚动条的调节自适应改变。

#include "cv.h"
#include "highgui.h"
#include <stdio.h>
#include <ctype.h>
using namespace std;
using namespace cv;

IplImage *src = 0;
IplImage *histimg = 0;
CvHistogram *hist = 0;

int hdims = 50;     // 划分HIST的初始个数,越高越精确

//滚动条函数
void HIST(int t)
{
float hranges_arr[] = {0,255};
float* hranges = hranges_arr;
int bin_w;
int bin_u;
float max;
int i;
char string[10];
CvFont font;
cvInitFont( &font, CV_FONT_HERSHEY_PLAIN,1, 1, 0, 1, 8);//字体结构初始化
if(hdims==0)
{
printf("直方图条数不能为零!\n");
}
else
{
hist = cvCreateHist( 1, &hdims, CV_HIST_ARRAY, &hranges, 1 );  // 创建直方图
histimg = cvCreateImage(cvSize(800,512),8,3);
cvZero( histimg );
cvCalcHist( &src, hist, 0, 0 ); // 计算直方图
cvGetMinMaxHistValue(hist,NULL,&max,NULL,NULL);//寻找最大值及其位置
//printf("max_val:%f \n",max_val);
cvZero( histimg );

double bin_w =(double) histimg->width / hdims;  // hdims: 条的个数,则 bin_w 为条的宽度
double bin_u = (double)histimg->height/ max;  //// max: 最高条的像素个数,则 bin_u 为单个像素的高度

// 画直方图
for(int i=0;i<hdims;i++)
{
CvPoint p0=cvPoint(i*bin_w,histimg->height);
int val=cvGetReal1D(hist->bins,i);
CvPoint p1=cvPoint((i+1)*bin_w,histimg->height-cvGetReal1D(hist->bins,i)*bin_u);
cvRectangle(histimg,p0,p1,cvScalar(0,255),1,8,0);
}
//画纵坐标刻度(像素个数)
int kedu=0;
for(int i=1;kedu<max;i++)
{
kedu=i*max/10;
itoa(kedu,string,10);//把一个整数转换为字符串
//在图像中显示文本字符串
cvPutText(histimg, string , cvPoint(0,histimg->height-kedu*bin_u), &font, CV_RGB(0,255,255));
}
//画横坐标刻度(像素灰度值)
kedu=0;
for(int i=1;kedu<256;i++)
{
kedu=i*20;
itoa(kedu,string,10);//把一个整数转换为字符串
//在图像中显示文本字符串
cvPutText(histimg, string , cvPoint(kedu*(histimg->width / 256),histimg->height), &font, CV_RGB(255,0,0));
}

cvShowImage( "Histogram", histimg );
}
}

int main( int argc, char** argv )
{
argc=2;
argv[1]="lena.jpg";

if( argc != 2 || (src=cvLoadImage(argv[1], 0)) == NULL)  // force to gray image
return -1;

cvNamedWindow( "src", 1);
cvShowImage( "src", src);
cvNamedWindow( "Histogram", 1 );

cvCreateTrackbar( "hdims", "src", &hdims, 256, HIST );
HIST(0);
cvWaitKey(0);

cvDestroyWindow("src");
cvDestroyWindow("Histogram");
cvReleaseImage( &src );
cvReleaseImage( &histimg );
cvReleaseHist ( &hist );

return 0;
}


效果如下:

1.分成50条:





2.分成256条:





上面是老版本的代码,2.0版本的代码采用了Mat图像存储方式,新代码如下:

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

/*  全局变量的声明及初始化    */
Mat srcImage; //读入的图片矩阵
Mat dstImage; //读入的图片矩阵
MatND dstHist; //直方图矩阵,对应老版本中的cvCreateHist()
int g_hdims = 50;     // 划分HIST的初始个数,越高越精确

/* 回调函数声明 */
void on_HIST(int t,void *);

/*   主函数   */
int main( int argc, char** argv )
{

srcImage=imread("lena.jpg",0);//"0"表示读入灰度图像
namedWindow( "原图", 1 );//对应老版本中的cvNamedWindow( )
imshow("原图",srcImage);//对应老版本中的 cvShowImage()

createTrackbar( "hdims", "原图", &g_hdims, 256, on_HIST);//对应旧版本中的cvCreateTrackbar( );
on_HIST(0,0);//调用滚动条回调函数
cvWaitKey(0);
return 0;
}

/*      滚动条回调函数       */
void on_HIST(int t,void *)
{
dstImage=Mat::zeros(512,800,CV_8UC3);//每次都要初始化
float hranges[]={0,255}; //灰度范围
const float *ranges[]={hranges};//灰度范围的指针

if(g_hdims==0)
{
printf("直方图条数不能为零!\n");
}
else
{
/*
srcImage:读入的矩阵
1:数组的个数为1
0:因为灰度图像就一个通道,所以选0号通道
Mat():表示不使用掩膜
dstHist:输出的目标直方图
1:需要计算的直方图的维度为1
g_hdims:划分HIST的个数
ranges:表示每一维度的数值范围
*/
//int channels=0;
calcHist( &srcImage,1,0, Mat(),dstHist,1,&g_hdims,ranges); // 计算直方图对应老版本的cvCalcHist

/* 获取最大最小值 */
double max=0;
minMaxLoc(dstHist,NULL,&max,0,0);// 寻找最大值及其位置,对应旧版本的cvGetMinMaxHistValue();

/*  绘出直方图    */

double bin_w =(double) dstImage.cols/g_hdims;  // hdims: 条的个数,则 bin_w 为条的宽度
double bin_u = (double)dstImage.rows/ max;  //// max: 最高条的像素个数,则 bin_u 为单个像素的高度

// 画直方图
for(int i=0;i<g_hdims;i++)
{
Point p0=Point(i*bin_w,dstImage.rows);//对应旧版本中的cvPoint()

int val=dstHist.at<float>(i);//注意一点要用float类型,对应旧版本中的 cvGetReal1D(hist->bins,i);
Point p1=Point((i+1)*bin_w,dstImage.rows-val*bin_u);
rectangle(dstImage,p0,p1,cvScalar(0,255),1,8,0);//对应旧版中的cvRectangle();
}

/*   画刻度   */
char string[12];//存放转换后十进制数,转化成十进制后的位数不超过12位,这个根据情况自己设定
//画纵坐标刻度(像素个数)
int kedu=0;
for(int i=1;kedu<max;i++)
{
kedu=i*max/10;//此处选择10个刻度
itoa(kedu,string,10);//把一个整数转换为字符串,这个当中的10指十进制
//在图像中显示文本字符串
putText(dstImage, string , Point(0,dstImage.rows-kedu*bin_u), 1,1,Scalar(0,255,255));//对应旧版中的cvPutText()
}
//画横坐标刻度(像素灰度值)
kedu=0;
for(int i=1;kedu<256;i++)
{
kedu=i*20;//此处选择间隔为20
itoa(
4000
kedu,string,10);//把一个整数转换为字符串
//在图像中显示文本字符串
putText(dstImage, string , cvPoint(kedu*(dstImage.cols / 256),dstImage.rows),1,1,Scalar(0,255,255));
}
namedWindow( "Histogram", 1 );
imshow( "Histogram", dstImage );
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: