[OpenCV]Camera Calibration(카메라 왜곡 펴기)

사용 환경 : Ubuntu Linux 18.04 LTS, Python 3.7.7
OpenCV Version = 4.2.0.34

2020/5/3 - [OpenCV] Camera Calibration 2 (카메라 구멍 없이 왜곡 펴기)

1.  Chessboard image

wc = 10  ## 체스 보드 가로 패턴 개수 - 1
hc = 7  ## 체스 보드 세로 패턴 개수 - 1

wc = 10, hc = 7

2. drawChessboardCorners

objp = np.zeros((wc * hc, 3), np.float32)
objp[:, :2] = np.mgrid[0:wc, 0:hc].T.reshape(-1, 2)

objpoints = []
imgpoints = []

img = cv2.imread(file) ## 체스 보드 이미지
_img = cv2.resize(img, dsize = (640, 480), interpolation = cv2.INTER_AREA)
gray = cv2.cvtColor(_img, cv2.COLOR_BGR2GRAY)

ret, corners = cv2.findChessboardCorners(gray, (wc, hc), None)

if ret == True:
    objpoints.append(objp)

    corners2 = cv2.cornerSubPix(gray, corners, (10, 10), (-1, -1), criteria)
    imgpoints.append(corners2)

    ## 찾은 코너 점들을 이용해 체스 보드 이미지에 그려넣는다
    img = cv2.drawChessboardCorners(_img, (wc, hc), corners2, ret)

cv2.findChessboardCorners(image, patternSize[, corners[, flags]]) → retval, corners

image - 8비트 grayscale이거나 color image
patternSize - 체스보드 row, column
corners - 코너를 찾으면 array로 return

만약 ret값이 False라면, 체스 보드 이미지의 패턴 개수를 맞게 했는지 확인하거나 (wc, hc) 체스 보드가 깔끔하게 나온 이미지를 가져와야 한다.

cv.cornerSubPix(image, corners, win, zero_zone, criteria)

Canny86 알고리즘(중심 q에서 p 주변 부근에 있는 지점까지의 모든 벡터가 이미지 및 측정 노이즈 q와 p에 따라 이미지 기울기와 직교한다.)으로 도형이 겹치는 코너 점을 찾는다.

cv2.drawChessboardCorners(image, patternSize, corners, patternWasFound)

cornerSubpix에서 return 받은 array를 corners에 넣고 ret값을 patternWasFound에 넣으면 빨간색 원 또는 보드를 찾은 경우 선으로 연결된 컬러 모서리로 감지 된 개별 체스 판 모서리를 그려준다.

3. undistort without getOptimalNewCameraMatrix

4. undistort with getOptimalNewCameraMatrix

cv2.getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, imageSize, alpha[, newImgSize[, centerPrincipalPoint]])→ retval, validPixROI

cameraMatrix = getOptimalNewCameraMatrix parameter alpha 
distCoeffs = Free scaling parameter 
alpha = between 0 (when all the pixels in the undistorted image are valid) and 1 (when all the source image pixels are retained in the undistorted image)
-> 1에 가까울수록 왜곡을 펼 때 잘라낸 부분들을 더 보여준다.
-> 전체를 보고 싶다면 1, 펴진 부분만 보고 싶다면 0에 가깝게 인자 값을 주면 된다.

alpha == 0                                                                                       alpha == 1

다음 글에서는 구멍이 뚫리지 않게 왜곡된 이미지를 펴는 방법에 대해 알려드리겠습니다.

5. 코드

import numpy as np
import cv2

criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
wc = 10  ## 체스 보드 가로 패턴 개수 - 1
hc = 7  ## 체스 보드 세로 패턴 개수 - 1
objp = np.zeros((wc * hc, 3), np.float32)
objp[:, :2] = np.mgrid[0:wc, 0:hc].T.reshape(-1, 2)

objpoints = []
imgpoints = []

file = 'C:\\Users\\bit\\Downloads\\new test.png'  ## 체스 보드 이미지
dist_file = 'C:\\Users\\bit\\Downloads\\lane_test.png'  ## 왜곡된 이미지 (같은 화각으로 찍은 이미지)

img = cv2.imread(file)
_img = cv2.resize(img, dsize = (640, 480), interpolation = cv2.INTER_AREA)
# cv2.imshow('img', _img)
gray = cv2.cvtColor(_img, cv2.COLOR_BGR2GRAY) ## gray scale로 바꾸기
# cv2.waitKey(0)

ret, corners = cv2.findChessboardCorners(gray, (wc, hc), None)  ## 체스 보드 찾기
print(ret) 
## 만약 ret값이 False라면, 체스 보드 이미지의 패턴 개수를 맞게 했는지 확인하거나 (wc, hc)
체스 보드가 깔끔하게 나온 이미지를 가져와야 한다

if ret == True:
    objpoints.append(objp)

    corners2 = cv2.cornerSubPix(gray, corners, (10, 10), (-1, -1), criteria) ## Canny86 알고리즘으로
    도형이 겹치는 코너 점을 찾는다
    imgpoints.append(corners2)

    ## 찾은 코너 점들을 이용해 체스 보드 이미지에 그려넣는다
    img = cv2.drawChessboardCorners(_img, (wc, hc), corners2, ret)
    # cv2.imshow('img', img)

    ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)  ## 왜곡 펴기
    h, w = img.shape[:2]
    newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (w, h), 1)
    ## mtx = getOptimalNewCameraMatrix parameter alpha 
    ## dist = Free scaling parameter 
    ## 4번째 인자 = between 0 (when all the pixels in the undistorted image are valid) and 1 (when all the source image pixels are retained in the undistorted image)
    ## 1에 가까울수록 왜곡을 펼 때 잘라낸 부분들을 더 보여준다
    ## 전체를 보고 싶다면 1, 펴진 부분만 보고 싶다면 0에 가깝게 인자 값을 주면 된다
    dst = cv2.undistort(img, mtx, dist) ## getOptimalNewCameraMatrix 함수를 쓰지 않은 이미지
    dst2 = cv2.undistort(img, mtx, dist, None, newcameramtx) ## 함수를 쓴 이미지
    cv2.imshow('num1', dst)
    cv2.imshow('num2', dst2)
    cv2.waitKey(0)

cv2.destroyAllWindows()

'OpenCV > OpenCV' 카테고리의 다른 글

[OpenCV]차선 인식  (2) 2020.05.26
[OpenCV] Camera Calibration 2 (카메라 구멍 없이 왜곡 펴기)  (3) 2020.05.03