鱼眼摄像头的畸变矫正方法-python+opencv
魚眼攝像頭畸變校正的方法:
1. 棋盤矯正法
2. 經緯度矯正法。
?
相機為什么會出現畸變?
當前相機的畸變主要分為徑向畸變和切向畸變兩種。
? ? 徑向畸變產生的原因:相機的光學鏡頭厚度不均勻,離鏡頭越遠場景的光線就越彎曲從而產生徑向畸變。
? ? 切向畸變產生的原因:鏡頭與圖像傳感器不完全平行造成的。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? ? ? 圖一? ?徑向畸變? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?圖二? 切向畸變
?
相機參數有哪些?
相機內參:主要包括相機矩陣(包括焦距,光學中心,這些都是相機本身屬性)和畸變系數(畸變數學模型的5個參數 D = {K1,K2,K3,P1,P2})。
相機外參:通過旋轉和平移將實際場景3D映射到相機的2D坐標過程中的旋轉和平移就是外參。(他描述的是世界坐標轉化成相機坐標的過程)
相機的標定流程
? ? ? 相機標定流程就是4個坐標系在轉換過程中求出計算機的外參和內參的過程。四個坐標系分別是:世界坐標系(真實的實際場景),相機坐標系(攝像頭鏡頭中心),圖像坐標系(圖像傳感器成像中心,圖片中心,影布中心),像素坐標系(圖像左上角為原點)。如圖三所示,O1是圖像坐標系,O0 是像素坐標系,兩者之間的區別只是原點發生了變化。? ?
世界坐標系 -》相機坐標系? ? ?求解外參(旋轉和平移)
相機坐標系 -》圖像坐標系? ? ?求解內參(攝像頭矩陣,畸變系數)
圖像坐標系 -》像素坐標系? ? ?求解像素轉化矩陣(可簡單理解為原點從圖片中心到左上角,單位厘米變行列)
? ? ? 圖三? 圖像坐標系和像素坐標系
一、基于棋盤的相機畸變校正方法
打印棋盤并采集魚眼攝像頭下的棋盤圖片:
1. 棋盤獲取:鏈接: https://pan.baidu.com/s/14qB3kQ_MbWORay1i0GFm1A 提取碼: ksqw 復制這段內容后打開百度網盤手機App,操作更方便哦
2. 采集圖片,采集圖片如下圖所示,可以多采集一些,標注的會更加準確。
? ? ? ?? ? ?
3. 使用采集的圖片求出相機的內參和矯正系數(DIM, K, D),然后使用得到的(DIM, K, D)再進行測試,代碼如下。
import cv2 import numpy as np import globdef get_K_and_D(checkerboard, imgsPath):CHECKERBOARD = checkerboardsubpix_criteria = (cv2.TERM_CRITERIA_EPS+cv2.TERM_CRITERIA_MAX_ITER, 30, 0.1)calibration_flags = cv2.fisheye.CALIB_RECOMPUTE_EXTRINSIC+cv2.fisheye.CALIB_CHECK_COND+cv2.fisheye.CALIB_FIX_SKEWobjp = np.zeros((1, CHECKERBOARD[0]*CHECKERBOARD[1], 3), np.float32)objp[0,:,:2] = np.mgrid[0:CHECKERBOARD[0], 0:CHECKERBOARD[1]].T.reshape(-1, 2)_img_shape = Noneobjpoints = []imgpoints = []images = glob.glob(imgsPath + '/*.png')for fname in images:img = cv2.imread(fname)if _img_shape == None:_img_shape = img.shape[:2]else:assert _img_shape == img.shape[:2], "All images must share the same size."gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)ret, corners = cv2.findChessboardCorners(gray, CHECKERBOARD,cv2.CALIB_CB_ADAPTIVE_THRESH+cv2.CALIB_CB_FAST_CHECK+cv2.CALIB_CB_NORMALIZE_IMAGE)if ret == True:objpoints.append(objp)cv2.cornerSubPix(gray,corners,(3,3),(-1,-1),subpix_criteria)imgpoints.append(corners)N_OK = len(objpoints)K = np.zeros((3, 3))D = np.zeros((4, 1))rvecs = [np.zeros((1, 1, 3), dtype=np.float64) for i in range(N_OK)]tvecs = [np.zeros((1, 1, 3), dtype=np.float64) for i in range(N_OK)]rms, _, _, _, _ = cv2.fisheye.calibrate(objpoints,imgpoints,gray.shape[::-1],K,D,rvecs,tvecs,calibration_flags,(cv2.TERM_CRITERIA_EPS+cv2.TERM_CRITERIA_MAX_ITER, 30, 1e-6))DIM = _img_shape[::-1]print("Found " + str(N_OK) + " valid images for calibration")print("DIM=" + str(_img_shape[::-1]))print("K=np.array(" + str(K.tolist()) + ")")print("D=np.array(" + str(D.tolist()) + ")")return DIM, K, Ddef undistort(img_path,K,D,DIM,scale=0.6,imshow=False):img = cv2.imread(img_path)dim1 = img.shape[:2][::-1] #dim1 is the dimension of input image to un-distortassert dim1[0]/dim1[1] == DIM[0]/DIM[1], "Image to undistort needs to have same aspect ratio as the ones used in calibration"if dim1[0]!=DIM[0]:img = cv2.resize(img,DIM,interpolation=cv2.INTER_AREA)Knew = K.copy()if scale:#change fovKnew[(0,1), (0,1)] = scale * Knew[(0,1), (0,1)]map1, map2 = cv2.fisheye.initUndistortRectifyMap(K, D, np.eye(3), Knew, DIM, cv2.CV_16SC2)undistorted_img = cv2.remap(img, map1, map2, interpolation=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT)if imshow:cv2.imshow("undistorted", undistorted_img)return undistorted_imgif __name__ == '__main__':# 開始使用圖片來獲取內參和畸變系數DIM, K, D = get_K_and_D((6,9), '')# 得到內參和畸變系數畸變矯正進行測試'''DIM=(2560, 1920)K=np.array([[652.8609862494474, 0.0, 1262.1021584894233], [0.0, 653.1909758659955, 928.0871455436396], [0.0, 0.0, 1.0]])D=np.array([[-0.024092199861108887], [0.002745976275100771], [0.002545415522352827], [-0.0014366825722748522]])img = undistort('../imgs/pig.jpg',K,D,DIM)cv2.imwrite('../imgs/pig_checkerboard.jpg', img)'''二、基于經緯度的矯正方法
1. 算法原理:經緯度矯正法, 可以把魚眼圖想象成半個地球, 然后將地球展開成地圖,經緯度矯正法主要是利用幾何原理, 對圖像進行展開矯正。(此算法操作簡單不需要使用棋盤來進行數據采集)
2. 代碼實現:
import cv2 import numpy as np import time# 魚眼有效區域截取 def cut(img):img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)(_, thresh) = cv2.threshold(img_gray, 20, 255, cv2.THRESH_BINARY)contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)cnts = sorted(contours, key=cv2.contourArea, reverse=True)[0]x,y,w,h = cv2.boundingRect(cnts)r = max(w/ 2, h/ 2)# 提取有效區域img_valid = img[y:y+h, x:x+w]return img_valid, int(r)# 魚眼矯正 def undistort(src,r):# r: 半徑, R: 直徑R = 2*r# Pi: 圓周率Pi = np.pi# 存儲映射結果dst = np.zeros((R, R, 3))src_h, src_w, _ = src.shape# 圓心x0, y0 = src_w//2, src_h//2# 數組, 循環每個點range_arr = np.array([range(R)])theta = Pi - (Pi/R)*(range_arr.T)temp_theta = np.tan(theta)**2phi = Pi - (Pi/R)*range_arrtemp_phi = np.tan(phi)**2tempu = r/(temp_phi + 1 + temp_phi/temp_theta)**0.5tempv = r/(temp_theta + 1 + temp_theta/temp_phi)**0.5# 用于修正正負號flag = np.array([-1] * r + [1] * r)# 加0.5是為了四舍五入求最近點u = x0 + tempu * flag + 0.5v = y0 + tempv * np.array([flag]).T + 0.5# 防止數組溢出u[u<0]=0u[u>(src_w-1)] = src_w-1v[v<0]=0v[v>(src_h-1)] = src_h-1# 插值dst[:, :, :] = src[v.astype(int),u.astype(int)]return dstif __name__ == "__main__":t = time.perf_counter()frame = cv2.imread('../imgs/pig.jpg')cut_img,R = cut(frame)t = time.perf_counter()result_img = undistort(cut_img,R)cv2.imwrite('../imgs/pig_vector_nearest.jpg',result_img)print(time.perf_counter()-t)?
感謝一下幾位大佬資源支持:
https://blog.csdn.net/hpuhjl/article/details/80899931
https://blog.csdn.net/waeceo/article/details/50580808
https://zhuanlan.zhihu.com/p/55648494
http://www.expoon.com/wenda/20180427218.html
總結
以上是生活随笔為你收集整理的鱼眼摄像头的畸变矫正方法-python+opencv的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: js网易云歌词解析处理,
- 下一篇: Python实战HSV颜色模型——提取像