OpenCV中角點未檢測到原因與FindChessboardCorners函數

本博客參考兩位前輩的實驗記錄角點檢測與FindChessboardCorners函數 和 OpenCV學習筆記(33)棋盤格角點檢測練習程序,總結整理而成。

實驗歷程:

我在前幾天的實驗中,總是檢測不到角點,很鬱悶。來來回回測了七八組數據,都沒有第一次測量的那種效果。因爲標定板的原因,要貼掉一部分的標定板纔可以使用。第一次做的實驗圖片有點暗,所以想把圖片再重新拍一下,就隨便貼了一下,這一隨便拍就出現問題了,導致角點提取不出來,然後又以爲是曝光問題,圖片太暗了,導致圖片角點提取不出來,又去調整曝光,拍了幾組照片還是找不到角點,後來感覺是透明膠帶的問題,改用紙膠帶,用紙膠帶可以去除透明膠帶的一些問題,比如透明膠帶放時間長了,拉出來透明膠帶邊緣有些黑邊,也會影響後面的角點提取,用新的透明膠帶,好好貼,應該也沒啥問題。紙透明一點不會影響角點的提取,只要被紙覆蓋住了,基本就不會被檢測到角點。下面是我實驗中因爲膠帶的原因檢測不到的角點實驗結果輸出圖:

透明膠帶貼到內角點上,影響角點的提取

結合上面實驗闡述——

反思實驗拍照和貼紙注意事項:

  • 如果因爲學校的標定板,不適用OpenCV算法,就需要貼掉一部分來使用,畢竟買一塊新的精度高點的標定板代價還是很大的,能用學校已經有的,儘量利用已經有的資源。
  • pattern_size參數傳遞內點數,內點是黑色方塊相互連通的位置。爲了便於辨識方向,每行每列對應的角點數不能相同 。
  • 要學會將能提取出來角點在圖片上顯示出來,這樣有利於找到原因,而不是去盲目的去猜測原因是啥,在這要特別感謝OpenCV學習筆記(33)棋盤格角點檢測練習程序這位博主的博客。
  • 在拍攝圖片的時候應注意減少干擾,例如燈光、背景、自然光等。
  • 如果需要貼紙的話,可以選擇紙膠帶減少反光。
  • 如果不需要貼紙,在將打印的棋盤格貼在平整的板子上時,透明膠帶不要貼到內角點上,不然可能影響到角點檢測,如上圖中我提取不到完整的角點以及下面的原圖與運行結果圖中的圖2。
  • 提取不到角點,和貼紙的厚度沒啥關係。正常的A4紙放上去,就算能看到裏面的格子的影子,但它格子的邊緣,你可以試試苗一下,根本苗不清楚的,所以FindChessboardCorners函數應該也會忽略它,我猜是這樣的。哈哈哈。你也可以這樣想,普通的透明膠帶都可以影響它提取角點,那可是透明的呀,更何況紙都把角點覆蓋住了,看的非常模糊了。所以貼上的紙不會因爲角點行數和列數不對的原因影響角點提取。

目的:

在研究座標映射的相關問題時,遇到棋盤座標匹配出錯的問題。其中涉及到一個關鍵函數FindChessboardCorners。以下將對其做一定的介紹和分析。

函數介紹:

FindChessboardCorners是opencv的一個函數,可以用來尋找棋盤圖的內角點位置。

 

函數形式

int cvFindChessboardCorners( const void* image, CvSize pattern_size, CvPoint2D32f* corners, int* corner_count = NULL, int flags = CV_CALIB_CB_ADAPTIVE_THRESH );

參數說明

  • Image:     輸入的棋盤圖,必須是8位的灰度或者彩色圖像。
  • pattern_size:    棋盤圖中每行和每列角點的個數。
  • Corners:     檢測到的角點
  • corner_count:     輸出,角點的個數。如果不是NULL,函數將檢測到的角點的個數存儲於此變量。
  • Flags:    各種操作標誌,可以是0或者下面值的組合:
    • CV_CALIB_CB_ADAPTIVE_THRESH - 使用自適應閾值(通過平均圖像亮度計算得到)將圖像轉換爲黑白圖,而不是一個固定的閾值。
    • CV_CALIB_CB_NORMALIZE_IMAGE - 在利用固定閾值或者自適應的閾值進行二值化之前,先使用cvNormalizeHist來均衡化圖像亮度。
    • CV_CALIB_CB_FILTER_QUADS - 使用其他的準則(如輪廓面積,周長,方形形狀)來去除在輪廓檢測階段檢測到的錯誤方塊。

補充說明

函數cvFindChessboardCorners試圖確定輸入圖像是否是棋盤模式,並確定角點的位置。如果所有角點都被檢測到且它們都被以一定順序排布,函數返回非零值,否則在函數不能發現所有角點或者記錄它們地情況下,函數返回0。例如一個正常地棋盤圖右8x8個方塊和7x7個內角點,內角點是黑色方塊相互聯通的位置。這個函數檢測到地座標只是一個大約的值,如果要精確確定它們的位置,可以使用函數cvFindCornerSubPix。
 

函數測試:

測試圖像(左)和運行結果(右)

圖像均爲640*360的8*8黑白格棋盤圖,7*7個內點。

  • 圖1.計算機圖像,成功檢測出所有49個角點,順序以行從左上到右下
  • 圖2.正面實拍圖像,檢測出48個角點,其中正確47個,錯誤一個,沒有標記順序,只標記位置
  • 圖3.正面實拍圖像,成功檢測出所有49個角點,順序以行從左上到右下
  • 圖4.側面實拍圖像,成功檢測出所有49個角點,順序以列從右上到左下
     

結果分析:

  • 1圖與3圖,角特性良好,正面拍攝,函數順利找到角點位置
  • 2圖中,未檢測出的右上角兩個角點可能是由於膠帶干擾,角特徵變的不明顯。檢測到的錯誤點是因爲背景圖像中有黑色物體,導致計算機誤認爲其爲黑色方格。
  • 4圖中,由於拍攝角度傾斜,棋盤圖像發生變形,角點查找順序發生變化。可以通過重新排列矩陣Corners的大小來得到1圖與3圖同樣的效果

反思與函數應用注意事項:

  • pattern_size參數傳遞內點數,8*8的棋盤只有7*7內點。
  • 圖像選取應注意減少干擾,例如光照與背景等。
  • Corners中的角點座標順序排列規律不一定是以行從左上到右下。使用座標計算映射關係時應提高警惕,對座標進行重新排列。

 

運行環境:win7 + VS2010 + OpenCV2.4.9

我是在我相機標定程序裏面直接修改的,借鑑一些下面的代碼和想法進行需要的修改。你們也可以根據需要進行相應的修改。

#include "opencv2/opencv.hpp"
 
#define m 9
#define n 6
 
using namespace std;
using namespace cv;
 
void main()
{
	Mat srcimage;
	Mat grayimage;
	vector<Point2f> corners;
	Size PatSize;
 
	PatSize.width = m;
	PatSize.height = n;
 
	srcimage = imread("a111.bmp");
	bool ret=findChessboardCorners(srcimage, PatSize, corners);
	//Mat viewGray;
	//cvtColor(srcimage, viewGray, COLOR_BGR2GRAY);
	//cornerSubPix(viewGray, corners, Size(11, 11),
	//	Size(-1, -1), TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 30, 0.1));
	drawChessboardCorners(srcimage, PatSize, Mat(corners), ret);
	namedWindow("chessboard corners");
	imshow("chessboard corners", srcimage);
 
	waitKey(0);
}

運行結果:

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章