码迷,mamicode.com
首页 > 其他好文 > 详细

Opencv图像识别从零到精通(8)-----灰度直方图

时间:2016-07-19 11:08:03      阅读:341      评论:0      收藏:0      [点我收藏+]

标签:

           其实刚开始的时候,看很多的书和教程讲绘图和彩色图像等,但是我觉得还是先学会灰度直方图,因为灰度的dims是1,如果dims是3的就是彩色,同时知道前面将的彩色图像的像素访问,相信很快就可以迁移过去的。

 一、换个角度认识图像(直方图)

          第一个就是当我们面对图像的时候,我们面对的是抽象的矩阵,如下图,下面是0-255的灰度图像的表示,密密麻麻的

                                                  技术分享

           那么我们做的直方图,其实就是对这些像素值的统计,看下图,其中Bin是条数,数据和范围是对图的解释,一看就懂

                                     技术分享

二、准备知识

       如果想绘制出来直方图,先要知道几个函数

       (1) Point类数据结构表示了二维坐标系下的点

      Point point=Point(1,2);

       (2)calcHist()绘制直方图

void calcHist(const Mat* arrays, intnarrays, const int* channels, InputArray mask, OutputArray 
hist, int dims,const int* histSize, const float** ranges, bool uniform=true, boolaccumulate=false );

        参数解释:

  •        arrays:输入的图像的指针,可以是多幅图像,所有的图像必须有同样的深度(CV_8U orCV_32F)。同时一副图像可以有多个channes。
  •        narrays:输入的图像的个数。
  •        channels:用来计算直方图的channes的数组。比如输入是2副图像,第一副图像有0,1,2共三个channel,第二幅图像只有0一个channel,那么输入就一共有4个channes,如果int channels[3] = {3, 2, 0},那么就表示是使用第二副图像的第一个通道和第一副图像的第2和第0个通道来计算直方图。
  •        mask:掩码。如果mask不为空,那么它必须是一个8位(CV_8U)的数组,并且它的大小的和arrays[i]的大小相同,值为1的点将用来计算直方图。
  •        hist:计算出来的直方图
  •        dims:计算出来的直方图的维数。
  •        histSize:在每一维上直方图的个数。简单把直方图看作一个一个的竖条的话,就是每一维上竖条的个数。
  •        ranges:用来进行统计的范围。比如 float rang1[] = {0, 20};float rang2[] = {30, 40};  const float*rangs[] = {rang1, rang2};那么就是对0,20和30,40范围的值进行统计。
  •       uniform:每一个竖条的宽度是否相等。
  •       accumulate:  是否累加。如果为true,在下次计算的时候不会首先清空hist。

画直线,在图像img中画一条颜色为color,粗细为thickness,类型为lineType的直线

    (3)line() rectangle()画出直方图

void line(Mat& img, Point pt1, Pointpt2, const Scalar& color, int thickness=1,
         int lineType=8, int shift=0)
//两点确认一条直线。
//lineType:直线类型
//shift:坐标小数点维数
 
//画一个单一的实矩形
void rectangle(Mat& img, Point pt1,Point pt2, const Scalar& color, int thickness=1,
                 int lineType=8, int shift=0)
//一条对角线的两个顶点可确定一个矩形
//pt1和pt2互为对顶点
//thickness为负值表示矩形为实矩形


三、绘制一维灰度直方图

<span style="font-size:18px;">#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;

void Help()
{
	printf("\n\n\t\t\t欢迎来到直方图的世界!\n");
	printf("\n\n  ----------------------------------------------------------------------------\n");
}


int main()
{
	Mat srcImage = imread("lena.jpg", 0);
	imshow("原图",srcImage);
	if(!srcImage.data) {cout << "fail to load image" << endl; 	return 0;}
	system("color 1F");
	Help();

	MatND dstHist;       // 在cv中用CvHistogram *hist = cvCreateHist
	int dims = 1;
	float hranges[2] = {0, 255};
	const float *ranges[1] = {hranges};   // 这里需要为const类型
	int size = 256;
	int channels = 0;
	//计算图像的直方图
	calcHist(&srcImage, 1, &channels, Mat(), dstHist, dims, &size, ranges);    // cv 中是cvCalcHist
	int scale = 1;
	Mat dstImage(size * scale, size, CV_8U, Scalar(0));
	//获取最大值和最小值
	double minValue = 0;
	double maxValue = 0;
	minMaxLoc(dstHist,&minValue, &maxValue, 0, 0);  //  在cv中用的是cvGetMinMaxHistValue
	//绘制出直方图
	int hpt = saturate_cast<int>(0.9 * size);
	for(int i = 0; i < 256; i++)
	{
		float binValue = dstHist.at<float>(i);           //   注意hist中是float类型    
		int realValue = saturate_cast<int>(binValue * hpt/maxValue);
		//rectangle(dstImage,Point(i*scale, size - 1), Point((i+1)*scale - 1, size - realValue), Scalar(255));
		line(dstImage,Point(i*scale,size-1),Point((i+1)*scale-1,size-realValue),Scalar(255));
	}
	imshow("一维直方图", dstImage);
	waitKey(0);
	return 0;
}</span>

技术分享

      其实我们有时候想改变量化,上面的表示是256,我们可以50 100都可以,这里用过滑块的知识,所以不想多讲,只是提供一个别人写的参考,尊重原作者,写的很好

<span style="font-size:18px;">#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;
}</span>

技术分享

三、彩色直方图

      这里不想过多的介绍,以后讲彩色图像的时候会具体的说

四、matlab辅助

      一个imhist()函数就搞定了

<span style="font-size:18px;">clear;
%%读入图像
a=imread('cameraman.tif');
imhist(a);
title('原始cameraman图像的直方图');</span>

技术分享

Opencv图像识别从零到精通(8)-----灰度直方图

标签:

原文地址:http://blog.csdn.net/qq_20823641/article/details/51932798

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!