opencv鱼眼镜头矫正

说明

鱼眼镜头是一种视场角很大的镜头,但是得到的图片有很大的畸变,所以需要对鱼眼镜头进行标定,标定所得的参数可以对鱼眼镜头的图像进行矫正。

下图来自opencv的文档。其中c是鱼眼镜头原图,a和b是不同的矫正方法得到的图片。
在这里插入图片描述
从OpenCV 3.0开始,OpenCV包含了cv2.fisheye包用来处理鱼眼镜头的矫正。
据《鱼眼相机成像模型》这篇文章所讲,opencv也只是实现了众多鱼眼镜头模型中的一种,是由Kannala提出的一种鱼眼相机的一般近似模型。

矫正步骤

关于使用opencv矫正鱼眼镜头的步骤和代码,github上很多,其中外网的一篇《Calibrate fisheye lens using OpenCV—part 1》很不错,但是貌似打不开了,我在一个国内的哥们的github项目上看到了pdf版,需要的自取:HLearning/fisheye

矫正鱼眼镜头分为2步:

  1. 标定镜头的2个内参。OpenCV中称作K(内参矩阵)和D(畸变系数)。
  2. 通过使用K和D矫正图片

为了得到k和d, 一般都是使用“张正友标定法”,也就是使用摄像头拍摄一批棋盘格的图片来计算K/D。学个矫正我还要买个镜头,打印棋盘格,还要拍照,好多人估计想到这就想放弃了。
别急,《sourishg/fisheye-stereo-calibration》这个gitgub项目里有拍好的图片,拿过来直接用就可以,
项目里有left和right俩镜头的图片,我只需要一个,选了left。注意这个项目是c++的,我只是用他的图片,代码来自别处。
在这里插入图片描述

镜头标定

我用的这个github的开源代码修改的:lengkujiaai/Calibrate-fisheye-lens-using-OpenCV

将代码保存为calibrate.py,和标定图片放在一个目录下执行,生成的K和D会打印到屏幕上。

我的代码如下:

import cv2
assert cv2.__version__[0] >= '3', 'The fisheye module requires opencv version >= 3.0.0'
import numpy as np
import os
import glob
CHECKERBOARD = (6,9)
subpix_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_SKEW
objp = 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 = None
objpoints = [] # 3d point in real world space
imgpoints = [] # 2d points in image plane.
images = glob.glob('*.jpg')
imgcnt=0
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)
    # Find the chess board corners
    imgcnt+=1
    ret, corners = cv2.findChessboardCorners(gray, CHECKERBOARD, cv2.CALIB_CB_ADAPTIVE_THRESH+cv2.CALIB_CB_FAST_CHECK+cv2.CALIB_CB_NORMALIZE_IMAGE)
    # If found, add object points, image points (after refining them)
    if ret == True:
        objpoints.append(objp)
        cv2.cornerSubPix(gray,corners,(3,3),(-1,-1),subpix_criteria)
        imgpoints.append(corners)
    else:
        print(fname, "findChessboardCorners failed")
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)
    )
print("imgcnt:", imgcnt)
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()) + ")")

这个代码需要修改的参数主要是"CHECKERBOARD = (6,9)"这里,需要根据棋盘格实际的角点数来。角点在哪呢?下面 是可视化后的结果,相信不难数。
在这里插入图片描述
上述代码执行输出:

imgcnt: 29
Found 29 valid images for calibration
DIM=(960, 600)
K=np.array([[227.37445013320539, 0.0, 471.44988103922896], [0.0, 226.54869118283946, 305.68361664835436], [0.0, 0.0, 1.0]])
D=np.array([[0.025348291552841663], [-0.025433974064838705], [0.022414488170602896], [-0.00804494586747774]])

其中K和D是我们下一步矫正需要的参数。

矫正图片

K和D是为了求解remap matrix,具体到之后的代码中就是map1和map2两个变量。他们满足“map1[i, j]=m 和 map2[i, j]=n”,表示 矫正后的第i行、第j列的像素值,等于原始图片的第n行、第m列的像素,其中m, n允许是非整数 。

# You should replace these 3 lines with the output in calibration step
import numpy as np
import cv2
import sys
import os
import glob

# DIM=(1280, 720)
# K=np.array([[-31190.47191209647, -0.0, 667.330647269763], [0.0, -14405.222579044883, 80.68167531658455], [0.0, 0.0, 1.0]])
# D=np.array([[152.50098302679038], [-150.36440309694163], [83.13957034501341], [-39.63732437907149]])

DIM=(960, 600)
K=np.array([[227.37445013320539, 0.0, 471.44988103922896], [0.0, 226.54869118283946, 305.68361664835436], [0.0, 0.0, 1.0]])
D=np.array([[0.025348291552841663], [-0.025433974064838705], [0.022414488170602896], [-0.00804494586747774]])


def undistort(img_path, out_path):
    img = cv2.imread(img_path)
    h,w = img.shape[:2]
    map1, map2 = cv2.fisheye.initUndistortRectifyMap(K, D, np.eye(3), K, DIM, cv2.CV_16SC2)
    undistorted_img = cv2.remap(img, map1, map2, interpolation=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT)
    #cv2.imshow("undistorted", undistorted_img)
    cv2.imwrite(out_path,undistorted_img)
    #cv2.waitKey(0)
    #cv2.destroyAllWindows()
if __name__ == '__main__':
    print("sys.argv[0]", sys.argv[0])
    print("sys.argv[1]", sys.argv[1])
    # print("sys.argv[1]", sys.argv[1])
    print("sys.argv[1:]", sys.argv[1:])

    # input_path=os.path(sys.argv[1])
    # out_path=os.path(sys.argv[2])

    glob_str=os.path.join(sys.argv[1], "*.jpg")
    print("glob_str:", glob_str)
    images=glob.glob(glob_str)

    for img in images:
        print("input", img)
        out_img=os.path.join(sys.argv[2], os.path.basename(img))
        print("out_img", out_img)
        undistort(img, out_img)

矫正前后的的对比:
在这里插入图片描述

可以看到,矫正后的图片被裁剪了,只保留了中间的部分。这是因为越靠近边缘矫正后拉伸越明显,用过汽车360影像的应该都知道是啥意思。

《Calibrate fisheye lens using OpenCV—part 2》里保留全部图片的方法我没走通,我参考《关于C ++:OpenCV鱼眼校准会剪切太多的结果图像》这里的方法,可以得到一个完整的图像,但是效果感觉怪怪的:
在这里插入图片描述

参考资料

鱼眼相机成像模型

lengkujiaai/Calibrate-fisheye-lens-using-OpenCV

sourishg/fisheye-stereo-calibration

HLearning/fisheye

一文看透鱼眼相机的畸变矫正,以及目标检测应用

关于C ++:OpenCV鱼眼校准会剪切太多的结果图像

### 回答1: 鱼眼畸变是由鱼眼相机广角镜头的特性引起的一种畸变现象。在图像中,直线变得弯曲并且物体的边缘拉伸。 OpenCV提供了一种用于鱼眼畸变矫正的函数,称为`cv2.fisheye.undistortImage()`。该函数可以将畸变图像转换为非畸变的图像。 使用该函数需要提供畸变图像、相机的内参矩阵和畸变参数。内参矩阵包括焦距和光学中心等参数,通常通过相机标定得到。畸变参数包括径向畸变和切向畸变等,同样也需要通过相机标定获得。 以下是使用OpenCV进行鱼眼畸变矫正的主要步骤: 1. 读取畸变图像和相机的内参矩阵和畸变参数。 2. 创建输出图像的尺寸和类型。 3. 调用`cv2.fisheye.undistortImage()`函数,传入畸变图像、内参矩阵和畸变参数,以及输出图像。 4. 显示和保存矫正后的图像。 需要注意的是,畸变矫正的效果取决于相机的标定质量和参数的准确性。在进行鱼眼畸变矫正之前,最好对相机进行标定,以获取准确的内参矩阵和畸变参数。 OpenCV鱼眼畸变矫正功能可以广泛应用于计算机视觉和图像处理领域,例如机器人导航、三维重建和全景图像拼接等。 ### 回答2: 鱼眼畸变矫正是一种在计算机视觉中常用的技术,可以通过对图片进行处理,将鱼眼相机拍摄的图像转换为透视图像,使图像中的直线保持直线,更符合人眼看到的实际情况。 OpenCV是一个开源的计算机视觉库,提供了许多图像处理和计算机视觉相关的函数和工具。在OpenCV中,也提供了鱼眼畸变矫正的函数来实现这一功能。 鱼眼畸变矫正的过程通常分为两步:参数估计和图像转换。 参数估计阶段主要是根据鱼眼相机的特性,估计出畸变的参数。OpenCV提供了一些函数,如`findChessboardCorners`和`calibrateCamera`等,可以通过拍摄棋盘格样板并基于棋盘格图像的角点位置,估计相机的标定矩阵和畸变系数。 图像转换阶段使用估计出的参数,对图像进行畸变矫正OpenCV提供了函数`undistort`来完成这个任务。该函数接受源图像、畸变参数和标定矩阵作为输入,并输出矫正后的图像。 使用OpenCV进行鱼眼畸变矫正的步骤如下:首先,使用相机拍摄一系列棋盘格图片,并检测角点位置。然后,利用检测到的角点位置和已知的棋盘格尺寸,使用`calibrateCamera`函数估计相机的标定矩阵和畸变系数。最后,对要矫正的图像应用`undistort`函数,得到畸变校正后的图像。 通过OpenCV提供的鱼眼畸变矫正功能,我们可以清晰地看到鱼眼相机拍摄的图像中的物体和线条,使其更加符合真实的显示效果。 ### 回答3: OpenCV是一个开源的计算机视觉库,其中包含了很多图像处理和计算机视觉算法。其中一个功能是鱼眼畸变矫正。 在摄影中,鱼眼镜头是一种广角镜头,能够拍摄到非常宽广的景象。然而,鱼眼镜头会引入一种畸变,使得图像中的直线变为弯曲的弧线。这种畸变使图像在某些任务中变得不可用,因此鱼眼畸变矫正就变得十分重要。 鱼眼畸变矫正算法主要包括以下几个步骤: 1. 读取鱼眼图像:使用OpenCV的函数读取待处理的鱼眼图像。 2. 相机参数估计:根据鱼眼图像的特性,使用OpenCV的函数估计相机畸变参数。这些参数包括焦距、主点和径向畸变系数等。 3. 畸变矫正:使用OpenCV的函数根据相机参数对图像进行畸变矫正处理。这个过程会根据畸变模型对图像进行重新映射,使得直线变为直线而不再弯曲。 4. 输出结果:保存或者显示经过畸变矫正后的图像。可以使用OpenCV的函数将图像保存到文件中,或者直接显示处理结果。 总结来说,OpenCV提供了强大的鱼眼畸变矫正功能,可以通过估计相机参数和对图像进行畸变矫正来减少或消除鱼眼镜头引入的畸变,从而得到更加准确和可靠的图像。这种算法在计算机视觉和机器人领域有广泛的应用。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值