手機廣角相機標定和畸變校正

攝像頭或者相機會因爲鏡片的光學特性而發生有規律的變形或者畸變,包括桶型畸變,枕型畸變和線性畸變。普通相機的這些畸變十分輕微,人的肉眼幾乎分辨不出,所以這時可以不需要校正。對於廣角相機,魚眼相機,由於視角極大,相機透鏡的物理屬性十分明顯,從而容易導致相片極度畸變,這時除了一些追求特殊藝術效果的場合,大部分情況下都需要校正。

這裏使用OPENCV算法對相機標定和畸變校正。OPENCV是非常牛B的圖像,視頻,相機處理算法庫,封裝了圖像計算,圖像處理,分像解析,圖像分離,圖像切割,圖像識別,圖像濾鏡,圖像查找,圖像匹配等十分強大的函數庫。在VR,AR,3D,二維碼,車牌,身份證,銀行卡識別方面也應用很廣。OPENCV底層使用C和C++實現,這使其也有十分優異的速度。智能手機可以使用很多種訪求調用OPENCV完成工作,android從早期的JNI和現在的服務調用。從調用方式上來說是越來越簡單了,但從應用角度來說,卻是選擇越來越多,根據不同場合和需求,既可以直接原始JNI,也可以使用JAR調用C,還可以通過OPENCV MANAGER的服務實現。

攝像頭或者相機,或者圖片的校正分兩個步驟,一是標定,二是反畸變。標定過程是求出攝像頭或者相機或者圖片的畸變參數,通過這些參數使用特定畸變算法對圖像進行校正。

 

1.相機標定算法比較複雜,詳情參考我的前面博客。這裏不再對算法做具體解釋說明,只簡單介紹一下標定的方法。在OPECV中,標定有兩種算法,一種是棋盤紙,類似方格子紙,一種是圓圈陣列紙,兩種方法實現的原理一樣,都是通過分析圖像上固定角點的位置實現,取得的標定的參數也一樣,下面具體實現代碼,我通過一個布爾變量使得我們的校正算法可以兼容棋盤和圓圈陣列兩種方式。核心函數是findCirclesGrid和findChessboardCorners

boolean isChessboard = false;
private void findPattern(Mat grayFrame) {
    isChessboard = false;
    mPatternWasFound = Calib3d.findCirclesGrid(grayFrame, mPatternSize,
            mCorners, Calib3d.CALIB_CB_ASYMMETRIC_GRID);
    if (!mPatternWasFound) {
        isChessboard = true;
        mPatternWasFound = Calib3d.findChessboardCorners(grayFrame, mPatternSize2,
                mCorners, Calib3d.CALIB_CB_NORMALIZE_IMAGE + Calib3d.CALIB_CB_ADAPTIVE_THRESH + Calib3d.CALIB_CB_FAST_CHECK);
    }

}

 

2.求得到角點會在後面轉爲畸變矩陣存儲mDistortionCoefficients,以備反畸變算法調用。核心函數是calibrateCamera

public void calibrate() {
    ArrayList<Mat> rvecs = new ArrayList<Mat>();
    ArrayList<Mat> tvecs = new ArrayList<Mat>();
    Mat reprojectionErrors = new Mat();
    ArrayList<Mat> objectPoints = new ArrayList<Mat>();
    if (isChessboard){
        objectPoints.add(Mat.zeros(mCornersSize2, 1, CvType.CV_32FC3));
    }else {
        objectPoints.add(Mat.zeros(mCornersSize, 1, CvType.CV_32FC3));
    }
    calcBoardCornerPositions(objectPoints.get(0));
    for (int i = 1; i < mCornersBuffer.size(); i++) {
        objectPoints.add(objectPoints.get(0));
    }

    Calib3d.calibrateCamera(objectPoints, mCornersBuffer, mImageSize,
            mCameraMatrix, mDistortionCoefficients, rvecs, tvecs, mFlags);

    mIsCalibrated = Core.checkRange(mCameraMatrix)
            && Core.checkRange(mDistortionCoefficients);

    mRms = computeReprojectionErrors(objectPoints, rvecs, tvecs, reprojectionErrors);
    Log.i(TAG, String.format("Average re-projection error: %f", mRms));
    Log.i(TAG, "Camera matrix: " + mCameraMatrix.dump());
    Log.i(TAG, "Distortion coefficients: " + mDistortionCoefficients.dump());
}

3.最後使用反畸變函數undistort把校正後的圖像還原。

public Mat render(CvCameraViewFrame inputFrame) {
    Mat renderedFrame = new Mat(inputFrame.rgba().size(), inputFrame.rgba().type());
    Imgproc.undistort(inputFrame.rgba(), renderedFrame,
            mCalibrator.getCameraMatrix(), mCalibrator.getDistortionCoefficients());

    return renderedFrame;
}

4兩種算法的標定比較,兩種方法是獨立的,都可以達到標定的目的,棋盤紙的方法比較比較慢,圓圈陣列比較快,在低端手機上校正,可以使用圓圈陣列。

 

5.源碼下載地址:

https://github.com/blogercn/CameraCalibration

 使用方法,代碼編繹APP裝入手機中

校正前校正前畸變十分嚴重,方形屏幕成了流體體



棋盤紙校正



圓圈陣列校正

校正後


前後對比



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