opencv使用記錄

/*2017-1-14*/

/*視頻的讀取。。。*/

int g_n=0;
void on_change(int pos,void *)//看來void*不能省! 
{
	printf("g_n id %d\n",pos);
}

int main()
{
	//結構體第一個字母都是大寫,函數小寫 
	//打開視頻文件:其實就是創建一個VideoCapture結構  
	VideoCapture capture("E:\\vedio\\01.avi");
	//檢測是否正常打開:成功打開時,isOpened返回ture  
    if(!capture.isOpened())  
        cout<<"fail to open!"<<endl; 
		 
    //獲取整個幀數
    //capture.get(宏)能夠獲取各類屬性信息 
    long total = capture.get(CV_CAP_PROP_FRAME_COUNT);  
    cout<<"視頻"<<total<<"幀"<<endl;
    namedWindow("視頻",1);
    
    createTrackbar("position","視頻",&g_n,total,&on_change);
	on_change(g_n,0);
	
	Mat frame;  
    while(capture.read(frame)){
		//frame 保存當前讀取幀文件,會保存讀取信息,讀到結尾會返回NULL 
		imshow("car",frame);
		
		char c = waitKey(1);//這一步很重要,否則看不到視頻內容,延時30ms(每秒30幀)
   	
	   	while( c ==' '){//可使用空格暫停 
    		c=waitKey(0);
    	}
	}
    capture.release();

	waitKey(0);  
	return 0;
}

/*
Mat這個類有兩部分數據。
一個是matrixheader,這部分的大小是固定的,包含矩陣的大小,存儲的方式,矩陣存儲的地址等等。
另外一個部分是一個指向矩陣包含像素值的指針。
*/

/*,使用矩陣爲Mat賦值的時候,位數必定要匹配,CV_8U是8位,而一個int有4個字節,*/

int main()
{
	char data[]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18};
	//尼瑪,我說怎麼搜到的程序上有使用char定義數組給Mat賦值的,這TMD位數不匹配,因此用char 
	Mat M = Mat(1, 18, CV_8U, data);
	//CV_8U是8位,而一個int有4個字節,這是否是說明,
	//這樣成立的話,是否是說明,即便是64位的編譯器,一個字節也是8位(廢話!!) 
	//Mat M(3,3,CV_8UC2); 
	//M=(Mat_<int>(3,3) <<);
//	for(int y=0;y<M.rows;y++){
//		for(int x=0;x<M.cols;x++){
//			 int value = M.at<int>(y,x);
//			 printf("%2d",value);
//		}
//		cout<<endl;
//	}
	
	cout<<sizeof(int)<<endl;
	cout<<M<<endl;


	waitKey(0);  
	return 0;
	
}


/* 函數 M.channels()  M.ptr()  分別返回M的通道數和行地址
儘管M是以兩個通道類型保存的數據,而且二維矩陣,可是,返回指針任然是一維,行式存儲
 */

	char* p =(char *)M.ptr(0);//ptr<>()函數返回第i行的地址 
	cout<<(int)++data[2]<<endl;
	//儘管M是以兩個通道類型保存的數據,而且二維矩陣,可是,返回指針任然是一維,行式存儲 
	//只能經過逐步移動指針,訪問同一元素的不一樣通道的值 
	//不作強制轉換,就會輸出字符,看來上面是自動強制了 

/*2017-1-16*/
/*分離通道,看來,使用*/char* p =(char *)M.ptr(0)/*返回的行地址,增長也是以單個字節爲單位*/

int main()
{
	Mat M=imread("E:\\visio\\1.jpg",1);

	Mat rtemp=Mat::zeros(M.size(),CV_8UC1); 
	Mat gtemp=Mat::zeros(M.size(),CV_8UC1); 
	Mat btemp=Mat::zeros(M.size(),CV_8UC1); 
	
	for(int i=0;i<M.rows;i++){
		char* data = M.ptr<char>(i);
		
		for(int j=0;j<M.cols;j++){

			rtemp.at<uchar>(i,j) = (data+3*j)[0];
			gtemp.at<uchar>(i,j) = (data+3*j)[1];
			btemp.at<uchar>(i,j) = (data+3*j)[2];
		}
	}	
	imshow("Rtongdao",rtemp);
	imshow("Gtongdao",gtemp);
	imshow("Btongdao",btemp);
	waitKey(0);
} 

//彩色版本  而且使用 Vec3b 
//template<typename_Tp, int n> class Vec : public Matx<_Tp, n, 1> {...};
typedef Vec<uchar, 3> Vec3b;
//其實這句就是定義一個uchar類型的數組,長度爲3

	Mat rtemp=Mat::zeros(M.size(),CV_8UC3); 
	Mat gtemp=Mat::zeros(M.size(),CV_8UC3); 
	Mat btemp=Mat::zeros(M.size(),CV_8UC3); 
	
	for(int i=0;i<M.rows;i++){
		char* data = M.ptr<char>(i);
		char* bdata = btemp.ptr<char>(i);
		char* gdata = gtemp.ptr<char>(i);
		char* rdata = rtemp.ptr<char>(i);
		for(int j=0;j<M.cols;j++){
			
			(bdata+3*j)[0] = (data+3*j)[0];
			gtemp.at<Vec3b>(i,j)[1]=(data+3*j)[1];
			////其實這句就是定義一個uchar類型的數組,長度爲3
			(rdata+3*j)[2] = (data+3*j)[2];
	
		}
	}	

/*繪製一維直方圖*/

int main()
{
	//【1】載入原圖並顯示
	Mat srcImage = imread("E:\\visio\\1.jpg", 1);
	imshow("原圖",srcImage);
	if(!srcImage.data) {cout << "fail to load image" << endl; 	return 0;}
	Mat btemp(srcImage.size(),CV_8UC1);
	Mat gtemp(srcImage.size(),CV_8UC1);
	Mat rtemp(srcImage.size(),CV_8UC1);
	
	vector<Mat> channel;
	//建立mat爲元素的可變數組; 
	split(srcImage,channel);
	//使用split函數分離通道爲三個元素,存放到channles[]
	btemp = channel.at(0);
	gtemp = channel.at(1);
	rtemp = channel.at(2);
	 
	imshow("b",btemp);
	imshow("g",gtemp);
	imshow("r",rtemp);
	
	//【2】定義變量
	MatND bdstHist,gdstHist,rdstHist;
	
	int dims = 1;//幾維直方圖 
	float hranges[] = {0, 255};//範圍數組 
	const float *ranges[] = {hranges};// 這裏須要爲const類型,幾維,從這取幾個範圍,元素是數組 
	int size[] = {256};//每一維度尺寸的大小,幾維,就有幾個尺寸,裏面的元素是數 
	int channels = 0;

	//【3】計算圖像的直方圖
	calcHist(&btemp, 1, &channels, Mat(), bdstHist, dims, size, ranges);  
	calcHist(&gtemp, 1, &channels, Mat(), gdstHist, dims, size, ranges);
	calcHist(&rtemp, 1, &channels, Mat(), rdstHist, dims, size, ranges);
	
	
	int scale = 5;//能夠根據用戶的需求調節顯示圖像 
	Mat bdstImage(256 , 64*scale, CV_8U, Scalar(0));//保存白色高度,8位的,單通道圖像
	Mat gdstImage(256 , 64*scale, CV_8U, Scalar(0));
	Mat rdstImage(256 , 64*scale, CV_8U, Scalar(0));
	
	
	//【4】獲取最大值和最小值
	double bminValue = 0,gminValue = 0,rminValue = 0;
	double bmaxValue = 0,gmaxValue = 0,rmaxValue = 0;
	minMaxLoc(bdstHist,&bminValue, &bmaxValue, 0, 0);  
	minMaxLoc(gdstHist,&gminValue, &gmaxValue, 0, 0);
	minMaxLoc(rdstHist,&rminValue, &rmaxValue, 0, 0);
	
	//【5】繪製出直方圖
	int hpt = 64 ;
	for(int i = 0; i < 256; i++)//有256組,因此要畫256次 
	{
		float binValue = bdstHist.at<float>(i);//獲取對應直方柱的值
		//感受當Mat.at<>()[],,若是對象的元素是單通道,不須要[],當元素爲數組vec3b,須要[] 
		
		int realValue = saturate_cast<int>(binValue * hpt/bmaxValue);
		//是加是減,乘除,都會超出一個像素灰度值的範圍
		//當運算完以後,結果爲負,則轉爲0,結果超出255,則爲255。
		
		rectangle(bdstImage,//對角兩個點,畫矩形
				Point(i*scale, 64 - 1), //原點在左上角,因此點在下水平軸上 
				Point((i+1)*scale - 3, 64 - realValue), // -3,應該是柱與柱之間測間隔。 
				Scalar(255));// scalar(255),邊框填充白色 
	}
	
	for(int i = 0; i < 256; i++)
	{
		float binValue = gdstHist.at<float>(i);
		int realValue = saturate_cast<int>(binValue * hpt/gmaxValue);
	
		rectangle(gdstImage,
				Point(i*scale, 64 - 1),  
				Point((i+1)*scale - 3, 64 - realValue),   
				Scalar(255));  
	}
	
	for(int i = 0; i < 256; i++)
	{
		float binValue = rdstHist.at<float>(i);
		int realValue = saturate_cast<int>(binValue * hpt/rmaxValue);
	
		rectangle(rdstImage,
				Point(i*scale, 64 - 1),  
				Point((i+1)*scale - 3, 64 - realValue),   
				Scalar(255));  
	}
	imshow("一維直方圖b", bdstImage);
	imshow("一維直方圖g", gdstImage);
	imshow("一維直方圖r", rdstImage);
	waitKey(0);
	return 0;
}

/*以灰度圖像加載圖像是經過公式Y=0.2..*b+0.5*g+0.1..*r=R=G=B計算*/

/*RGB顏色空間中,對角線上,沒有顏色,只有亮度,即當R=G=B*/

/*色相(Hue):指物體傳導或反射的波長。定義各類顏色,取值範圍0度-360度,直徑兩端,是互補色(混在一塊兒是白色)
飽和度(Saturation):又稱色度,是指色彩的強度或純度。越靠近內軸,彷佛就摻了白色,變得淡了
亮度 (brightness/Intensity):是指顏色的相對明暗度(能夠理解爲光照),一般以 0% (黑色) 到 100% (白色) 的百分比來衡量。
*/

/*不必value非得定義成char,定義成int徹底能覆蓋,CV-8U全部數值 */
/*當Mat型數據的元素是,三通道時,使用(vec3b)訪問時可使用下標定位 hsvImage.at<Vec3b>(i,j)[1]*/
	
	int value;
	for(int i=0;i<hsvImage.rows;i++){
		for(int j=0;j<hsvImage.cols;j++)
			{
				value = hsvImage.at<Vec3b>(i,j)[1];//當char被賦值170時可能已經發生了溢出, 
				cout<<value<<" ";					//因此以後不管怎麼處理都挽回不了,
				 
			}
	}
//	imshow("hsv",hsvImage); 
	cout<<endl<<format(srcImage,"python")<<endl<<endl;
	cout<<format(hsvImage,"python");
	
/*srcImage.copyTo(hsvImage);//這個函數應該是把數據類型也改了 */
/*copy的使用*/
C++: void Mat::copyTo(OutputArray m) const
C++: void Mat::copyTo(OutputArray m, InputArray mask) const
/*通常狀況下使用第一種複製的方法,目的矩陣和數據矩陣大小須要相同
(一半設置爲圖像的感興趣區域,用來賦值LOGO)
第二種使用方式,有一個mask(只須要單通道),
mask須要與數據矩陣等大,其非零區域代表須要使用的地方,零的不會用來複制,因此目的矩陣的對應區域不變
*/

/*2016-1-18*/

/*
cvConvertScale(IplImage*,IplImage*,1.0,0)函數彷佛只能使用IplImage=cvLoadImage加載的圖像才能運行;
在Mat數據類型中有個函數convertTo()函數,以下,也能夠轉換數據類型
*/
/*
使用cout顯示的方式,不如使用循環指針訪問獲得的真實
*/

/*
保存HSV格式的圖像,圖像數據只能用char大小的數據
*/

int main(int argc, char** argv)  
{  
	char data[]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18};
    Mat src2 = Mat(3, 2, CV_8UC3, data);
	Mat src3;
 
	src2.convertTo(src3,CV_32FC3,1.0,0.1);
	
	float value[3];
	for(int i=0;i<src3.rows;i++){
		for(int j=0;j<src3.cols;j++)
			{
				value[0] = src3.at<Vec3f>(i,j)[0];
				value[1] = src3.at<Vec3f>(i,j)[1];
				value[2] = src3.at<Vec3f>(i,j)[2];
				cout<<"<"<<value[0]<<" "<<value[1]<<" "<<value[2]<<endl;
				 
			}
	}
	
		
	//保存HSV格式的圖像,圖像數據只能用char大小的數據
	hsvImage.convertTo(hsvImage,CV_8UC3,(1.0/360)*255,0); 
	 
	imshow("hsv",hsvImage); 
  	cout<<endl<<format(src3,"python");
  	imshow("jieguo",src3); 
    getchar();  
    return 0;  
}

/*
自定義結構體元素,進行腐蝕操做:若是B的原點平移到點(x,y),那麼B將徹底包含於X中。輸入的二值圖像只包含黑色(0)和白色(255)像素,所以結構元素覆蓋的圖像區域中有黑色像素,則錨點所在像素(x,y)將會被替換成黑色0,不然替換成白色255。而物體的邊界一般會有黑色像素,因此腐蝕至關於收縮邊界。

另外一種理解,腐蝕就是把當前像素替換成所定義的像素集中的最小像素值。


*/
int main()
{
	char data[20][20]={0};
	for(int i=3;i<8;i++){
		for(int j=4;j<10;j++){
			data[i][j]=255;
		}
	} 
	for(int i=8;i<16;i++){
		for(int j=2;j<8;j++){
			data[i][j]=255;
		}
	}
	Mat srcImage(20,20, CV_8UC1, data);
	cout<<format(srcImage,"python");
	
	//使用自定義結構元素進行腐蝕的正確姿式,
	//網上說本身定義麻煩,確實本身賦值結構元素是有點麻煩,
	//自定義一個有「形狀」的mat,erode 自動能夠判斷其餘參數 
	char vaule[16]={ 0,0,0,0,
					 0,0,1,0,
					 0,1,1,0,
					 0,0,0,0};
	Mat element(4,4,CV_8UC1,vaule);
	Mat result(srcImage.size(),CV_8UC1,Scalar::all(0));
	erode(srcImage,result,element);//默認腐蝕操做一次
	cout<<endl<<endl<<format(result,"python");
	
					 

	waitKey(0);
	return 0;
}

/*2016-1-17*/
/*輪廓提取
一、提取前應該先使用邊緣算子處理,才能提取到單根輪廓
二、看來轉爲灰度圖,保存的通道也是 cvtColor
三、vector<Vec4i> hierarchy;保存輪廓關係一維數組,元素是4個數
	vector< vector<Point> > contours;保存輪廓數據的「二維數組」,元素是點
四、//hierarchy[][]後一個輪廓、前一個輪廓、內嵌輪廓,父輪廓的contours數組索引編號(行)
五、反過來用(y,x)srcImage.at<Vec3b>(y,x)[2]=255;//對對,這樣使用是先返回行,對應於座標是y 
*/
int main()
{
	Mat srcImage=imread("E:/visio/lunkuo.jpg");
	
	//cvtColor(srcImage,srcImage,CV_BGR2GRAY,0);
	//這就是單通道了,看來轉爲灰度圖,保存的通道也是 1 
	 
	imshow("jiegou",srcImage);
//	cout<<format(srcImage,"python")<<endl;
	Mat gimage;  
    GaussianBlur(srcImage,gimage,Size(3,3),0);//高斯模糊 
//    imshow("GAUSS Image",gimage);//這裏仍是彩色的 
    Mat cimage;
    Canny(gimage,cimage,100,250); //圖像處理之Canny 邊緣檢測 1
//    imshow("Cann Image",cimage);
 // cout<<format(image,"python")<<endl;//這裏已經變成單通道了 
      
	Mat lunkuo=Mat::zeros(srcImage.size(),CV_8UC3);  //繪製 
	vector<Vec4i> hierarchy;  
	vector< vector<Point> > contours;
	//第二個參數:contours,定義爲「vector<vector<Point>> contours」,
	//是一個向量,而且是一個雙重向量,向量
    //內每一個元素保存了一組由連續的Point點構成的點的集合的向量,每一組Point點集就是一個輪廓。  
    //有多少輪廓,向量contours就有多少元素。

	//使用cvFindContours的返回值爲int型,指檢測出來的輪廓的個數
	findContours(cimage,contours,hierarchy,1,CV_CHAIN_APPROX_NONE);//沒有返回值 
	//只有以第四種模式尋找輪廓,hierarchy的數組,才能徹底被附上應有的值! 
 	int idx = 0;
 	int i=0;
    for( ; idx<contours.size(); idx++){
    	 for(int j=0;j<contours[idx].size();j++){
    	 	int x=contours[idx][j].x,y=contours[idx][j].y;
		 	if(idx % 2 == 0) lunkuo.at<Vec3b>(y,x)[2]=255;
			if(idx % 2 != 0) lunkuo.at<Vec3b>(y,x)[1]=255;
			//除了模式0以外,
			//1,2,3模式每個輪廓都有兩個存儲數組,僅有幾個點有差異,8個輪廓共16個數組 
//      Scalar color(0,0,255 );
//		drawContours( lunkuo, contours, idx, color, 1, 8, hierarchy );
//		使用drawContours,能夠順便給線復顏色值,idx是contour數組的行變量,
//		應該還不至於操做父子結構。。以後的參數掠過 
		}
		imshow("lunkuo",lunkuo);
    }

//	imshow("lunkuo",lunkuo);
	
	
/*	模式2-1 查找全部輪廓,所有輸出 
	for(i=0;i<contours.size();i++)  
    {  
        //contours[i]表明的是第i個輪廓,
		//contours[i].size()表明的是第i個輪廓上全部的像素點數  
        for(int j=0;j<contours[i].size();j++)   
        {  
            //繪製出contours向量內全部的像素點
			//這裏要想畫在原圖上,要畫gimage,由於gimage已經與原圖像不同了
			//而且原圖像畫邊界的部分是白色,都是255,因此會有截斷彷佛
			//還有一種辦法,更改原圖像  
            int x=contours[i][j].x,y=contours[i][j].y;  
            //還有一種辦法,更改原圖像 ,數組的話還不能總體賦值呢,就先一步一步操做吧 
			//這裏竟然要反過來用,像素點(x,y),,這裏要輸入(y,x) 
			//否則就使用Point point(x,y),,srcImage.at<Vec3b>(p)[] 
			srcImage.at<Vec3b>(y,x)[2]=255;//對對,這樣使用是先返回行,對應於座標是y 
			srcImage.at<Vec3b>(y,x)[0]=0; //那麼使用的時候,也得反着用 
			srcImage.at<Vec3b>(y,x)[1]=0;  
		
        }
        
        //輸出hierarchy向量內容  
        cout<<"向量hierarchy的第" <<i<<" 個元素內容爲:"<<endl
		<<hierarchy[i]<<endl<<endl;  
	}
	imshow("lunkuo",srcImage);
*/	
	
/*  模式 	RETR_EXTERNAL==0  只查找最外層輪廓,
	輪廓保存數組,仍然是二維,儘管只保存一個輪廓
	沒有使用層次關係 hierarchy
	for(int i=0;i<contours.size();i++)  
    {  
        //contours[i]表明的是第i個輪廓,contours[i].size()表明的是第i個輪廓上全部的像素點數  
        for(int j=0;j<contours[i].size();j++)   
        {  
           //繪製出contours向量內全部的像素點  
            Point P=Point(contours[i][j].x,contours[i][j].y);  
            lunkuo.at<uchar>(P)=255;  
        }
        
         //輸出hierarchy向量內容  
        char ch[256];  
        sprintf(ch,"%d",i);  
        string str=ch;
    //hierarchy[][]後一個輪廓、前一個輪廓、內嵌輪廓的索引編號,父輪廓、應該是contours的行號 
        cout<<"向量hierarchy的第" <<str<<" 個元素內容爲:"<<endl<<hierarchy[i]<<endl<<endl;  
  
	}
	imshow("lunkuo",lunkuo);
*/
	waitKey(0);
	return 0;
}

/*2017-1-19*/
//圖像的細化,先有原圖獲得灰度圖cvtColor
//在有灰度圖獲得二值化threshold
//由程序中判斷邊緣點的方法將其記錄到edg,再由索引表八連通圖的方法判斷是否爲刪除點,記錄到delete,以後刪除
//以後再有邊緣函數fincontours試試..........
void deletecontours(Mat &srcImage)  
{ 
    unsigned char deletemark[256] = {  
        0,0,0,0,0,0,0,1,    0,0,1,1,0,0,1,1,  
        0,0,0,0,0,0,0,0,    0,0,1,1,1,0,1,1,  
        0,0,0,0,0,0,0,0,    1,0,0,0,1,0,1,1,  
        0,0,0,0,0,0,0,0,    1,0,1,1,1,0,1,1,  
        0,0,0,0,0,0,0,0,    0,0,0,0,0,0,0,0,  
        0,0,0,0,0,0,0,0,    0,0,0,0,0,0,0,0,  
        0,0,0,0,0,0,0,0,    1,0,0,0,1,0,1,1,  
        1,0,0,0,0,0,0,0,    1,0,1,1,1,0,1,1,  
        0,0,1,1,0,0,1,1,    0,0,0,1,0,0,1,1,  
        0,0,0,0,0,0,0,0,    0,0,0,1,0,0,1,1,  
        1,1,0,1,0,0,0,1,    0,0,0,0,0,0,0,0,  
        1,1,0,1,0,0,0,1,    1,1,0,0,1,0,0,0,  
        0,1,1,1,0,0,1,1,    0,0,0,1,0,0,1,1,  
        0,0,0,0,0,0,0,0,    0,0,0,0,0,1,1,1,  
        1,1,1,1,0,0,1,1,    1,1,0,0,1,1,0,0,  
        1,1,1,1,0,0,1,1,    1,1,0,0,1,1,0,0  
    };//索引表  

	Mat image;
    Mat copyImage;
    cvtColor(srcImage,image,CV_BGR2GRAY);
    threshold(image, copyImage, 128, 1, THRESH_BINARY);//這樣,像素點就變成0 1 //image = image * 255  顯示圖像 
   // cout<<endl<<endl<<format(copyImage,"python");
    //僅使用最外一層輪廓,不用作預處理,而且只有一層
	vector<Point> edg;
	vector<Point> detele;
	
	bool flag = true;
 	int times = 0;
 	int sum;
 	char vaule[8] = { 0 };
 	while( flag ) {
 		
	 	times++;
	 	flag = false;
	 	
		int number0=0;
	 	//記得以前使用一種函數,返回的是行號 注意像素點的表示(行號,列號)
		//若想以後正確使用,一開始就得按照規矩來
	 	for(int i=1;i<copyImage.rows-1;i++){
	 		for(int j=1;j<copyImage.cols-1;j++){
				int x=i,y=j;
				if( copyImage.at<char>(x,y) == 1 ){
				
				vaule[0] = copyImage.at<char>(x-1,y-1);
				vaule[1] = copyImage.at<char>(x-1,y);
				vaule[2] = copyImage.at<char>(x-1,y+1);
				vaule[3] = copyImage.at<char>(x,y+1);
				vaule[4] = copyImage.at<char>(x+1,y+1);
				vaule[5] = copyImage.at<char>(x+1,y);
				vaule[6] = copyImage.at<char>(x+1,y-1);
				vaule[7] = copyImage.at<char>(x,y-1);

					sum = vaule[0] & vaule[1] & vaule[2] & vaule[3] & vaule[4] & vaule[5] & vaule[6] & vaule[7];
				
					if(sum == 0) {
						edg.push_back(Point (x,y));
					}
				}
			 }
		 }
 
		 for(int i=0 ; i<edg.size() ; i++){
		 	
		 	int x,y;
			x = edg[i].x;
			y = edg[i].y;
		
			vaule[0] = copyImage.at<char>(x-1,y-1);
			vaule[1] = copyImage.at<char>(x-1,y);
			vaule[2] = copyImage.at<char>(x-1,y+1);
			vaule[3] = copyImage.at<char>(x,y+1);
			vaule[4] = copyImage.at<char>(x+1,y+1);
			vaule[5] = copyImage.at<char>(x+1,y);
			vaule[6] = copyImage.at<char>(x+1,y-1);
			vaule[7] = copyImage.at<char>(x,y-1);
		//因爲字符轉換int使得數值變成0了估計!!!!!!!!!!!!!	
			vaule[1]*=2;
			vaule[2]*=4;
			vaule[3]*=8;
			vaule[4]*=16;
			vaule[5]*=32;
			vaule[6]*=64;
			vaule[7]*=128;
			
			sum = vaule[0] + vaule[1] + vaule[2] + vaule[3] + vaule[4] + vaule[5] + vaule[6] + vaule[7] ;
		//若發現該點是可刪除點,即當即刪除.刪除會影響到之後的判斷,故先作標記
			if(deletemark[sum] == 1){
				detele.push_back(Point (x,y));//vertor的插入
		 	}

		}		
		if(detele.size() > 0)//vector的成員函數.size()
			flag = true;
		 	for(int i=0;i<detele.size();i++){
				 int x,y;
				 x=detele[i].x,y=detele[i].y;
				 copyImage.at<char>(x,y)=0;
			 }
		cout<<endl<<"time"<<times<<endl;
		detele.clear();
		edg.clear();
	}
	
	imshow("jieguo",copyImage*255);
}

/*2017-2-2*/

/*
hu矩
質量中心的簡稱,它同做用於質點繫上的力系無關。設?n個質點組成的質點系?,其各質點的質量分別爲m1,m2,…,mn。若用?r1?,r2,……,rn分別表示質點系中各質點相對某固定點的矢徑,rc?表示質心的矢徑,則有rc=(m1r1+m2r2+……+mnrn)/(m1+m2+……+mn)。當物體具備連續分佈的質量時,質心C的矢徑?rc=∫ρrdτ/∫ρdτ,式中ρ爲體(或面、線)密度;dτ爲至關於ρ的體(或面?、線)元?;積分在具備分佈密度ρ的整個物質體(或面、線)上進行。由牛頓運動定律或質點系的動量定理,可推導出質心運動定理:質心的運動和一個位於質心的質點的運動相同,

中心矩具備平移不變性,它與中心作差了
歸一化中心矩,應該具備縮放平移不變性
Hu矩具備平移,縮放,旋轉不變性,應該是綜合了好多矩的向量
中心矩是20 11 02開始,,由於00就是p+q 00 ;01 10中心矩不存在
*/

int main()
{
	char data[100]={0};
	for(int i=3;i<6;i++){
		for(int j=3;j<6;j++)
			data[10*i+j]=255;		
	}
	Mat srcImage= Mat(10, 10, CV_8U, data);
	Moments mts=moments(srcImage,2);//2是非零的意思,會將圖像中大於零的都認爲1
	//這應該是庫中的函數,能夠直接使用,計算各階矩(原點矩,中心矩)0,1,2
	double hu[7]; 
    HuMoments(mts, hu);//只須要接受各階矩,計算獲得hu矩,存入hu數組
	 
    for (int i=0; i<7; i++) 
    { 
        cout << log(abs(hu[i])) <<endl; 
    } 
}


/*2017-2-3*/
/*
resylt = matchShapes(contours[],contours [],1 ) 函數的使用方法,輸入比較的邊緣數組,比較方法1 2 三、 
返回值是個浮點數,顯示比較距離,越小越類似
其內部仍是先計算出兩個圖像的hu矩,而後經過一些數學方法計算兩個hu矩之間的差距				
*/
int main()
{
	Mat srcImage0=imread("E:/visio/dev/xin.JPG");
	Canny(srcImage0,srcImage0,100,250);
	//即便看似很規整,仍是直接檢測最外層輪廓,仍是會檢測到前一個後一個的關係,不是繼承 
	
	Mat srcImage1=imread("E:\\visio\\dev\\youxin.JPG");
	Canny(srcImage1,srcImage1,100,250);

	Mat lunkuo0=Mat::zeros(srcImage0.size(),CV_8U);  //繪製
	Mat lunkuo1=Mat::zeros(srcImage1.size(),CV_8U);  //繪製
	vector<Vec4i> hierarchy;  
	vector< vector<Point> > contours0;
	vector< vector<Point> > contours1;
	findContours(srcImage0,contours0,hierarchy,0,CV_CHAIN_APPROX_NONE);//沒有返回值 
	findContours(srcImage1,contours1,hierarchy,0,CV_CHAIN_APPROX_NONE);//沒有返回值 
	
	drawContours( lunkuo0, contours0, 0, 255, 1, 8 );
	drawContours( lunkuo1, contours1, 0, 255, 1, 8 );
	
	//經過上面的邊緣檢測以後,一幅圖才能尋找出一個邊緣。
	 
	imshow("lunkuo0",lunkuo0);
	imshow("lunkuo1",lunkuo1);
	
	double result;
	
	result=matchShapes(contours0[0],contours1[0],1,0);
	//比較方法的宏定義有三個,只是這裏居然輸入的是邊緣數組,而不是二值化圖像,1,2,3 
	//使用這種方法,比較結果不能提錢限定只能從總的比較結果中選取一個最小的 
	cout<<result<<endl;
	waitKey(0);
}

/*matchTempate()模版匹配到的使用*/
//計算一個二維矩陣中最大值最小值,以及他們的位置

minMaxLoc(	//取出矩陣中最大最小值  
    const CvArr* arr,//目標矩陣  
    double* min_val,//最小值  
    double* max_val,//最大值  
    CvPoint* min_loc = NULL,//最小值位置  
    CvPoint* max_loc = NULL,//最大值位置  
    const CvArr* mask = NULL//掩膜,以便作區域操做
);  

int main()
{
	Mat srcImage=imread("zong.jpg");
	Mat temp=imread("ling.jpg");
	
	int srcw=srcImage.rows,srch=srcImage.cols,tempw=temp.rows,temph=temp.rows;
	int resultw=srcw-tempw+1;//儲存匹配結果的矩陣,按照上述原理,應該的長度和寬度就是這樣
	int resulth=srch-temph+1;
	Mat result(resultw,resulth,CV_8U,Scalar::all(0));
	//結果矩陣,保存着匹配信息,估計以後須要可以對矩陣計算的相關函數 
	matchTemplate(srcImage,temp,result,1);
	//這個函數類型爲void,
	//使用一個與temp大小的框,遍歷原圖像,而後對比temple(對比方法6中) 
	//有6種比較計算方法,估計也是計算矩,不一樣的方法,result中值的大小意義不一樣

	double min,max;
	Point minpoint,maxpoint,rightpoint;
	minMaxLoc(result,&min,&max,&minpoint,&maxpoint,Mat()); 
	//查找矩陣中最大值最小值,及其餘們的位置 
	
	rightpoint=minpoint;//使用了第一種方法,最小值表示最類似 
	rectangle(srcImage,rightpoint,Point(rightpoint.x+tempw,rightpoint.y+temph),Scalar(0,0,255));
	//畫矩形函數,輸入圖像,座上,右下點,顏色(使用了構造函數,構造了一個每名的量)
	 
	imshow("jieguo",srcImage);
	waitKey(0);
}

//上面的版本只能實如今衆多圖像中匹配一個最類似的結果,並不能識別
//比模版大的類似對象(由匹配原理),後者,多個與模版大小相同(只能圈出一個最類似的,識別多個須要設計,視頻的最後一節)
//因爲這個方法並不能很好的實現刀閘的識別,因此,識別多個的項目就先放一放

/*2017-2-13*/
/*
仿照houghcircles的思想改寫的檢測圓形曲線,但結果彷佛並很差,發現大多說的圖像通過處理後
半徑很小的圓,每每峯值很大,這也學是由於半徑越小,其邊緣越能近似到同一個(半徑)圓心
半徑大的,卻能近似到幾個有那麼一點點差異的圓心,從而致使峯值分散,不能與半徑小的圓相比 
*/
int main()
{
	Mat src=imread(".//刀閘圖片//data.jpg");
	int radius=50;//定義半徑範圍 
	float interval=1;//定義角度範圍 
	
	Mat result;
	src.copyTo(result);
	
	cvtColor(src,src,CV_RGB2GRAY);
	GaussianBlur(src,src,Size(3,3),0);
	Canny(src,src,100,250);
	 
	imshow("src",src);
	//三維矩陣,下標爲各類圓(不一樣半徑時以各個像素爲圓心),值表明有多少像素點在它上面 
	vector<vector<vector<int> > > count(radius,vector<vector<int> >(src.rows,vector<int>(src.cols)));
	//只知道這樣建立不知道爲何?
	
	
	int x0,y0;
	for(int k=1;k<radius;k++){
	
		for(int i=0;i<src.rows;i++){
			for(int j=0;j<src.cols;j++){
				
				unsigned char color = src.at<uchar>(i,j);
				
				if(color > 0){//若是是前景點 
					for (int theta = 0; theta < (1 / interval) * 360; theta++){
						//計算圓心的方法也是獨特,就是圖中轉換後的圓(以點代圓)
						double t = ( (1 / interval) * theta * CV_PI ) / 180;
						x0 = (int)cvRound(j - k * cos(t));//對一個double型的數進行四捨五入
						y0 = (int)cvRound(i - k * sin(t));
						//計算圓心。k是半徑,這裏是根據r計算a,b(圓心),由於r有界可作外層循環。
						if (x0 < src.cols && x0 > 0 && y0 < src.rows && y0 > 0){
							count[k][y0][x0]++;
						}
					}
				}
			}
		}
	}
	int max = 0;
	int r = 0;
	int x = 0, y = 0;
	
	for(int k=1;k<50;k++){
		
		for(int i=0;i<src.rows;i++){
			for(int j=0;j<src.cols;j++){
			
				if (count[k][i][j] > max){
					max = count[k][i][j];
					x = j;
					y = i;
					r = k;
				}
				
			}
		}
	}

	cout << x << endl;
	cout << y << endl;
	cout << r << endl;
	cout<<"峯值"<<max<<endl;
	
	Point point;
	point.x = x;
	point.y = y;
	//畫圓
	circle(result, point, r, Scalar(0, 0, 255));
	
	imshow("yuan",result);
	waitKey(0); 
	return 0;
}

/*霍夫圓檢測函數*/ HoughCircles(src,circles,CV_HOUGH_GRADIENT,1,3,100,45,0,0);
	//8位圖,存儲變量,檢測方法,步長(肯定累加器的大小,越大,累加器空間越小)
	//圓心之間可合併的最大距離,canny檢測因子,判斷累加器閾值大小已肯定那些點是圓心
	//半徑的最小,最大
	//總之效果並很差用 
	vector<Vec3f> circles;

	HoughCircles(src,circles,CV_HOUGH_GRADIENT,1,3,100,45,0,0);
	
	for(int i=0;i<circles.size();i++){
		Point center(cvRound(circles[i][0]),cvRound(circles[i][1]));
		int radius = cvRound(circles[i][2]);
		//繪製圓心 
		circle(result,center,3,Scalar(0,0,255),-1,8,0);
		//繪製輪廓
		circle(result,center,radius,Scalar(155,50,255),3,8,0); 
		
	}
	cout<<circles.size()<<endl;
	
	
/*直線檢測*/

	Mat src=imread(".//刀閘圖片//01.jpg",1);//"./"此文件夾 
	
	Mat edg;
//霍夫直線檢測,能夠檢測出直線,,,,,轉換了參數空間
	Canny(src,edg,50,100); 
	imshow("edg",edg);
	vector<Vec4i> lines; 
	HoughLinesP(edg,lines,1,CV_PI/180,150,50,10);	
//輸入二值化圖像,存儲空間,(轉化後)半徑的步長,角度的步長,閾值(待定直線),
//最小直線閾值(小於該值,則不被認爲是一條直線),閾值(兩條直線間隙大於該值,則被認爲是兩條線段,不然是一條。) 
	for(int i=0;i<lines.size();i++){ //這種使用方法要學會 
		Vec4i l=lines[i];
		line(src,Point(l[0],l[i]),Point(l[2],l[3]),Scalar(0,0,255));
	}
	imshow("jieguo",src);
	
	
	
	
/*2017-2-15*/
/*Moravec角點檢測算法*/
//輸入二值化圖像,存儲角點座標指針,角點閾值(有計算方式肯定)
int getMoravec(Mat& src,Point* corners , float threshold)  
{  
    int winsize=5;//窗口的大小 即 5*5 win[5,5]  
    int halfwinsize=winsize/2;  
    Mat diffDst(src.size(),CV_32FC1,Scalar::all(0));  

    int conersCount=0;  
    int x,y;  
 
    for (y=halfwinsize ; y<src.rows-halfwinsize ; y++)//先y(行),每次移動一個像素
    {  
        for (x=halfwinsize;x<src.cols-halfwinsize; x++)//後x(列),從第一個浮動框的中點開始  
        {  
            float reaction[4],minVal;
  
            reaction[0]=0;  
            reaction[1]=0;  
            reaction[2]=0;    
            reaction[3]=0;//應該是記錄四個方向的差值  
          
            int i;  
//在咱們的算法中,(u,v)的取值是((1,0),(1,1),(0,1),(-1,1).//上半平面,每隔45度,取一個角
//固然,你本身能夠改爲(1,0),(1,1),(0,1),(-1,1),(-1,0),(-1,-1),(0,-1),(1,-1) 8種狀況
            //0  
            for (i=-halfwinsize;i<halfwinsize;i++)//-2 -1 0 -1  
            {//固然要加,要計算全部框內的差值平方和
			
                reaction[0]+= pow(src.at<uchar>(y,x+i)-src.at<uchar>(y,x+i+1),2);  
            }  
  
            //45  
            for (i=-halfwinsize;i<halfwinsize;i++)//-2 -1 0 -1  
            {  
                reaction[1]+= pow(src.at<uchar>(y+i,x+i)-src.at<uchar>(y+i+1,x+i+1),2);  
            }  
  
            //90  
            for (i=-halfwinsize;i<halfwinsize;i++)//-2 -1 0 -1  
            {  
                reaction[2]+= pow(src.at<uchar>(y+i,x)-src.at<uchar>(y+i+1,x),2);  
            }  
  
            //-45  
            for (i=-halfwinsize;i<halfwinsize;i++)//-2 -1 0 -1  
            {  
                reaction[3]+= pow(src.at<uchar>(y+i,x-i)-src.at<uchar>(x-i-1),2);  
            }  
  
            //-----------------------------  
            //取最小值  
          
            minVal=reaction[0];  
            minVal=reaction[1]<minVal?reaction[1]:minVal;  
            minVal=reaction[2]<minVal?reaction[2]:minVal;  
            minVal=reaction[3]<minVal?reaction[3]:minVal;  
  
			//將最小值保存在準備好的模版中,且與原圖對應像素
            diffDst.at<float>(y,x)=minVal;  
        }  
    }
  
	//獲取角點座標  判斷當前點的局部極大值!!! 對對 局部區域最大值
    for (y=halfwinsize;y<src.rows-halfwinsize;y+=halfwinsize){  
        for (x=halfwinsize;x<src.cols-halfwinsize;x+=halfwinsize){  
            
			float max=0;  
            int flag=0;  
            Point maxLoc;//保存最大值的位置
            maxLoc.x=-1;//初始化
            maxLoc.y=-1;
			//在局部區域裏面找最大值!
            for (int winy=-halfwinsize;winy<halfwinsize;winy++){  
                for (int winx=-halfwinsize;winx<halfwinsize;winx++){  
                    float value;
					
                    value= diffDst.at<float>(y+winy,x+winx);//取像素點的值
                    
					if (value>max){
                        max=value;
                        flag=1;//存在候選角點,還沒設置閾值
                        maxLoc.x=x+winx;  
                        maxLoc.y=y+winy;
                    }  
  
                }  
            }
  
            if (flag==1 && max>threshold){  
                corners[conersCount].x=maxLoc.x;  
                corners[conersCount].y=maxLoc.y;  
                conersCount++;  
            }  
  
        }  

    }
    return conersCount;  
}

/*2017-2-17*/
/*
.h文件,與相應的.cpp文件的使用
感受只能在項目文件中使用這種方法兩節兩個.cpp文件(主文件經過.h使用另外一個.cpp )
一、原理上並不要求這兩個文件(.h .cpp)同名,但爲了使用方便,一半設置爲同名
二、.cpp裏能夠只用各類函數,沒有主函數,由於在一個總體中只要又一個函數入口就好了
三、可是即便是非主的.cpp文件也須要他本身編譯經過所需的庫的頭文件引用
四、根據文本替代遠離的.h文件在主文件的位置也有講究,例如若.h文件中使用了Mat,
那麼他在主文件中的位置須在命名空間的後面,
否則,根據文本替代原理,編譯器不會識別.h文件中的陌生符號
*/


/*輸出字符到文本文件*/
#include <fstream>

	ofstream outfile("data.txt");//打開
	outfile<<"下標從小到大";
	for(int i=0;i<256;i++){
		outfile<<","<<(int)result[i];
	}
	outfile.close();關閉

	
/*可視化編程,滑動小框*/
for(int i=0;i<contours.size();i++){
		for(int j=0;j<contours[i].size();j++){
		
				int x,y;
				x=contours[i][j].x; 
				y=contours[i][j].y;
				int sum[2];
				
				//則以此點爲中心,考察一個框 
				Mat temp;
				src.copyTo(temp);
				circle(temp, Point(x,y),round,Scalar(255));
				imshow("temp",temp);
				waitKey(100);
		}
	}
	

//Point像素點座標訪問,X是橫向的座標軸是
//at(i,j),矩陣數據訪問,i是行號

	Point point(10,100);
	srcImage.at<uchar>(point.x,point.y)=255;//x,y==>行,列 
	cout<<point.x<<" "<<point.y<<endl;
	srcImage.at<uchar>(50,100)=255;//同上,先行後列 
		//這種用法很特殊,,彷佛本身作了轉換
	point.x=20;
	point.y=100;
	srcImage.at<uchar>(point)=255;//這樣使用x,y就表明  列,行了 
	
	Mat m=Mat::zeros(200,200,CV_8UC3);
	Point point(10,100);
	circle(m,point,1,Scalar(0,0,255));//使用point的數據,x列,y行 
	circle(m,Point(20,100),1,Scalar(0,0,255));//同上,x列,y行 
	cout<<point.x;//或者說對於Point來說,point.x就是cols 
	
	m.at<Vec3b>(10,100)[2]=255; //由於這裏(i,j)並非表明像素點的座標,而是cols號 
	
	
	imshow("jieguo",m);
	
	
//多邊形逼近
   
	Mat lunkuo=Mat::zeros(srcImage.size(),CV_8UC3);  //繪製 
	vector<Vec4i> hierarchy;  
	vector< vector<Point> > contours;

	findContours(srcImage,contours,hierarchy,0,CV_CHAIN_APPROX_NONE);//沒有返回值 
	vector<vector<Point> > approxPoint(contours.size()); 
	 
    for (int i = 0; i < (int)contours.size(); i++){  
        approxPolyDP(contours[i], approxPoint[i], 3, true);  
    }  
  
	for(int i=0;i<approxPoint.size();i++){
        drawContours(lunkuo, approxPoint, i, Scalar(255, 255, 255), 1);
    }
    imshow("black",lunkuo);
	
//角度計算
double=atan(y/x);
//計算在不在圓裏面,是帶入公式
{x1-x}^2+{y1-y}^2==r



/*2017-2-18*/
/*卷積*/
//有的圖像處理方法是把象素的顏色(灰度)值變換爲周圍圖像顏色(灰度)值的調和(周圍象素顏色(灰度)值乘以一個權重值求和,效果會使得圖像效果變得朦朧),這個過程也符合卷積的物理意義(一組值乘以他們相應的「權重」係數的和),因此這個處理也被稱爲卷積。


/*2017-2-19*/
/*
一、關於h文件的引用,沒主函數的cpp文件也須要引入相關的系統庫,才能經過編譯
or*///將全部須要的引入庫都寫在這裏h文件中是能夠的,,但,,  
//不將全部的庫都寫在這裏的緣由是,
//並不知道那個函數所須要引入那個庫,
//倒不如,每一個函數的庫,他本身負責引入  
//這裏這樣寫只是證實這樣寫是能夠的,並不建議這樣寫!

/**.h文件*/
#include <iostream>  
#include <string>  
#include <list>  
#include <vector>  
#include <map>  
#include <stack>
#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

Scalar icvprGetRandomColor();
void icvprCcaByTwoPass(const Mat& _binImg, Mat& _lableImg);
void icvprCcaBySeedFill(const Mat& _binImg, Mat& _lableImg);
void icvprLabelColor(const Mat& _labelImg, Mat& _colorLabelImg);

/*
二、防止h文件引用本身
*/

/*2017-2-20*/
//goodFeatureToTrack()函數

/*
一、//eig是最小特徵值矩陣,並非二值化矩陣,對其膨脹效果不一樣
//默認用3*3的核膨脹,膨脹以後,除了局部最大值點和原來相同,其它非局部最大值點被 
//3*3鄰域內的最大值點取代,如不理解,可看一下灰度圖像的膨脹原理
dilate( eig, tmp, Mat() );

二、Size imgsize = image.size(); //?還有這個類型?!

三、vector<const float*> tmpCorners;  //這裏使用指針,是要訪問他在內存中的真正地址,?指向浮點數的地址?

四、//size_t類型  
//而數組下標的正確類型則是size_t,是標準C庫中定義的一種類型,應爲unsigned int
size_t i, j

五、eig.data
返回eig內存塊的首地址?還有eig.data這樣的使用法? 
角點在原圖像中的行?eig.step也許是一行的大小吧? 
*/
oid cv::goodFeaturesToTrack(InputArray _image, 
							OutputArray _corners,  
                            int maxCorners, 
							double qualityLevel, 
							double minDistance,  
                            InputArray _mask, 
							int blockSize,  
                            bool useHarrisDetector, 
							double harrisK 
							)  
{
    //若是須要對_image全圖操做,則給_mask傳入cv::Mat(),不然傳入感興趣區域  
    Mat image = _image.getMat(), mask = _mask.getMat();    
  
    CV_Assert( qualityLevel > 0 && minDistance >= 0 && maxCorners >= 0 );  //對參數有一些基本要求  
    CV_Assert( mask.empty() || (mask.type() == CV_8UC1 && mask.size() == image.size()) );  
  
    Mat eig, tmp;   //eig存儲每一個像素協方差矩陣的最小特徵值,tmp用來保存經膨脹後的eig
					//?協方差矩陣 大概就是能夠表徵角的特色的一個矩陣吧?
					//?注意計算完以後,eig就變成float類型的了?					
    if( useHarrisDetector )  
        cornerHarris( image, eig, blockSize, 3, harrisK ); //blockSize是計算2*2協方差矩陣的窗口大小,sobel算子窗口爲3,harrisK是計算Harris角點時須要的值  
    else
        cornerMinEigenVal( image, eig, blockSize, 3 );  //計算每一個像素對應的協方差矩陣的最小特徵值,保存在eig中  
  
    double maxVal = 0;  
    minMaxLoc( eig, 0, &maxVal, 0, 0, mask );   //只有一個最大值(最小值)沒保存,maxVal保存了eig的最大值  
    threshold( eig, eig, maxVal*qualityLevel, 0, THRESH_TOZERO );  
	//閾值設置爲  maxVal乘以qualityLevel(圖像質量水平),
	//大於此閾值的保持不變,小於此閾值的都設爲0   

	//eig是最小特徵值矩陣,並非二值化矩陣,對其膨脹效果不一樣
	//默認用3*3的核膨脹,膨脹以後,除了局部最大值點和原來相同,其它非局部最大值點被 
	//3*3鄰域內的最大值點取代,如不理解,可看一下灰度圖像的膨脹原理
    dilate( eig, tmp, Mat() );  //tmp中保存了膨脹以後的eig,?保存膨脹以後的幹什麼?
  
    Size imgsize = image.size(); //?還有這個類型?!

    vector<const float*> tmpCorners;  //存放粗選出的角點地址,?指向浮點數的地址?
	//這裏使用指針,是要訪問他在內存中的真正地址
   
    for( int y = 1; y < imgsize.height - 1; y++ )//從第二行開始,到倒數第二行  
    {  
        const float* eig_data = (const float*)eig.ptr(y);  //得到eig第y行的首地址 
        const float* tmp_data = (const float*)tmp.ptr(y);  //得到tmp第y行的首地址  
        const uchar* mask_data = mask.data ? mask.ptr(y) : 0;  

        for( int x = 1; x < imgsize.width - 1; x++ ){  
            
			float val = eig_data[x];  
            
			if( val != 0 && val == tmp_data[x] && (!mask_data || mask_data[x]) )  
				//val == tmp_data[x]說明這是局部極大值
                tmpCorners.push_back(eig_data + x);  
				//保存其位置 		?eig_data已是y行首地址了? 
        } 
    }  
  
    //-----------此分割線以上是根據特徵值粗選出的角點,咱們稱之爲弱角點----------//  
  //----------此分割線如下還要根據minDistance進一步篩選角點,仍然能存活下來的咱們稱之爲強角點----------//  
	//tmpCorners,數組  保存弱角點的 內存像素地址
    sort( tmpCorners, greaterThanPtr<float>() );  //按特徵值降序排列,注意這一步很重要,後面的不少編程思路都是創建在這個降序排列的基礎上 
  
	vector<Point2f> corners;
	
	//size_t類型  
	//而數組下標的正確類型則是size_t,是標準C庫中定義的一種類型,應爲unsigned int
    size_t i, j, total = tmpCorners.size(), ncorners = 0;

    //下面的程序有點稍微難理解,須要本身仔細想一想
	//minDistance是傳入參數	
    if(minDistance >= 1){  
        int w = image.cols;  
        int h = image.rows;  
  
        const int cell_size = cvRound(minDistance);   //向最近的整數取整  

    /*	這裏根據cell_size構建了一個矩形窗口grid(雖然下面的grid定義的是vector<vector>,而並非咱們這裏說的矩形窗口,但爲了便於理解,仍是將grid想象成一個   grid_width*grid_height 的矩形窗口比較好),
	
	除以cell_size說明grid窗口裏相差一個像素至關於_image裏相差minDistance個像素,至於爲何加上cell_size - 1後面會講
	*/
        //w,h是整個圖像的,因此grid_width的大小也是對於整個圖像的
		const int grid_width = (w + cell_size - 1) / cell_size;   
        const int grid_height = (h + cell_size - 1) / cell_size;  
		
		//vector裏面是vector,grid用來保存得到的強角點座標,?注意grid中保存的是座標,但爲何是Point2f?
        std::vector<std::vector<Point2f> > grid(grid_width*grid_height);
		
        minDistance *= minDistance;//平方,方面後面計算,省的開根號  
  
        for( i = 0; i < total; i++ ) // 剛剛粗選的弱角點,都要到這裏來接收新一輪的考驗  
        {  
            int ofs = (int)( (const uchar*)tmpCorners[i] - eig.data );  //tmpCorners中保存了角點的地址,eig.data返回eig內存塊的首地址?還有eig.data這樣的使用法? 
			
            int y = (int)(ofs / eig.step);   //角點在原圖像中的行?eig.step也許是一行的大小吧?  
            int x = (int)((ofs - y*eig.step)/sizeof(float));  //在原圖像中的列  
  
            bool good = true;//先認爲當前角點就是強角點  
  
            int x_cell = x / cell_size;//x_cell,y_cell是角點(y,x)在grid中的對應座標  
            int y_cell = y / cell_size;//所有圖像分紅若干個 grid,,這個x_cell,y_cell處於的grid的座標  
			
			//如今知道爲何前面grid_width定義時要加上cell_size - 1了吧,這是爲了使得(y,x)在grid中的4鄰域像素都存在,也就是說(y_cell,x_cell)不會成爲邊界像素 // (y_cell,x_cell)的4鄰域像素  
            int x1 = x_cell - 1;  
            int y1 = y_cell - 1;  
            int x2 = x_cell + 1;    
            int y2 = y_cell + 1;  
  
            // boundary check,再次確認x1,y1,x2或y2不會超出grid邊界  
            x1 = std::max(0, x1);  //比較0和x1的大小  
            y1 = std::max(0, y1);  
            x2 = std::min(grid_width-1, x2);  
            y2 = std::min(grid_height-1, y2);  
  
            //記住grid中相差一個像素,至關於_image中相差了minDistance個像素  
            for( int yy = y1; yy <= y2; yy++ ){ // 行  
                for( int xx = x1; xx <= x2; xx++ ){  //列  
                  
                    vector <Point2f> &m = grid[yy*grid_width + xx];  //grid中元素的是Point2f引用  
					
					//若是(y_cell,x_cell)的4鄰域像素,
					//也就是(y,x)的minDistance鄰域像素中已有被保留的強角點
					
                    if( m.size() ){//m指向一個座標點                
                        for(j = 0; j < m.size(); j++){   //當前角點周圍的強角點都拉出來跟當前角點比一比  
                         
                            float dx = x - m[j].x;  
                            float dy = y - m[j].y;  
               //注意若是(y,x)的minDistance鄰域像素中已有被保留的強角點,則說明該強角點是在(y,x)以前就被測試過的,又由於tmpCorners中已按照特徵值降序排列(特徵值越大說明角點越好),這說明先測試的必定是更好的角點,也就是已保存的強角點必定好於當前角點,因此這裏只要比較距離,若是距離知足條件,能夠立馬扔掉當前測試的角點
			   
			   //也就是在必定範圍內,只保留一個角點,就是強角點,只不過這裏用的轉變思想很好啊
                            if( dx*dx + dy*dy < minDistance ){ 
								good = false;  
                                goto break_out;  
                            }  
                        }  
                    }  
                }   // 列  
            }    //行  
  
            break_out:  
  
            if(good)  
            {  
                // printf("%d: %d %d -> %d %d, %d, %d -- %d %d %d %d, %d %d, c=%d\n",  
                //    i,x, y, x_cell, y_cell, (int)minDistance, cell_size,x1,y1,x2,y2, grid_width,grid_height,c); 
				
                grid[y_cell*grid_width + x_cell].push_back(Point2f((float)x, (float)y));  
				//再從grid中轉變會原來圖像中的座標點
				
                corners.push_back(Point2f((float)x, (float)y));  
                ++ncorners;  
  
                if( maxCorners > 0 && (int)ncorners == maxCorners )  //因爲前面已按降序排列,當ncorners超過maxCorners的時候跳出循環直接忽略tmpCorners中剩下的角點,反正剩下的角點愈來愈弱  
                
				break;  
            }  
        }  
    }  
    else    //除了像素自己,沒有哪一個鄰域像素能與當前像素知足minDistance < 1,所以直接保存粗選的角點  
    {  
        for( i = 0; i < total; i++ )  
        {  
            int ofs = (int)((const uchar*)tmpCorners[i] - eig.data);  
            int y = (int)(ofs / eig.step);   //粗選的角點在原圖像中的行  
            int x = (int)((ofs - y*eig.step)/sizeof(float));  //在圖像中的列  
  
            corners.push_back(Point2f((float)x, (float)y));  
            ++ncorners;  
            if( maxCorners > 0 && (int)ncorners == maxCorners )    
                break;  
        }  
    }  
  
    Mat(corners).convertTo(_corners, _corners.fixedType() ? _corners.type() : CV_32F);  

}  



/*
使用Harris()函數找角點

一、仍是使用輪庫圖查找效果明顯一點,只是爲何平滑區域,檢測出來的值這麼大
二、首先使用normlize()函數,將float的矩陣歸一化到0-255 float(),
	convertScaleAbs在轉化到CV8U,減小了以後的計算量
三、根據賦值 = -數 的原理想  +=纔是另外一種 
*/


#include "harris2.h"

/*
對輸入的圖像使用Harris檢測,src
以後對於設置的局部框進行抑制,thresh
減小了連續角點的出現
*/ 
void cornerHarris_demo( Mat& src,int size, int thresh)  
{  
  Mat dst, dst_norm;  
  dst = Mat::zeros( src.size(), CV_32FC1 );  
  
  //harris函數的參數設置 
  int blockSize = 3;  
  int apertureSize = 3;  
  double k = 0.04;  
  
  /// Detecting corners  
  cornerHarris( src, dst, blockSize, apertureSize, k, BORDER_DEFAULT );  
  
  ///這一步僅僅是爲了好讓其可以轉換成到CV8U  
  normalize( dst, dst_norm, 0, 255, NORM_MINMAX, CV_32FC1, Mat() );
	//歸一化函數,結果還是float型    
	convertScaleAbs(dst_norm,dst_norm,1,0); 
	
	imshow("dst_norm",dst_norm);
	
	
	Mat show=Mat::zeros(src.size(),CV_8UC3);
	vector<vector<Point> > contours;
	vector<Vec4i> hierarchy;
	findContours(src, contours, hierarchy, 0, CV_CHAIN_APPROX_NONE);	
	drawContours(show, contours, -1, Scalar(255,255,255), 1, 8, hierarchy);
  
 
//根據Harris函數計算獲得的矩陣,進行閾值判斷 
//	for( int j = 0; j < dst_norm.rows ; j++ ){ 
//		for( int i = 0; i < dst_norm.cols; i++ ){
//            if( (int) dst_norm.at<float>(j,i) > thresh ){  
//               circle( show, Point( i, j ), 1,  Scalar(0,0,255));  
//            }  
//        }  
//	}


	//另外一個版本的閾值抑制 
	//(20*20)的窗口 
	//設定局部抑制時的窗口,也就是21的窗口有一個極大值點而且設定,變相的減小連續點 
	//同時進行閾值抑制 
	for( int i = size ; i < dst_norm.rows-size ; i+=size ){ 
		for( int j = size ; j < dst_norm.cols-size ; j+=size ){
            int max=0;
            Point point;
            
			for(int u = -size;u<size;u++){//根據賦值 = -數 的原理想  +=纔是另外一種 
            	for(int v =-size;v<size;v++){
            		
					if(max < dst_norm.at<uchar>(i+u,j+v)){
            			max = dst_norm.at<uchar>(i+u,j+v);
            			point.y = i+u;
            			point.x = j+v;
            			
					}	
				}
			}
			if(max > thresh) circle( show, point, 1,  Scalar(0,0,255) );  
        }
	}
	
  //畫出角點  
	imshow( "result", show );  
}  

/*2017-3-17*/

//加一個括號 初始化爲零
bufferGray2= new uchar[m_width*m_height]();

/*2017-3-28*/
/*CvTermCriteria  迭代算法的終止準則  */
#define CV_TERMCRIT_ITER    1  
#define CV_TERMCRIT_NUMBER  CV_TERMCRIT_ITER  
#define CV_TERMCRIT_EPS     2  
  
typedef struct CvTermCriteria  
 {  
  int    type;  /* CV_TERMCRIT_ITER 和CV_TERMCRIT_EPS二值之一,或者兩者的組合 */  
  int    max_iter; /* 最大迭代次數 */  
  double epsilon; /* 結果的精確性 */  
 }
 
 //得儘快將opencv 的矩陣的使用方法熟悉
 	//一、指定隨機數種子
	RNG rng(100);
	rng.fill
	//二、從整個數據集中取出前[0,89]行
	//注:*Range的範圍是[a,b)
	Mat trainClass = trainData.rowRange(0,nLinearSamples);
	//取出第一列
	Mat c = trainClass.colRange(0,1);
	
	
	
	
//2017-4-6
//使用canny算子,在查找輪廓,會形成輪廓數據混亂,每一個輪廓會走兩遍,而且有差異 
Canny(srcImage,srcImage,100,250);
	
    
    
//2017-12-12
積分直方圖:http://blog.csdn.net/linear_luo/article/details/52725358
梯度直方圖:https://www.leiphone.com/news/201708/ZKsGd2JRKr766wEd.html
相關文章
相關標籤/搜索