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



转载自dengshuaifei

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

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

本文亮点:

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

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



  
  
  1. #include "cv.h"
  2. #include "highgui.h"
  3. #include <stdio.h>
  4. #include <ctype.h>
  5. using namespace std;
  6. using namespace cv;
  7. IplImage *src = 0;
  8. IplImage *histimg = 0;
  9. CvHistogram *hist = 0;
  10. int hdims = 50; // 划分HIST的初始个数,越高越精确
  11. //滚动条函数
  12. void HIST(int t)
  13. {
  14. float hranges_arr[] = { 0, 255};
  15. float* hranges = hranges_arr;
  16. int bin_w;
  17. int bin_u;
  18. float max;
  19. int i;
  20. char string[ 10];
  21. CvFont font;
  22. cvInitFont( &font, CV_FONT_HERSHEY_PLAIN, 1, 1, 0, 1, 8); //字体结构初始化
  23. if(hdims== 0)
  24. {
  25. printf( "直方图条数不能为零!\n");
  26. }
  27. else
  28. {
  29. hist = cvCreateHist( 1, &hdims, CV_HIST_ARRAY, &hranges, 1 ); // 创建直方图
  30. histimg = cvCreateImage(cvSize( 800, 512), 8, 3);
  31. cvZero( histimg );
  32. cvCalcHist( &src, hist, 0, 0 ); // 计算直方图
  33. cvGetMinMaxHistValue(hist, NULL,&max, NULL, NULL); //寻找最大值及其位置
  34. //printf("max_val:%f \n",max_val);
  35. cvZero( histimg );
  36. double bin_w =( double) histimg->width / hdims; // hdims: 条的个数,则 bin_w 为条的宽度
  37. double bin_u = ( double)histimg->height/ max; //// max: 最高条的像素个数,则 bin_u 为单个像素的高度
  38. // 画直方图
  39. for( int i= 0;i<hdims;i++)
  40. {
  41. CvPoint p0=cvPoint(i*bin_w,histimg->height);
  42. int val=cvGetReal1D(hist->bins,i);
  43. CvPoint p1=cvPoint((i+ 1)*bin_w,histimg->height-cvGetReal1D(hist->bins,i)*bin_u);
  44. cvRectangle(histimg,p0,p1,cvScalar( 0, 255), 1, 8, 0);
  45. }
  46. //画纵坐标刻度(像素个数)
  47. int kedu= 0;
  48. for( int i= 1;kedu<max;i++)
  49. {
  50. kedu=i*max/ 10;
  51. itoa(kedu, string, 10); //把一个整数转换为字符串
  52. //在图像中显示文本字符串
  53. cvPutText(histimg, string , cvPoint( 0,histimg->height-kedu*bin_u), &font, CV_RGB( 0, 255, 255));
  54. }
  55. //画横坐标刻度(像素灰度值)
  56. kedu= 0;
  57. for( int i= 1;kedu< 256;i++)
  58. {
  59. kedu=i* 20;
  60. itoa(kedu, string, 10); //把一个整数转换为字符串
  61. //在图像中显示文本字符串
  62. cvPutText(histimg, string , cvPoint(kedu*(histimg->width / 256),histimg->height), &font, CV_RGB( 255, 0, 0));
  63. }
  64. cvShowImage( "Histogram", histimg );
  65. }
  66. }
  67. int main( int argc, char** argv )
  68. {
  69. argc= 2;
  70. argv[ 1]= "lena.jpg";
  71. if( argc != 2 || (src=cvLoadImage(argv[ 1], 0)) == NULL) // force to gray image
  72. return -1;
  73. cvNamedWindow( "src", 1);
  74. cvShowImage( "src", src);
  75. cvNamedWindow( "Histogram", 1 );
  76. cvCreateTrackbar( "hdims", "src", &hdims, 256, HIST );
  77. HIST( 0);
  78. cvWaitKey( 0);
  79. cvDestroyWindow( "src");
  80. cvDestroyWindow( "Histogram");
  81. cvReleaseImage( &src );
  82. cvReleaseImage( &histimg );
  83. cvReleaseHist ( &hist );
  84. return 0;
  85. }

效果如下:

1.分成50条:

2.分成256条:


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



  
  
  1. #include <opencv2/opencv.hpp>
  2. #include <iostream>
  3. using namespace std;
  4. using namespace cv;
  5. /* 全局变量的声明及初始化 */
  6. Mat srcImage; //读入的图片矩阵
  7. Mat dstImage; //读入的图片矩阵
  8. MatND dstHist; //直方图矩阵,对应老版本中的cvCreateHist()
  9. int g_hdims = 50; // 划分HIST的初始个数,越高越精确
  10. /* 回调函数声明 */
  11. void on_HIST(int t,void *);
  12. /* 主函数 */
  13. int main( int argc, char** argv )
  14. {
  15. srcImage=imread( "lena.jpg", 0); //"0"表示读入灰度图像
  16. namedWindow( "原图", 1 ); //对应老版本中的cvNamedWindow( )
  17. imshow( "原图",srcImage); //对应老版本中的 cvShowImage()
  18. createTrackbar( "hdims", "原图", &g_hdims, 256, on_HIST); //对应旧版本中的cvCreateTrackbar( );
  19. on_HIST( 0, 0); //调用滚动条回调函数
  20. cvWaitKey( 0);
  21. return 0;
  22. }
  23. /* 滚动条回调函数 */
  24. void on_HIST(int t,void *)
  25. {
  26. dstImage=Mat::zeros( 512, 800,CV_8UC3); //每次都要初始化
  27. float hranges[]={ 0, 255}; //灰度范围
  28. const float *ranges[]={hranges}; //灰度范围的指针
  29. if(g_hdims== 0)
  30. {
  31. printf( "直方图条数不能为零!\n");
  32. }
  33. else
  34. {
  35. /*
  36. srcImage:读入的矩阵
  37. 1:数组的个数为1
  38. 0:因为灰度图像就一个通道,所以选0号通道
  39. Mat():表示不使用掩膜
  40. dstHist:输出的目标直方图
  41. 1:需要计算的直方图的维度为1
  42. g_hdims:划分HIST的个数
  43. ranges:表示每一维度的数值范围
  44. */
  45. //int channels=0;
  46. calcHist( &srcImage, 1, 0, Mat(),dstHist, 1,&g_hdims,ranges); // 计算直方图对应老版本的cvCalcHist
  47. /* 获取最大最小值 */
  48. double max= 0;
  49. minMaxLoc(dstHist, NULL,&max, 0, 0); // 寻找最大值及其位置,对应旧版本的cvGetMinMaxHistValue();
  50. /* 绘出直方图 */
  51. double bin_w =( double) dstImage.cols/g_hdims; // hdims: 条的个数,则 bin_w 为条的宽度
  52. double bin_u = ( double)dstImage.rows/ max; //// max: 最高条的像素个数,则 bin_u 为单个像素的高度
  53. // 画直方图
  54. for( int i= 0;i<g_hdims;i++)
  55. {
  56. Point p0=Point(i*bin_w,dstImage.rows); //对应旧版本中的cvPoint()
  57. int val=dstHist.at< float>(i); //注意一点要用float类型,对应旧版本中的 cvGetReal1D(hist->bins,i);
  58. Point p1=Point((i+ 1)*bin_w,dstImage.rows-val*bin_u);
  59. rectangle(dstImage,p0,p1,cvScalar( 0, 255), 1, 8, 0); //对应旧版中的cvRectangle();
  60. }
  61. /* 画刻度 */
  62. char string[ 12]; //存放转换后十进制数,转化成十进制后的位数不超过12位,这个根据情况自己设定
  63. //画纵坐标刻度(像素个数)
  64. int kedu= 0;
  65. for( int i= 1;kedu<max;i++)
  66. {
  67. kedu=i*max/ 10; //此处选择10个刻度
  68. itoa(kedu, string, 10); //把一个整数转换为字符串,这个当中的10指十进制
  69. //在图像中显示文本字符串
  70. putText(dstImage, string , Point( 0,dstImage.rows-kedu*bin_u), 1, 1,Scalar( 0, 255, 255)); //对应旧版中的cvPutText()
  71. }
  72. //画横坐标刻度(像素灰度值)
  73. kedu= 0;
  74. for( int i= 1;kedu< 256;i++)
  75. {
  76. kedu=i* 20; //此处选择间隔为20
  77. itoa(kedu, string, 10); //把一个整数转换为字符串
  78. //在图像中显示文本字符串
  79. putText(dstImage, string , cvPoint(kedu*(dstImage.cols / 256),dstImage.rows), 1, 1,Scalar( 0, 255, 255));
  80. }
  81. namedWindow( "Histogram", 1 );
  82. imshow( "Histogram", dstImage );
  83. }
  84. }






猜你喜欢

转载自blog.csdn.net/weixin_41342624/article/details/89146464
今日推荐