其實剛開始的時候,看很多的書和教程講繪圖和彩色圖像等,但是我覺得還是先學(xué)會灰度直方圖,因為灰度的dims是1,如果dims是3的就是彩色,同時知道前面將的彩色圖像的像素訪問,相信很快就可以遷移過去的。
一、換個角度認(rèn)識圖像(直方圖)
第一個就是當(dāng)我們面對圖像的時候,我們面對的是抽象的矩陣,如下圖,下面是0-255的灰度圖像的表示,密密麻麻的
那么我們做的直方圖,其實就是對這些像素值的統(tǒng)計,看下圖,其中Bin是條數(shù),數(shù)據(jù)和范圍是對圖的解釋,一看就懂
二、準(zhǔn)備知識
如果想繪制出來直方圖,先要知道幾個函數(shù)
(1) Point類數(shù)據(jù)結(jié)構(gòu)表示了二維坐標(biāo)系下的點
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 );
參數(shù)解釋:
- arrays:輸入的圖像的指針,可以是多幅圖像,所有的圖像必須有同樣的深度(CV_8U orCV_32F)。同時一副圖像可以有多個channes。
- narrays:輸入的圖像的個數(shù)。
- channels:用來計算直方圖的channes的數(shù)組。比如輸入是2副圖像,第一副圖像有0,1,2共三個channel,第二幅圖像只有0一個channel,那么輸入就一共有4個channes,如果int channels[3] = {3, 2, 0},那么就表示是使用第二副圖像的第一個通道和第一副圖像的第2和第0個通道來計算直方圖。
- mask:掩碼。如果mask不為空,那么它必須是一個8位(CV_8U)的數(shù)組,并且它的大小的和arrays[i]的大小相同,值為1的點將用來計算直方圖。
- hist:計算出來的直方圖
- dims:計算出來的直方圖的維數(shù)。
- histSize:在每一維上直方圖的個數(shù)。簡單把直方圖看作一個一個的豎條的話,就是每一維上豎條的個數(shù)。
- ranges:用來進(jìn)行統(tǒng)計的范圍。比如 float rang1[] = {0, 20};float rang2[] = {30, 40}; const float*rangs[] = {rang1, rang2};那么就是對0,20和30,40范圍的值進(jìn)行統(tǒng)計。
- uniform:每一個豎條的寬度是否相等。
- accumulate: 是否累加。如果為true,在下次計算的時候不會首先清空hist。
畫直線,在圖像img中畫一條顏色為color,粗細(xì)為thickness,類型為lineType的直線
(3)line() rectangle()畫出直方圖
- void line(Mat& img, Point pt1, Pointpt2, const Scalar& color, int thickness=1,
- int lineType=8, int shift=0)
- //兩點確認(rèn)一條直線。
- //lineType:直線類型
- //shift:坐標(biāo)小數(shù)點維數(shù)
-
- //畫一個單一的實矩形
- void rectangle(Mat& img, Point pt1,Point pt2, const Scalar& color, int thickness=1,
- int lineType=8, int shift=0)
- //一條對角線的兩個頂點可確定一個矩形
- //pt1和pt2互為對頂點
- //thickness為負(fù)值表示矩形為實矩形
三、繪制一維灰度直方圖
- <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的初始個數(shù),越高越精確
-
- //滾動條函數(shù)
- 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);//字體結(jié)構(gòu)初始化
- if(hdims==0)
- {
- printf("直方圖條數(shù)不能為零!\n");
- }
- else
- {
- hist = cvCreateHist( 1, &hdims, CV_HIST_ARRAY, &hranges, 1 ); // 創(chuàng)建直方圖
- 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: 條的個數(shù),則 bin_w 為條的寬度
- double bin_u = (double)histimg->height/ max; //// max: 最高條的像素個數(shù),則 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);
- }
- //畫縱坐標(biāo)刻度(像素個數(shù))
- int kedu=0;
- for(int i=1;kedu<max;i++)
- {
- kedu=i*max/10;
- itoa(kedu,string,10);//把一個整數(shù)轉(zhuǎn)換為字符串
- //在圖像中顯示文本字符串
- cvPutText(histimg, string , cvPoint(0,histimg->height-kedu*bin_u), &font, CV_RGB(0,255,255));
- }
- //畫橫坐標(biāo)刻度(像素灰度值)
- kedu=0;
- for(int i=1;kedu<256;i++)
- {
- kedu=i*20;
- itoa(kedu,string,10);//把一個整數(shù)轉(zhuǎn)換為字符串
- //在圖像中顯示文本字符串
- 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()函數(shù)就搞定了
- <span style="font-size:18px;">clear;
- %%讀入圖像
- a=imread('cameraman.tif');
- imhist(a);
- title('原始cameraman圖像的直方圖');</span>
圖像識別算法交流 QQ群:145076161,歡迎圖像識別與圖像算法,共同學(xué)習(xí)與交流
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請
點擊舉報。