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

首先给大家推荐一下我老师大神的人工智能教学网站。教学不仅零基础,通俗易懂,而且非常风趣幽默,还时不时有内涵黄段子!点这里可以跳转到网站

           其实刚开始的时候,看很多的书和教程讲绘图和彩色图像等,但是我觉得还是先学会灰度直方图,因为灰度的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>

图像识别算法交流 QQ群:145076161,欢迎图像识别与图像算法,共同学习与交流

点这里可以跳转到人工智能网站

0 0 投票数
文章评分
订阅评论
提醒
0 评论
内联反馈
查看所有评论
0
希望看到您的想法,请发表评论。x
()
x