攝像頭校正 camera calibration - part3 OpenCV programming
在前兩篇文章 camera calibration -part1 camera model 以及 camera calibration -part2 camera calibration 中介紹了 camera 內部參數(intrinsic parameter) , 形變參數 (distortion parameter) 以及校正的方法和原理, 本文說明如何使用 OpenCV 實作camera校正 程序.
校正的程序分為兩部分;
(1)影像的擷取,
(2)讀取步驟 (1) 擷取的影像序列, 進行校正.
第 (1) 部分的功能是影像擷取以及存檔, 儲存的影像序列供步驟 (2) 使用, 這部分的程式代碼比較簡單:
代碼 86~95, 當擺放好 校正板後, 按下 S 鍵, 就可以存檔. 檔名固定為 SAVE_IMGXXX.bmp
如圖一所式 為筆者測試用的影像序列:
擺放的訣竅在於儘量放置在畫面的邊緣, 並且包含不同的深度. 基本上需要 15~20 張有效的影像.
第二部分的程式代碼如下:
54~60 行定義校正 pattern 角點的 3D coordinate.
62 行的 while loop 將影像序列 一張一張的讀入, 每讀入一張, 就以 77 以及 80 行的代碼進行角點提取. 87 行判斷是否正常提取到校正 pattern 上的所有48 個角點, 若是, 則將這些角點在影像上的座標儲存起來. 代碼 93 行則是將其取到的角點加以標示. 當所有的影像都完成角點提取, 則 108 行使用 calibrationCamera 進行攝像頭校正.
在這裡, 我們感興趣的是 camera 內部參數以及型變參數, calibrationCamera 會為我們計算這些參數並分別儲存在 cameraMatrix 以及 distCoeffs.
116~118 行, 我將 cameraMatrix以及 distCoeffs 的內容儲存到 test.yml 檔案.
圖二是其中一張影像的角點提取結果:
校正出的內參以及型變參數如下:
%YAML:1.0
intrinsic: !!opencv-matrix
rows: 3
cols: 3
dt: d
data: [ 7.2042901435965223e+002, 0., 3.2967552840264563e+002, 0.,
7.1972210146332782e+002, 2.6487944722387311e+002, 0., 0., 1. ]
distcoeff: !!opencv-matrix
rows: 1
cols: 5
dt: d
data: [ 1.0477467445014127e-001, -1.1727926119997072e+000,
3.4074683728567670e-003, 4.3480547323742199e-003,
2.2097821427154618e+000 ]
fx = 7.2042901435965223e+002
fy = 7.1972210146332782e+002
cx = 3.2967552840264563e+002
cy = 2.6487944722387311e+002
k1 = 1.0477467445014127e-001
k2 = -1.1727926119997072e+000
p1 = 3.4074683728567670e-003
p2 = 4.3480547323742199e-003
k3 = 2.2097821427154618e+000
校正的程序分為兩部分;
(1)影像的擷取,
(2)讀取步驟 (1) 擷取的影像序列, 進行校正.
第 (1) 部分的功能是影像擷取以及存檔, 儲存的影像序列供步驟 (2) 使用, 這部分的程式代碼比較簡單:
01 #include <stdio.h> 02 #include <iostream> 03 #include <vector> 04 #include "StdAfx.h" 05 #include "CameraDS.h" 06 07 #include <cv.h> 08 #include <highgui.h> 09 #include "opencv2/opencv.hpp" 10 11 12 using namespace cv; 13 using namespace std; 14 15 16 #define CAP_WIDTH 640 17 #define CAP_HEIGHT 480 18 int main() 19 { 20 cv::Mat img; 21 IplImage* capimg; 22 int DeviceCamCount = 0; 23 CCameraDS *pCamDS = NULL; 24 25 int CamCount = 0; 26 int CamIndex[10]; 27 28 pCamDS = new CCameraDS(); 29 DeviceCamCount = pCamDS->CameraCount(); 30 if ( DeviceCamCount == 0 ) 31 { 32 printf( "No Camera detected....\n" ); 33 exit(0); 34 } 35 36 for (int i = 0, j = 0; i < DeviceCamCount; i++) 37 { 38 char szCamName[1024]; 39 40 int retval = pCamDS->CameraName(i, szCamName, sizeof(szCamName)); 41 42 if (retval >0) 43 { 44 printf("Camera #%d's Name is '%s'.\n", i, szCamName); 45 if ( !strcmp( szCamName, "USB µø°T¸Ë¸m" ) ) 46 { 47 CamIndex[ j++ ] = i; 48 CamCount++; 49 } 50 } 51 else 52 { 53 printf("Can not get Camera #%d's name.\n", i); 54 } 55 } 56 57 if ( pCamDS->OpenCamera( CamIndex[0], false, 58 CAP_WIDTH, CAP_HEIGHT ) == false ) 59 { 60 printf( "USB Camera 0 do not support w=%d:h=%d\n", 61 CAP_WIDTH, CAP_HEIGHT ); 62 return (-1); 63 } 64 65 int loop = 1; 66 int key; 67 int file_idx = 0; 68 char filename[256]; 69 char fileidx[10]; 70 71 while ( loop ) 72 { 73 //camera >> img; 74 capimg=pCamDS->QueryFrame(); 75 img = capimg; 76 if (img.empty()) 77 { 78 std::cerr << "ERROR: Could not capture image" << std::endl; 79 } 80 imshow("image", img); 81 key = cvWaitKey( 5 ); 82 if ( key == 27 ) 83 { 84 loop = 0; 85 } 86 else if (key =='s' || key=='S' ) 87 { 88 sprintf( fileidx, "%03d", file_idx++ ); 89 strcpy( filename, "SAVE_IMG" ); 90 strcat( filename, fileidx ); 91 strcat( filename, ".bmp" ); 92 93 imwrite( filename, img ); 94 printf("Image file %s saved.\n", filename); 95 } 96 else if (key =='r' || key=='R' ) 97 { 98 file_idx = 0; 99 } 100 } 101 //camera.close(); 102 } 103
代碼 86~95, 當擺放好 校正板後, 按下 S 鍵, 就可以存檔. 檔名固定為 SAVE_IMGXXX.bmp
如圖一所式 為筆者測試用的影像序列:
圖一 校正用影像序列 |
第二部分的程式代碼如下:
01 #include <stdio.h> 02 #include <iostream> 03 #include <vector> 04 #include "StdAfx.h" 05 #include "CameraDS.h" 06 07 #include <cv.h> 08 #include <highgui.h> 09 #include "opencv2/opencv.hpp" 10 11 12 using namespace cv; 13 using namespace std; 14 15 16 #define CAP_WIDTH 640 17 #define CAP_HEIGHT 480 18 19 std::vector<std::vector<cv::Point3f>> objectPoints; 20 std::vector<std::vector<cv::Point2f>> imagePoints; 21 22 cv::Mat cameraMatrix; 23 cv::Mat distCoeffs; 24 25 cv::Mat map1,map2; 26 27 int main() 28 { 29 cv::Mat img; 30 cv::Mat img2; 31 IplImage* capimg; 32 int DeviceCamCount = 0; 33 CCameraDS *pCamDS = NULL; 34 35 int CamCount = 0; 36 int CamIndex[10]; 37 38 pCamDS = new CCameraDS(); 39 DeviceCamCount = pCamDS->CameraCount(); 40 41 int loop = 1; 42 int key; 43 int file_idx = 0; 44 char filename[256]; 45 char fileidx[10]; 46 47 int i; 48 cv::Size boardSize( 8, 6 ); 49 cv::Size imageSize(CAP_WIDTH, CAP_HEIGHT); 50 std::vector<cv::Point2f> imageCorners; 51 std::vector<cv::Point3f> objectCorners; 52 53 // The corners are at 3D location (X,Y,Z)= (i,j,0) 54 for (int i=0; i<boardSize.height; i++) 55 { 56 for (int j=0; j<boardSize.width; j++) 57 { 58 objectCorners.push_back(cv::Point3f(i, j, 0.0f)); 59 } 60 } 61 62 while ( loop ) 63 { 64 // find file: 65 sprintf( fileidx, "%03d", file_idx++ ); 66 strcpy( filename, "SAVE_IMG" ); 67 strcat( filename, fileidx ); 68 strcat( filename, ".bmp" ); 69 70 printf("IMG = %s\n", filename); 71 72 img = imread( filename, 0 ); 73 if ( img.empty()) 74 loop = 0; 75 else 76 { 77 bool found = cv::findChessboardCorners( 78 img, boardSize, imageCorners); 79 80 cornerSubPix(img, imageCorners, 81 cv::Size(5,5), 82 cv::Size(-1,-1), 83 cv::TermCriteria(cv::TermCriteria::MAX_ITER + 84 cv::TermCriteria::EPS, 85 30, // max number of iterations 86 0.1)); // min accuracy 87 if (imageCorners.size() == boardSize.area()) 88 { 89 imagePoints.push_back(imageCorners); 90 objectPoints.push_back(objectCorners); 91 } 92 img.copyTo( img2 ); 93 drawChessboardCorners(img2, boardSize, imageCorners, found); 94 95 imshow( "image", img2 ); 96 97 key = cvWaitKey(400); 98 //key = cvWaitKey( 5 ); 99 if ( key == 27 ) 100 { 101 loop = 0; 102 } 103 } 104 } 105 106 std::vector<cv::Mat> rvecs, tvecs; 107 // start calibration 108 calibrateCamera(objectPoints, // the 3D points 109 imagePoints, // the image points 110 imageSize, // image size 111 cameraMatrix,// output camera matrix 112 distCoeffs, // output distortion matrix 113 rvecs, tvecs,// Rs, Ts 114 0); // set options 115 116 FileStorage fs("test.yml", FileStorage::WRITE); 117 fs << "intrinsic" << cameraMatrix; 118 fs << "distcoeff" << distCoeffs; 119 } 120筆者使用的校正 pattern 長寬各有 8 以及 6 個角點. 因此代碼 48 行 設定為 boardSize(8, 6)
54~60 行定義校正 pattern 角點的 3D coordinate.
62 行的 while loop 將影像序列 一張一張的讀入, 每讀入一張, 就以 77 以及 80 行的代碼進行角點提取. 87 行判斷是否正常提取到校正 pattern 上的所有48 個角點, 若是, 則將這些角點在影像上的座標儲存起來. 代碼 93 行則是將其取到的角點加以標示. 當所有的影像都完成角點提取, 則 108 行使用 calibrationCamera 進行攝像頭校正.
在這裡, 我們感興趣的是 camera 內部參數以及型變參數, calibrationCamera 會為我們計算這些參數並分別儲存在 cameraMatrix 以及 distCoeffs.
116~118 行, 我將 cameraMatrix以及 distCoeffs 的內容儲存到 test.yml 檔案.
圖二是其中一張影像的角點提取結果:
圖二 角點提取 |
校正出的內參以及型變參數如下:
%YAML:1.0
intrinsic: !!opencv-matrix
rows: 3
cols: 3
dt: d
data: [ 7.2042901435965223e+002, 0., 3.2967552840264563e+002, 0.,
7.1972210146332782e+002, 2.6487944722387311e+002, 0., 0., 1. ]
distcoeff: !!opencv-matrix
rows: 1
cols: 5
dt: d
data: [ 1.0477467445014127e-001, -1.1727926119997072e+000,
3.4074683728567670e-003, 4.3480547323742199e-003,
2.2097821427154618e+000 ]
fx = 7.2042901435965223e+002
fy = 7.1972210146332782e+002
cx = 3.2967552840264563e+002
cy = 2.6487944722387311e+002
k1 = 1.0477467445014127e-001
k2 = -1.1727926119997072e+000
p1 = 3.4074683728567670e-003
p2 = 4.3480547323742199e-003
k3 = 2.2097821427154618e+000
您好,請問一下
回覆刪除OpenCV這相機校正,是不是校正完後會產生參數檔?之後可否只要直接讀取該檔案的數值就好?不然每一次都要執行一次感覺很花時間的說
另外不知可否像您請教個人遇到的一些問題
因為我做相機校正,每一次結果都會不一樣
我不知道怎樣才是正確的結果...
下面兩部影片是我兩次校正結果,希望您有空的話能給予解答
http://www.youtube.com/watch?v=kPR4FoHz7C8
http://www.youtube.com/watch?v=5x0unaA2FSc
謝謝
(1)是的, 只要把 yml 檔讀入就可以了, 不需要重複 capture image 以及 計算校正參數.
回覆刪除(2)會有一些不一樣, 以形變來說, 可以使用 openCV 的 initUndistortRectifyMap 函式
進行 undistortion. 並使用一些測試用的 pattern, 例如 line grid pattern; 網格圖, 確認undistortion 的品質.
您好:
回覆刪除請問如果我想得到外部參數的話要怎麼做呢?
rotation matrix+translation matrix應該會是3x4的一個矩陣。
我有試著去寫出extrinsic_parameters:在yml上,但是寫出來的東西好像怪怪的一組rotation vector+translation vector只有六個數字。到底要怎麼看不太清楚,不知道能不能幫我解答一下,謝謝~
您好,我目前也有這個困擾
刪除請問樓主找到答案了嗎 ? 謝謝
透過calibrateCamera()會得到的15~20組rotation vector + translation vector,
刪除每組rotation vector + translation vector即是擷取的影像當下的外部參數。
如果想得到某張擷取影像當下的外部參數,可以用Rodrigues()將rotation vector轉成rotation matrix,此時rotation matrix + translation matrix就會是一個3x4的矩陣
你好:
回覆刪除程式碼第 113 行, 的兩個參數: rvecs, tvecs 是外部參數(extrinsic parameters).
rvecs 是 rotation matrix, tvecs 是 translation matrix.
Richard您好:
回覆刪除請問我依照您 [OpenCV 影像擷取 - 使用 DirectShow]方法
也做一次,但無法顯示USB影像,ERROR如下,請幫我看看,
感謝。
WIN7 64bit+OPENCV246+VS2012
有抓到筆電內CCD,但報ERROR如下
Debug Assertion Failed
program....ments\Visual Studio 2012\Projects\ccd_in\
x64\Debug\ccd_in.exe
File:C:\Program File (x86)\Microsoft Visual Studio 11.0\
VC\atlmfc\include\atlcomcli.h
Line:197
Expression:p!=0
For information on how your program can cause an assertion
failure,see the Visual C++ documentation on asserts.
匿名 你好
刪除我的平台是 Visual Studio 2010 + windows XP 32bits
並不會有這個問題.
此篇樓主您好,我也有同樣問題,請問您後來有解決了嗎?
刪除若有可否提供,謝謝
想請問一下,我在執行程式的時候,顯示說找不到下方此標頭檔,要如何解決
回覆刪除#include "CameraDS.h"
build code 環境設定請參考我blog的另一篇文章, 標題是
回覆刪除OpenCV 影像擷取 - 使用 DirectShow.
有沒有效正camera color matrix的方法呢?
回覆刪除想進一步瞭解...
thanks
想請問一下
回覆刪除我使用OpencCV校正過一次後
接著將失真的圖形remap成無失真圖片
並接著再對其無失真的圖片校正一次
結果二次校正並remap的圖片邊緣會嚴重失真
這個是甚麼原因呢?
是否OpenCV不能對已經校正過的相機(如手機相機)做校正呢?
這樣我要如何得到focal length?
作者已經移除這則留言。
回覆刪除請問OpenCv 3.0 的intrinsics.yml 跟extrinsics.yml跟之前版本的有何不同呢?
回覆刪除矩陣代表的意義是否也不同了呢?
請問整個型變參數在整個相機校正的流程當中
回覆刪除是使用在世界座標轉成相機座標後
還是使用在相機座標轉乘影像座標後使用
因為前面介紹內外部參數矩陣,都沒有包含扭曲參數的矩陣
那這個矩陣到底用在哪個部分呢?
請問為何54~60那段
回覆刪除為何objectCorners可以直接那樣取得??謝謝!!
您好,目前我碰到了一個很大的問題,我校正完發現所使用OpenCV的function為了維持校正完影像和原始影像相同大小,所以校正完會有切除超出影像大小的部分,不知道是否有方法可以在校正完的影像上得到原始影像的所有資訊
回覆刪除您好,目前我碰到了一個很大的問題,我校正完發現所使用OpenCV的function為了維持校正完影像和原始影像相同大小,所以校正完會有切除超出影像大小的部分,不知道是否有方法可以在校正完的影像上得到原始影像的所有資訊
回覆刪除作者已經移除這則留言。
回覆刪除Ankara
回覆刪除Van
Hakkari
Edirne
Yozgat
4QXUİ
elazığ
回覆刪除gümüşhane
kilis
siirt
sakarya
T3Q
https://titandijital.com.tr/
回覆刪除amasya parça eşya taşıma
adıyaman parça eşya taşıma
hatay parça eşya taşıma
giresun parça eşya taşıma
1Rİİ37
04D0F
回覆刪除Aydın Lojistik
Iğdır Lojistik
Uşak Parça Eşya Taşıma
Çerkezköy Korkuluk
Gölbaşı Fayans Ustası
Kripto Para Borsaları
Bilecik Lojistik
Ağrı Lojistik
Huobi Güvenilir mi
0700B
回覆刪除%20 binance indirim kodu
2B576
回覆刪除bedava görüntülü sohbet
antep canlı sohbet odası
edirne bedava sohbet chat odaları
aksaray en iyi ücretsiz sohbet uygulamaları
sinop rastgele sohbet odaları
ığdır rastgele sohbet uygulaması
hakkari parasız görüntülü sohbet
kütahya yabancı sohbet
kastamonu bedava sohbet odaları