日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

转载:https://blog.csdn.net/dcrmg/article/details/52939318

發(fā)布時(shí)間:2023/12/10 编程问答 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 转载:https://blog.csdn.net/dcrmg/article/details/52939318 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
張正友相機(jī)標(biāo)定Opencv實(shí)現(xiàn)以及標(biāo)定流程&&標(biāo)定結(jié)果評價(jià)&&圖像矯正流程解析(附標(biāo)定程序和棋盤圖)

使用Opencv實(shí)現(xiàn)張正友法相機(jī)標(biāo)定之前,有幾個(gè)問題事先要確認(rèn)一下,那就是相機(jī)為什么需要標(biāo)定,標(biāo)定需要的輸入和輸出分別是哪些?


相機(jī)標(biāo)定的目的:獲取攝像機(jī)的內(nèi)參和外參矩陣(同時(shí)也會得到每一幅標(biāo)定圖像的選擇和平移矩陣),內(nèi)參和外參系數(shù)可以對之后相機(jī)拍攝的圖像就進(jìn)行矯正,得到畸變相對很小的圖像。

相機(jī)標(biāo)定的輸入:標(biāo)定圖像上所有內(nèi)角點(diǎn)的圖像坐標(biāo),標(biāo)定板圖像上所有內(nèi)角點(diǎn)的空間三維坐標(biāo)(一般情況下假定圖像位于Z=0平面上)。

相機(jī)標(biāo)定的輸出:攝像機(jī)的內(nèi)參、外參系數(shù)。


這三個(gè)基礎(chǔ)的問題就決定了使用Opencv實(shí)現(xiàn)張正友法標(biāo)定相機(jī)的標(biāo)定流程、標(biāo)定結(jié)果評價(jià)以及使用標(biāo)定結(jié)果矯正原始圖像的完整流程:


1. 準(zhǔn)備標(biāo)定圖片

2. 對每一張標(biāo)定圖片,提取角點(diǎn)信息

3. 對每一張標(biāo)定圖片,進(jìn)一步提取亞像素角點(diǎn)信息

4. 在棋盤標(biāo)定圖上繪制找到的內(nèi)角點(diǎn)(非必須,僅為了顯示)

5. 相機(jī)標(biāo)定

6. 對標(biāo)定結(jié)果進(jìn)行評價(jià)

7. 查看標(biāo)定效果——利用標(biāo)定結(jié)果對棋盤圖進(jìn)行矯正


1. 準(zhǔn)備標(biāo)定圖片


標(biāo)定圖片需要使用標(biāo)定板在不同位置、不同角度、不同姿態(tài)下拍攝,最少需要3張,以10~20張為宜。標(biāo)定板需要是黑白相間的矩形構(gòu)成的棋盤圖,制作精度要求較高,如下圖所示:





2.對每一張標(biāo)定圖片,提取角點(diǎn)信息


需要使用findChessboardCorners函數(shù)提取角點(diǎn),這里的角點(diǎn)專指的是標(biāo)定板上的內(nèi)角點(diǎn),這些角點(diǎn)與標(biāo)定板的邊緣不接觸。

?findChessboardCorners函數(shù)原型:

[cpp] view plaincopy
  • //!?finds?checkerboard?pattern?of?the?specified?size?in?the?image??
  • CV_EXPORTS_W?bool?findChessboardCorners(?InputArray?image,?Size?patternSize,??
  • ?????????????????????????????????????????OutputArray?corners,??
  • ?????????????????????????????????????????int?flags=CALIB_CB_ADAPTIVE_THRESH+CALIB_CB_NORMALIZE_IMAGE?);??

  • 第一個(gè)參數(shù)Image,傳入拍攝的棋盤圖Mat圖像,必須是8位的灰度或者彩色圖像;

    第二個(gè)參數(shù)patternSize,每個(gè)棋盤圖上內(nèi)角點(diǎn)的行列數(shù),一般情況下,行列數(shù)不要相同,便于后續(xù)標(biāo)定程序識別標(biāo)定板的方向;

    第三個(gè)參數(shù)corners,用于存儲檢測到的內(nèi)角點(diǎn)圖像坐標(biāo)位置,一般用元素是Point2f的向量來表示:vector<Point2f> image_points_buf;

    第四個(gè)參數(shù)flage:用于定義棋盤圖上內(nèi)角點(diǎn)查找的不同處理方式,有默認(rèn)值。



    3. 對每一張標(biāo)定圖片,進(jìn)一步提取亞像素角點(diǎn)信息


    為了提高標(biāo)定精度,需要在初步提取的角點(diǎn)信息上進(jìn)一步提取亞像素信息,降低相機(jī)標(biāo)定偏差,常用的方法是cornerSubPix,另一個(gè)方法是使用find4QuadCornerSubpix函數(shù),這個(gè)方法是專門用來獲取棋盤圖上內(nèi)角點(diǎn)的精確位置的,或許在相機(jī)標(biāo)定的這個(gè)特殊場合下它的檢測精度會比cornerSubPix更高?

    cornerSubPix函數(shù)原型:

    [cpp] view plaincopy
  • //!?adjusts?the?corner?locations?with?sub-pixel?accuracy?to?maximize?the?certain?cornerness?criteria??
  • CV_EXPORTS_W?void?cornerSubPix(?InputArray?image,?InputOutputArray?corners,??
  • ????????????????????????????????Size?winSize,?Size?zeroZone,??
  • ????????????????????????????????TermCriteria?criteria?);??

  • 第一個(gè)參數(shù)image,輸入的Mat矩陣,最好是8位灰度圖像,檢測效率更高;

    第二個(gè)參數(shù)corners,初始的角點(diǎn)坐標(biāo)向量,同時(shí)作為亞像素坐標(biāo)位置的輸出,所以需要是浮點(diǎn)型數(shù)據(jù),一般用元素是Pointf2f/Point2d的向量來表示:vector<Point2f/Point2d> iamgePointsBuf;

    第三個(gè)參數(shù)winSize,大小為搜索窗口的一半;

    第四個(gè)參數(shù)zeroZone,死區(qū)的一半尺寸,死區(qū)為不對搜索區(qū)的中央位置做求和運(yùn)算的區(qū)域。它是用來避免自相關(guān)矩陣出現(xiàn)某些可能的奇異性。當(dāng)值為(-1,-1)時(shí)表示沒有死區(qū);

    第五個(gè)參數(shù)criteria,定義求角點(diǎn)的迭代過程的終止條件,可以為迭代次數(shù)和角點(diǎn)精度兩者的組合;

    find4QuadCornerSubpix函數(shù)原型:

    [cpp] view plaincopy
  • //!?finds?subpixel-accurate?positions?of?the?chessboard?corners??
  • CV_EXPORTS?bool?find4QuadCornerSubpix(InputArray?img,?InputOutputArray?corners,?Size?region_size);??

  • 第一個(gè)參數(shù)img,輸入的Mat矩陣,最好是8位灰度圖像,檢測效率更高;

    第二個(gè)參數(shù)corners,初始的角點(diǎn)坐標(biāo)向量,同時(shí)作為亞像素坐標(biāo)位置的輸出,所以需要是浮點(diǎn)型數(shù)據(jù),一般用元素是Pointf2f/Point2d的向量來表示:vector<Point2f/Point2d> iamgePointsBuf;

    第三個(gè)參數(shù)region_size,角點(diǎn)搜索窗口的尺寸;

    在其中一個(gè)標(biāo)定的棋盤圖上分別運(yùn)行cornerSubPix和find4QuadCornerSubpix尋找亞像素角點(diǎn),兩者定位到的亞像素角點(diǎn)坐標(biāo)分別為:


    ? ?cornerSubPix: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??find4QuadCornerSubpix:

    ? ? ? ? ? ? ? ? ? ? ? ?


    雖然有一定差距,但偏差基本都控制在0.5個(gè)像素之內(nèi)。



    4. 在棋盤標(biāo)定圖上繪制找到的內(nèi)角點(diǎn)(非必須,僅為了顯示)



    drawChessboardCorners函數(shù)用于繪制被成功標(biāo)定的角點(diǎn),函數(shù)原型:


    [cpp] view plaincopy
  • //!?draws?the?checkerboard?pattern?(found?or?partly?found)?in?the?image??
  • CV_EXPORTS_W?void?drawChessboardCorners(?InputOutputArray?image,?Size?patternSize,??
  • ?????????????????????????????????????????InputArray?corners,?bool?patternWasFound?);??
  • 第一個(gè)參數(shù)image,8位灰度或者彩色圖像;

    第二個(gè)參數(shù)patternSize,每張標(biāo)定棋盤上內(nèi)角點(diǎn)的行列數(shù);

    第三個(gè)參數(shù)corners,初始的角點(diǎn)坐標(biāo)向量,同時(shí)作為亞像素坐標(biāo)位置的輸出,所以需要是浮點(diǎn)型數(shù)據(jù),一般用元素是Pointf2f/Point2d的向量來表示:vector<Point2f/Point2d> iamgePointsBuf;

    第四個(gè)參數(shù)patternWasFound,標(biāo)志位,用來指示定義的棋盤內(nèi)角點(diǎn)是否被完整的探測到,true表示別完整的探測到,函數(shù)會用直線依次連接所有的內(nèi)角點(diǎn),作為一個(gè)整體,false表示有未被探測到的內(nèi)角點(diǎn),這時(shí)候函數(shù)會以(紅色)圓圈標(biāo)記處檢測到的內(nèi)角點(diǎn);

    以下是drawChessboardCorners函數(shù)中第四個(gè)參數(shù)patternWasFound設(shè)置為true和false時(shí)內(nèi)角點(diǎn)的繪制效果:

    patternWasFound=ture時(shí),依次連接各個(gè)內(nèi)角點(diǎn):




    patternWasFound=false時(shí),以(紅色)圓圈標(biāo)記處角點(diǎn)位置:




    5. 相機(jī)標(biāo)定



    獲取到棋盤標(biāo)定圖的內(nèi)角點(diǎn)圖像坐標(biāo)之后,就可以使用calibrateCamera函數(shù)進(jìn)行標(biāo)定,計(jì)算相機(jī)內(nèi)參和外參系數(shù),

    calibrateCamera函數(shù)原型:

    [cpp] view plaincopy
  • //!?finds?intrinsic?and?extrinsic?camera?parameters?from?several?fews?of?a?known?calibration?pattern.??
  • CV_EXPORTS_W?double?calibrateCamera(?InputArrayOfArrays?objectPoints,??
  • ?????????????????????????????????????InputArrayOfArrays?imagePoints,??
  • ?????????????????????????????????????Size?imageSize,??
  • ?????????????????????????????????????CV_OUT?InputOutputArray?cameraMatrix,??
  • ?????????????????????????????????????CV_OUT?InputOutputArray?distCoeffs,??
  • ?????????????????????????????????????OutputArrayOfArrays?rvecs,?OutputArrayOfArrays?tvecs,??
  • ?????????????????????????????????????int?flags=0,?TermCriteria?criteria?=?TermCriteria(??
  • ?????????????????????????????????????????TermCriteria::COUNT+TermCriteria::EPS,?30,?DBL_EPSILON)?);??

  • 第一個(gè)參數(shù)objectPoints,為世界坐標(biāo)系中的三維點(diǎn)。在使用時(shí),應(yīng)該輸入一個(gè)三維坐標(biāo)點(diǎn)的向量的向量,即vector<vector<Point3f>> object_points。需要依據(jù)棋盤上單個(gè)黑白矩陣的大小,計(jì)算出(初始化)每一個(gè)內(nèi)角點(diǎn)的世界坐標(biāo)。

    第二個(gè)參數(shù)imagePoints,為每一個(gè)內(nèi)角點(diǎn)對應(yīng)的圖像坐標(biāo)點(diǎn)。和objectPoints一樣,應(yīng)該輸入vector<vector<Point2f>> image_points_seq形式的變量;

    第三個(gè)參數(shù)imageSize,為圖像的像素尺寸大小,在計(jì)算相機(jī)的內(nèi)參和畸變矩陣時(shí)需要使用到該參數(shù);

    第四個(gè)參數(shù)cameraMatrix為相機(jī)的內(nèi)參矩陣。輸入一個(gè)Mat cameraMatrix即可,如Mat cameraMatrix=Mat(3,3,CV_32FC1,Scalar::all(0));

    第五個(gè)參數(shù)distCoeffs為畸變矩陣。輸入一個(gè)Mat distCoeffs=Mat(1,5,CV_32FC1,Scalar::all(0))即可;

    第六個(gè)參數(shù)rvecs為旋轉(zhuǎn)向量;應(yīng)該輸入一個(gè)Mat類型的vector,即vector<Mat>rvecs;

    第七個(gè)參數(shù)tvecs為位移向量,和rvecs一樣,應(yīng)該為vector<Mat> tvecs;

    第八個(gè)參數(shù)flags為標(biāo)定時(shí)所采用的算法。有如下幾個(gè)參數(shù):

    CV_CALIB_USE_INTRINSIC_GUESS:使用該參數(shù)時(shí),在cameraMatrix矩陣中應(yīng)該有fx,fy,u0,v0的估計(jì)值。否則的話,將初始化(u0,v0)圖像的中心點(diǎn),使用最小二乘估算出fx,fy。?
    CV_CALIB_FIX_PRINCIPAL_POINT:在進(jìn)行優(yōu)化時(shí)會固定光軸點(diǎn)。當(dāng)CV_CALIB_USE_INTRINSIC_GUESS參數(shù)被設(shè)置,光軸點(diǎn)將保持在中心或者某個(gè)輸入的值。?
    CV_CALIB_FIX_ASPECT_RATIO:固定fx/fy的比值,只將fy作為可變量,進(jìn)行優(yōu)化計(jì)算。當(dāng)CV_CALIB_USE_INTRINSIC_GUESS沒有被設(shè)置,fx和fy將會被忽略。只有fx/fy的比值在計(jì)算中會被用到。?
    CV_CALIB_ZERO_TANGENT_DIST:設(shè)定切向畸變參數(shù)(p1,p2)為零。?
    CV_CALIB_FIX_K1,…,CV_CALIB_FIX_K6:對應(yīng)的徑向畸變在優(yōu)化中保持不變。?
    CV_CALIB_RATIONAL_MODEL:計(jì)算k4,k5,k6三個(gè)畸變參數(shù)。如果沒有設(shè)置,則只計(jì)算其它5個(gè)畸變參數(shù)。

    第九個(gè)參數(shù)criteria是最優(yōu)迭代終止條件設(shè)定。

    在使用該函數(shù)進(jìn)行標(biāo)定運(yùn)算之前,需要對棋盤上每一個(gè)內(nèi)角點(diǎn)的空間坐標(biāo)系的位置坐標(biāo)進(jìn)行初始化,標(biāo)定的結(jié)果是生成相機(jī)的內(nèi)參矩陣cameraMatrix、相機(jī)的5個(gè)畸變系數(shù)distCoeffs,另外每張圖像都會生成屬于自己的平移向量和旋轉(zhuǎn)向量。



    6. 對標(biāo)定結(jié)果進(jìn)行評價(jià)



    對標(biāo)定結(jié)果進(jìn)行評價(jià)的方法是通過得到的攝像機(jī)內(nèi)外參數(shù),對空間的三維點(diǎn)進(jìn)行重新投影計(jì)算,得到空間三維點(diǎn)在圖像上新的投影點(diǎn)的坐標(biāo),計(jì)算投影坐標(biāo)和亞像素角點(diǎn)坐標(biāo)之間的偏差,偏差越小,標(biāo)定結(jié)果越好。

    對空間三維坐標(biāo)點(diǎn)進(jìn)行反向投影的函數(shù)是projectPoints,函數(shù)原型是:

    [cpp] view plaincopy
  • //!?projects?points?from?the?model?coordinate?space?to?the?image?coordinates.?Also?computes?derivatives?of?the?image?coordinates?w.r.t?the?intrinsic?and?extrinsic?camera?parameters??
  • CV_EXPORTS_W?void?projectPoints(?InputArray?objectPoints,??
  • ?????????????????????????????????InputArray?rvec,?InputArray?tvec,??
  • ?????????????????????????????????InputArray?cameraMatrix,?InputArray?distCoeffs,??
  • ?????????????????????????????????OutputArray?imagePoints,??
  • ?????????????????????????????????OutputArray?jacobian=noArray(),??
  • ?????????????????????????????????double?aspectRatio=0?);??

  • 第一個(gè)參數(shù)objectPoints,為相機(jī)坐標(biāo)系中的三維點(diǎn)坐標(biāo);

    第二個(gè)參數(shù)rvec為旋轉(zhuǎn)向量,每一張圖像都有自己的選擇向量;

    第三個(gè)參數(shù)tvec為位移向量,每一張圖像都有自己的平移向量;

    第四個(gè)參數(shù)cameraMatrix為求得的相機(jī)的內(nèi)參數(shù)矩陣;

    第五個(gè)參數(shù)distCoeffs為相機(jī)的畸變矩陣;

    第六個(gè)參數(shù)iamgePoints為每一個(gè)內(nèi)角點(diǎn)對應(yīng)的圖像上的坐標(biāo)點(diǎn);

    第七個(gè)參數(shù)jacobian是雅可比行列式;

    第八個(gè)參數(shù)aspectRatio是跟相機(jī)傳感器的感光單元有關(guān)的可選參數(shù),如果設(shè)置為非0,則函數(shù)默認(rèn)感光單元的dx/dy是固定的,會依此對雅可比矩陣進(jìn)行調(diào)整;

    下邊顯示了某一張標(biāo)定圖片上的亞像素角點(diǎn)坐標(biāo)和根據(jù)標(biāo)定結(jié)果把空間三維坐標(biāo)點(diǎn)映射回圖像坐標(biāo)點(diǎn)的對比:


    find4QuadCornerSubpix查找到的亞像素點(diǎn)坐標(biāo): ? ? ? ? ? ? ? ? ? ? ? ? ??projectPoints映射的坐標(biāo):

    ? ? ? ? ? ? ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ????


    以下是每一幅圖像上24個(gè)內(nèi)角點(diǎn)的平均誤差統(tǒng)計(jì)數(shù)據(jù):




    7. 查看標(biāo)定效果——利用標(biāo)定結(jié)果對棋盤圖進(jìn)行矯正



    利用求得的相機(jī)的內(nèi)參和外參數(shù)據(jù),可以對圖像進(jìn)行畸變的矯正,這里有兩種方法可以達(dá)到矯正的目的,分別說明一下。

    方法一:使用initUndistortRectifyMap和remap兩個(gè)函數(shù)配合實(shí)現(xiàn)。

    initUndistortRectifyMap用來計(jì)算畸變映射,remap把求得的映射應(yīng)用到圖像上。

    initUndistortRectifyMap的函數(shù)原型:

    [cpp] view plaincopy
  • //!?initializes?maps?for?cv::remap()?to?correct?lens?distortion?and?optionally?rectify?the?image??
  • CV_EXPORTS_W?void?initUndistortRectifyMap(?InputArray?cameraMatrix,?InputArray?distCoeffs,??
  • ???????????????????????????InputArray?R,?InputArray?newCameraMatrix,??
  • ???????????????????????????Size?size,?int?m1type,?OutputArray?map1,?OutputArray?map2?);??
  • 第一個(gè)參數(shù)cameraMatrix為之前求得的相機(jī)的內(nèi)參矩陣;

    第二個(gè)參數(shù)distCoeffs為之前求得的相機(jī)畸變矩陣;

    第三個(gè)參數(shù)R,可選的輸入,是第一和第二相機(jī)坐標(biāo)之間的旋轉(zhuǎn)矩陣;

    第四個(gè)參數(shù)newCameraMatrix,輸入的校正后的3X3攝像機(jī)矩陣;

    第五個(gè)參數(shù)size,攝像機(jī)采集的無失真的圖像尺寸;

    第六個(gè)參數(shù)m1type,定義map1的數(shù)據(jù)類型,可以是CV_32FC1或者CV_16SC2;

    第七個(gè)參數(shù)map1和第八個(gè)參數(shù)map2,輸出的X/Y坐標(biāo)重映射參數(shù);


    remap函數(shù)原型:

    [cpp] view plaincopy
  • //!?warps?the?image?using?the?precomputed?maps.?The?maps?are?stored?in?either?floating-point?or?integer?fixed-point?format??
  • CV_EXPORTS_W?void?remap(?InputArray?src,?OutputArray?dst,??
  • ?????????????????????????InputArray?map1,?InputArray?map2,??
  • ?????????????????????????int?interpolation,?int?borderMode=BORDER_CONSTANT,??
  • ?????????????????????????const?Scalar&?borderValue=Scalar());??

  • 第一個(gè)參數(shù)src,輸入?yún)?shù),代表畸變的原始圖像;

    第二個(gè)參數(shù)dst,矯正后的輸出圖像,跟輸入圖像具有相同的類型和大小;

    第三個(gè)參數(shù)map1和第四個(gè)參數(shù)map2,X坐標(biāo)和Y坐標(biāo)的映射;

    第五個(gè)參數(shù)interpolation,定義圖像的插值方式;

    第六個(gè)參數(shù)borderMode,定義邊界填充方式;


    方法二:使用undistort函數(shù)實(shí)現(xiàn)

    undistort函數(shù)原型:

    [cpp] view plaincopy
  • //!?corrects?lens?distortion?for?the?given?camera?matrix?and?distortion?coefficients??
  • CV_EXPORTS_W?void?undistort(?InputArray?src,?OutputArray?dst,??
  • ?????????????????????????????InputArray?cameraMatrix,??
  • ?????????????????????????????InputArray?distCoeffs,??
  • ?????????????????????????????InputArray?newCameraMatrix=noArray()?);??

  • 第一個(gè)參數(shù)src,輸入?yún)?shù),代表畸變的原始圖像;

    第二個(gè)參數(shù)dst,矯正后的輸出圖像,跟輸入圖像具有相同的類型和大小;

    第三個(gè)參數(shù)cameraMatrix為之前求得的相機(jī)的內(nèi)參矩陣;

    第四個(gè)參數(shù)distCoeffs為之前求得的相機(jī)畸變矩陣;

    第五個(gè)參數(shù)newCameraMatrix,默認(rèn)跟cameraMatrix保持一致;

    方法一相比方法二執(zhí)行效率更高一些,推薦使用。


    以下是使用某一張標(biāo)定圖使用方法一和方法二進(jìn)行矯正的效果圖對比。

    原始標(biāo)定圖像:



    方法一,使用initUndistortRectifyMap和remap實(shí)現(xiàn)矯正效果:



    方法二,使用undistort函數(shù)實(shí)現(xiàn)矯正效果:



    兩個(gè)方法從矯正效果上看,結(jié)果是一致的。


    以下是完整的工程代碼:


    [cpp] view plaincopy
  • #include?"opencv2/core/core.hpp"??
  • #include?"opencv2/imgproc/imgproc.hpp"??
  • #include?"opencv2/calib3d/calib3d.hpp"??
  • #include?"opencv2/highgui/highgui.hpp"??
  • #include?<iostream>??
  • #include?<fstream>??
  • ??
  • using?namespace?cv;??
  • using?namespace?std;??
  • ??
  • void?main()???
  • {??
  • ????ifstream?fin("calibdata.txt");?/*?標(biāo)定所用圖像文件的路徑?*/??
  • ????ofstream?fout("caliberation_result.txt");??/*?保存標(biāo)定結(jié)果的文件?*/????
  • ????//讀取每一幅圖像,從中提取出角點(diǎn),然后對角點(diǎn)進(jìn)行亞像素精確化???
  • ????cout<<"開始提取角點(diǎn)………………";??
  • ????int?image_count=0;??/*?圖像數(shù)量?*/??
  • ????Size?image_size;??/*?圖像的尺寸?*/??
  • ????Size?board_size?=?Size(4,6);????/*?標(biāo)定板上每行、列的角點(diǎn)數(shù)?*/??
  • ????vector<Point2f>?image_points_buf;??/*?緩存每幅圖像上檢測到的角點(diǎn)?*/??
  • ????vector<vector<Point2f>>?image_points_seq;?/*?保存檢測到的所有角點(diǎn)?*/??
  • ????string?filename;??
  • ????int?count=?-1?;//用于存儲角點(diǎn)個(gè)數(shù)。??
  • ????while?(getline(fin,filename))??
  • ????{??
  • ????????image_count++;????????
  • ????????//?用于觀察檢驗(yàn)輸出??
  • ????????cout<<"image_count?=?"<<image_count<<endl;??????????
  • ????????/*?輸出檢驗(yàn)*/??
  • ????????cout<<"-->count?=?"<<count;????????
  • ????????Mat?imageInput=imread(filename);??
  • ????????if?(image_count?==?1)??//讀入第一張圖片時(shí)獲取圖像寬高信息??
  • ????????{??
  • ????????????image_size.width?=?imageInput.cols;??
  • ????????????image_size.height?=imageInput.rows;???????????
  • ????????????cout<<"image_size.width?=?"<<image_size.width<<endl;??
  • ????????????cout<<"image_size.height?=?"<<image_size.height<<endl;??
  • ????????}??
  • ??
  • ????????/*?提取角點(diǎn)?*/??
  • ????????if?(0?==?findChessboardCorners(imageInput,board_size,image_points_buf))??
  • ????????{?????????????
  • ????????????cout<<"can?not?find?chessboard?corners!\n";?//找不到角點(diǎn)??
  • ????????????exit(1);??
  • ????????}???
  • ????????else???
  • ????????{??
  • ????????????Mat?view_gray;??
  • ????????????cvtColor(imageInput,view_gray,CV_RGB2GRAY);??
  • ????????????/*?亞像素精確化?*/??
  • ????????????find4QuadCornerSubpix(view_gray,image_points_buf,Size(5,5));?//對粗提取的角點(diǎn)進(jìn)行精確化??
  • ????????????//cornerSubPix(view_gray,image_points_buf,Size(5,5),Size(-1,-1),TermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER,30,0.1));??
  • ????????????image_points_seq.push_back(image_points_buf);??//保存亞像素角點(diǎn)??
  • ????????????/*?在圖像上顯示角點(diǎn)位置?*/??
  • ????????????drawChessboardCorners(view_gray,board_size,image_points_buf,false);?//用于在圖片中標(biāo)記角點(diǎn)??
  • ????????????imshow("Camera?Calibration",view_gray);//顯示圖片??
  • ????????????waitKey(500);//暫停0.5S?????????
  • ????????}??
  • ????}??
  • ????int?total?=?image_points_seq.size();??
  • ????cout<<"total?=?"<<total<<endl;??
  • ????int?CornerNum=board_size.width*board_size.height;??//每張圖片上總的角點(diǎn)數(shù)??
  • ????for?(int?ii=0?;?ii<total?;ii++)??
  • ????{??
  • ????????if?(0?==?ii%CornerNum)//?24?是每幅圖片的角點(diǎn)個(gè)數(shù)。此判斷語句是為了輸出?圖片號,便于控制臺觀看???
  • ????????{?????
  • ????????????int?i?=?-1;??
  • ????????????i?=?ii/CornerNum;??
  • ????????????int?j=i+1;??
  • ????????????cout<<"-->?第?"<<j?<<"圖片的數(shù)據(jù)?-->?:?"<<endl;??
  • ????????}??
  • ????????if?(0?==?ii%3)??//?此判斷語句,格式化輸出,便于控制臺查看??
  • ????????{??
  • ????????????cout<<endl;??
  • ????????}??
  • ????????else??
  • ????????{??
  • ????????????cout.width(10);??
  • ????????}??
  • ????????//輸出所有的角點(diǎn)??
  • ????????cout<<"?-->"<<image_points_seq[ii][0].x;??
  • ????????cout<<"?-->"<<image_points_seq[ii][0].y;??
  • ????}?????
  • ????cout<<"角點(diǎn)提取完成!\n";??
  • ??
  • ????//以下是攝像機(jī)標(biāo)定??
  • ????cout<<"開始標(biāo)定………………";??
  • ????/*棋盤三維信息*/??
  • ????Size?square_size?=?Size(10,10);??/*?實(shí)際測量得到的標(biāo)定板上每個(gè)棋盤格的大小?*/??
  • ????vector<vector<Point3f>>?object_points;?/*?保存標(biāo)定板上角點(diǎn)的三維坐標(biāo)?*/??
  • ????/*內(nèi)外參數(shù)*/??
  • ????Mat?cameraMatrix=Mat(3,3,CV_32FC1,Scalar::all(0));?/*?攝像機(jī)內(nèi)參數(shù)矩陣?*/??
  • ????vector<int>?point_counts;??//?每幅圖像中角點(diǎn)的數(shù)量??
  • ????Mat?distCoeffs=Mat(1,5,CV_32FC1,Scalar::all(0));?/*?攝像機(jī)的5個(gè)畸變系數(shù):k1,k2,p1,p2,k3?*/??
  • ????vector<Mat>?tvecsMat;??/*?每幅圖像的旋轉(zhuǎn)向量?*/??
  • ????vector<Mat>?rvecsMat;?/*?每幅圖像的平移向量?*/??
  • ????/*?初始化標(biāo)定板上角點(diǎn)的三維坐標(biāo)?*/??
  • ????int?i,j,t;??
  • ????for?(t=0;t<image_count;t++)???
  • ????{??
  • ????????vector<Point3f>?tempPointSet;??
  • ????????for?(i=0;i<board_size.height;i++)???
  • ????????{??
  • ????????????for?(j=0;j<board_size.width;j++)???
  • ????????????{??
  • ????????????????Point3f?realPoint;??
  • ????????????????/*?假設(shè)標(biāo)定板放在世界坐標(biāo)系中z=0的平面上?*/??
  • ????????????????realPoint.x?=?i*square_size.width;??
  • ????????????????realPoint.y?=?j*square_size.height;??
  • ????????????????realPoint.z?=?0;??
  • ????????????????tempPointSet.push_back(realPoint);??
  • ????????????}??
  • ????????}??
  • ????????object_points.push_back(tempPointSet);??
  • ????}??
  • ????/*?初始化每幅圖像中的角點(diǎn)數(shù)量,假定每幅圖像中都可以看到完整的標(biāo)定板?*/??
  • ????for?(i=0;i<image_count;i++)??
  • ????{??
  • ????????point_counts.push_back(board_size.width*board_size.height);??
  • ????}?????
  • ????/*?開始標(biāo)定?*/??
  • ????calibrateCamera(object_points,image_points_seq,image_size,cameraMatrix,distCoeffs,rvecsMat,tvecsMat,0);??
  • ????cout<<"標(biāo)定完成!\n";??
  • ????//對標(biāo)定結(jié)果進(jìn)行評價(jià)??
  • ????cout<<"開始評價(jià)標(biāo)定結(jié)果………………\n";??
  • ????double?total_err?=?0.0;?/*?所有圖像的平均誤差的總和?*/??
  • ????double?err?=?0.0;?/*?每幅圖像的平均誤差?*/??
  • ????vector<Point2f>?image_points2;?/*?保存重新計(jì)算得到的投影點(diǎn)?*/??
  • ????cout<<"\t每幅圖像的標(biāo)定誤差:\n";??
  • ????fout<<"每幅圖像的標(biāo)定誤差:\n";??
  • ????for?(i=0;i<image_count;i++)??
  • ????{??
  • ????????vector<Point3f>?tempPointSet=object_points[i];??
  • ????????/*?通過得到的攝像機(jī)內(nèi)外參數(shù),對空間的三維點(diǎn)進(jìn)行重新投影計(jì)算,得到新的投影點(diǎn)?*/??
  • ????????projectPoints(tempPointSet,rvecsMat[i],tvecsMat[i],cameraMatrix,distCoeffs,image_points2);??
  • ????????/*?計(jì)算新的投影點(diǎn)和舊的投影點(diǎn)之間的誤差*/??
  • ????????vector<Point2f>?tempImagePoint?=?image_points_seq[i];??
  • ????????Mat?tempImagePointMat?=?Mat(1,tempImagePoint.size(),CV_32FC2);??
  • ????????Mat?image_points2Mat?=?Mat(1,image_points2.size(),?CV_32FC2);??
  • ????????for?(int?j?=?0?;?j?<?tempImagePoint.size();?j++)??
  • ????????{??
  • ????????????image_points2Mat.at<Vec2f>(0,j)?=?Vec2f(image_points2[j].x,?image_points2[j].y);??
  • ????????????tempImagePointMat.at<Vec2f>(0,j)?=?Vec2f(tempImagePoint[j].x,?tempImagePoint[j].y);??
  • ????????}??
  • ????????err?=?norm(image_points2Mat,?tempImagePointMat,?NORM_L2);??
  • ????????total_err?+=?err/=??point_counts[i];?????
  • ????????std::cout<<"第"<<i+1<<"幅圖像的平均誤差:"<<err<<"像素"<<endl;?????
  • ????????fout<<"第"<<i+1<<"幅圖像的平均誤差:"<<err<<"像素"<<endl;?????
  • ????}?????
  • ????std::cout<<"總體平均誤差:"<<total_err/image_count<<"像素"<<endl;?????
  • ????fout<<"總體平均誤差:"<<total_err/image_count<<"像素"<<endl<<endl;?????
  • ????std::cout<<"評價(jià)完成!"<<endl;????
  • ????//保存定標(biāo)結(jié)果??????
  • ????std::cout<<"開始保存定標(biāo)結(jié)果………………"<<endl;?????????
  • ????Mat?rotation_matrix?=?Mat(3,3,CV_32FC1,?Scalar::all(0));?/*?保存每幅圖像的旋轉(zhuǎn)矩陣?*/??
  • ????fout<<"相機(jī)內(nèi)參數(shù)矩陣:"<<endl;?????
  • ????fout<<cameraMatrix<<endl<<endl;?????
  • ????fout<<"畸變系數(shù):\n";?????
  • ????fout<<distCoeffs<<endl<<endl<<endl;?????
  • ????for?(int?i=0;?i<image_count;?i++)???
  • ????{???
  • ????????fout<<"第"<<i+1<<"幅圖像的旋轉(zhuǎn)向量:"<<endl;?????
  • ????????fout<<tvecsMat[i]<<endl;??????
  • ????????/*?將旋轉(zhuǎn)向量轉(zhuǎn)換為相對應(yīng)的旋轉(zhuǎn)矩陣?*/?????
  • ????????Rodrigues(tvecsMat[i],rotation_matrix);?????
  • ????????fout<<"第"<<i+1<<"幅圖像的旋轉(zhuǎn)矩陣:"<<endl;?????
  • ????????fout<<rotation_matrix<<endl;?????
  • ????????fout<<"第"<<i+1<<"幅圖像的平移向量:"<<endl;?????
  • ????????fout<<rvecsMat[i]<<endl<<endl;?????
  • ????}?????
  • ????std::cout<<"完成保存"<<endl;???
  • ????fout<<endl;??
  • ????/************************************************************************???
  • ????顯示定標(biāo)結(jié)果???
  • ????*************************************************************************/??
  • ????Mat?mapx?=?Mat(image_size,CV_32FC1);??
  • ????Mat?mapy?=?Mat(image_size,CV_32FC1);??
  • ????Mat?R?=?Mat::eye(3,3,CV_32F);??
  • ????std::cout<<"保存矯正圖像"<<endl;??
  • ????string?imageFileName;??
  • ????std::stringstream?StrStm;??
  • ????for?(int?i?=?0?;?i?!=?image_count?;?i++)??
  • ????{??
  • ????????std::cout<<"Frame?#"<<i+1<<"..."<<endl;??
  • ????????initUndistortRectifyMap(cameraMatrix,distCoeffs,R,cameraMatrix,image_size,CV_32FC1,mapx,mapy);????????
  • ????????StrStm.clear();??
  • ????????imageFileName.clear();??
  • ????????string?filePath="chess";??
  • ????????StrStm<<i+1;??
  • ????????StrStm>>imageFileName;??
  • ????????filePath+=imageFileName;??
  • ????????filePath+=".bmp";??
  • ????????Mat?imageSource?=?imread(filePath);??
  • ????????Mat?newimage?=?imageSource.clone();??
  • ????????//另一種不需要轉(zhuǎn)換矩陣的方式??
  • ????????//undistort(imageSource,newimage,cameraMatrix,distCoeffs);??
  • ????????remap(imageSource,newimage,mapx,?mapy,?INTER_LINEAR);?????????
  • ????????StrStm.clear();??
  • ????????filePath.clear();??
  • ????????StrStm<<i+1;??
  • ????????StrStm>>imageFileName;??
  • ????????imageFileName?+=?"_d.jpg";??
  • ????????imwrite(imageFileName,newimage);??
  • ????}??
  • ????std::cout<<"保存結(jié)束"<<endl;??????
  • ????return?;??
  • }??

  • 標(biāo)定圖例1:



    標(biāo)定圖例2:



    標(biāo)定結(jié)果1:



    標(biāo)定結(jié)果2:



    矯正效果1:



    矯正效果2:



    以上程序已經(jīng)是完整程序,需要棋盤標(biāo)定圖或者整個(gè)項(xiàng)目包的可以到這里下載:張正友相機(jī)標(biāo)定Opencv實(shí)現(xiàn)(完整程序+棋盤圖)。

    總結(jié)

    以上是生活随笔為你收集整理的转载:https://blog.csdn.net/dcrmg/article/details/52939318的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。