圖像畸變校正常用于計算機視覺、攝影測量學和機器人導航等領域,能夠修正因鏡頭光學特性或傳感器排列問題導致的圖像失真。下面我將介紹幾種常用的圖像畸變校正算法,并提供Python實現和測試用例。
常用算法及Python實現
1. 徑向畸變校正
徑向畸變是最常見的畸變類型,表現為圖像中心區域正常,邊緣區域出現拉伸或壓縮。校正公式如下:
import numpy as np
import cv2
from matplotlib import pyplot as pltdef correct_radial_distortion(image, k1, k2, k3=0):"""校正圖像的徑向畸變參數:image: 輸入的畸變圖像k1, k2, k3: 徑向畸變系數返回:corrected_image: 校正后的圖像"""h, w = image.shape[:2]# 創建網格坐標x, y = np.meshgrid(np.arange(w), np.arange(h))x_c, y_c = w / 2, h / 2 # 圖像中心# 計算離中心的距離r = np.sqrt((x - x_c)**2 + (y - y_c)**2)# 徑向畸變校正公式x_distorted = (x - x_c) * (1 + k1 * r**2 + k2 * r**4 + k3 * r**6) + x_cy_distorted = (y - y_c) * (1 + k1 * r**2 + k2 * r**4 + k3 * r**6) + y_c# 使用雙線性插值進行重采樣corrected_image = np.zeros_like(image)# 處理整數坐標x_distorted_int = np.clip(x_distorted.astype(int), 0, w - 1)y_distorted_int = np.clip(y_distorted.astype(int), 0, h - 1)# 應用校正if len(image.shape) == 3: # 彩色圖像corrected_image[y, x] = image[y_distorted_int, x_distorted_int]else: # 灰度圖像corrected_image[y, x] = image[y_distorted_int, x_distorted_int]return corrected_image# 測試用例
def test_radial_distortion():# 創建測試圖像(棋盤格)test_image = np.zeros((400, 400), dtype=np.uint8)for i in range(8):for j in range(8):if (i + j) % 2 == 0:test_image[i*50:(i+1)*50, j*50:(j+1)*50] = 255# 引入徑向畸變(k1=0.00005, k2=0.0000002)distorted_image = correct_radial_distortion(test_image, 0.00005, 0.0000002)# 校正徑向畸變corrected_image = correct_radial_distortion(distorted_image, -0.00005, -0.0000002)# 顯示結果plt.figure(figsize=(15, 5))plt.subplot(131), plt.imshow(test_image, cmap='gray')plt.title('原始圖像'), plt.axis('off')plt.subplot(132), plt.imshow(distorted_image, cmap='gray')plt.title('畸變圖像'), plt.axis('off')plt.subplot(133), plt.imshow(corrected_image, cmap='gray')plt.title('校正圖像'), plt.axis('off')plt.show()# 運行測試
test_radial_distortion()
2. 切向畸變校正
切向畸變是由于鏡頭與圖像傳感器不平行引起的,表現為圖像局部區域的傾斜。校正公式如下:
def correct_tangential_distortion(image, p1, p2):"""校正圖像的切向畸變參數:image: 輸入的畸變圖像p1, p2: 切向畸變系數返回:corrected_image: 校正后的圖像"""h, w = image.shape[:2]# 創建網格坐標x, y = np.meshgrid(np.arange(w), np.arange(h))x_c, y_c = w / 2, h / 2 # 圖像中心# 計算離中心的距離r = np.sqrt((x - x_c)**2 + (y - y_c)**2)# 切向畸變校正公式x_distorted = (x - x_c) + (2 * p1 * (x - x_c) * (y - y_c) + p2 * (r**2 + 2 * (x - x_c)**2)) + x_cy_distorted = (y - y_c) + (p1 * (r**2 + 2 * (y - y_c)**2) + 2 * p2 * (x - x_c) * (y - y_c)) + y_c# 使用雙線性插值進行重采樣corrected_image = np.zeros_like(image)# 處理整數坐標x_distorted_int = np.clip(x_distorted.astype(int), 0, w - 1)y_distorted_int = np.clip(y_distorted.astype(int), 0, h - 1)# 應用校正if len(image.shape) == 3: # 彩色圖像corrected_image[y, x] = image[y_distorted_int, x_distorted_int]else: # 灰度圖像corrected_image[y, x] = image[y_distorted_int, x_distorted_int]return corrected_image# 測試用例
def test_tangential_distortion():# 創建測試圖像(棋盤格)test_image = np.zeros((400, 400), dtype=np.uint8)for i in range(8):for j in range(8):if (i + j) % 2 == 0:test_image[i*50:(i+1)*50, j*50:(j+1)*50] = 255# 引入切向畸變(p1=0.001, p2=0.0008)distorted_image = correct_tangential_distortion(test_image, 0.001, 0.0008)# 校正切向畸變corrected_image = correct_tangential_distortion(distorted_image, -0.001, -0.0008)# 顯示結果plt.figure(figsize=(15, 5))plt.subplot(131), plt.imshow(test_image, cmap='gray')plt.title('原始圖像'), plt.axis('off')plt.subplot(132), plt.imshow(distorted_image, cmap='gray')plt.title('畸變圖像'), plt.axis('off')plt.subplot(133), plt.imshow(corrected_image, cmap='gray')plt.title('校正圖像'), plt.axis('off')plt.show()# 運行測試
test_tangential_distortion()
3. 使用OpenCV進行相機標定與畸變校正
實際應用中,通常使用OpenCV提供的相機標定功能來自動計算畸變系數:
def camera_calibration_and_undistortion():"""使用OpenCV進行相機標定和圖像畸變校正"""# 準備對象點,如 (0,0,0), (1,0,0), (2,0,0) ..., (7,5,0)objp = np.zeros((6*8, 3), np.float32)objp[:, :2] = np.mgrid[0:8, 0:6].T.reshape(-1, 2)# 存儲對象點和圖像點的數組objpoints = [] # 3D點在現實世界中的坐標imgpoints = [] # 2D點在圖像平面中的坐標# 生成模擬標定圖像(通常需要使用多幅圖像)images = []for i in range(5):img = np.zeros((480, 640), dtype=np.uint8)# 生成模擬的棋盤格角點corners = np.zeros((48, 2), dtype=np.float32)for j in range(48):x = 50 + (j % 8) * 60 + np.random.randint(-5, 6) # 添加隨機畸變y = 50 + (j // 8) * 60 + np.random.randint(-5, 6)corners[j] = [x, y]imgpoints.append(corners)objpoints.append(objp)# 在圖像上繪制角點for corner in corners:cv2.circle(img, (int(corner[0]), int(corner[1])), 5, 255, -1)images.append(img)# 相機標定ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, images[0].shape[::-1], None, None)# 生成測試圖像test_img = np.zeros((480, 640), dtype=np.uint8)for i in range(8):for j in range(6):cv2.circle(test_img, (100 + i * 60, 100 + j * 60), 10, 255, -1)# 畸變校正h, w = test_img.shape[:2]newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (w, h), 1, (w, h))undistorted_img = cv2.undistort(test_img, mtx, dist, None, newcameramtx)# 顯示結果plt.figure(figsize=(10, 5))plt.subplot(121), plt.imshow(test_img, cmap='gray')plt.title('畸變圖像'), plt.axis('off')plt.subplot(122), plt.imshow(undistorted_img, cmap='gray')plt.title('校正圖像'), plt.axis('off')plt.show()# 返回標定結果return mtx, dist# 運行相機標定和畸變校正
camera_matrix, distortion_coeffs = camera_calibration_and_undistortion()
print("相機內參矩陣:\n", camera_matrix)
print("畸變系數:\n", distortion_coeffs)
算法解釋
-
徑向畸變校正:
- 徑向畸變是最常見的畸變類型,表現為圖像中心區域正常,邊緣區域出現拉伸或壓縮。
- 校正公式基于多項式模型,通過徑向畸變系數(k1, k2, k3)來調整像素位置。
-
切向畸變校正:
- 切向畸變是由于鏡頭與圖像傳感器不平行引起的,表現為圖像局部區域的傾斜。
- 校正公式使用切向畸變系數(p1, p2)來調整像素位置。
-
相機標定與OpenCV實現:
- 實際應用中,通常使用已知的標定板(如棋盤格)來計算相機的內參矩陣和畸變系數。
- OpenCV提供了完整的相機標定和畸變校正功能,能夠自動計算所有參數并進行圖像校正。
以上代碼實現了常見的圖像畸變校正算法,并提供了測試用例來驗證算法的有效性。在實際應用中,你可能需要根據具體的相機型號和場景來調整參數。