Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/303.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用openCV和Python将对象从一个图像映射到另一个图像_Python_Opencv_Image Processing_Camera Calibration - Fatal编程技术网

使用openCV和Python将对象从一个图像映射到另一个图像

使用openCV和Python将对象从一个图像映射到另一个图像,python,opencv,image-processing,camera-calibration,Python,Opencv,Image Processing,Camera Calibration,这是一个有关使用openCV(版本4.5.1.48)和Python(版本3.8.5)进行立体声校准和校正的问题 我在同一轴上放置了两个摄像头,如下图所示: 左(上)摄像机以640x480分辨率拍照,右(下)摄像机以320x240分辨率拍照。 目标是在右侧图像(320x240)上找到一个对象,然后在左侧图像(640x480)上裁剪出相同的对象。换言之;将构成右图像中对象的矩形传输到左图像。这一想法概述如下 在右图中发现了一个红色的物体,我需要把它的位置转移到左图中,然后裁剪出来。物体被放置在距

这是一个有关使用openCV(版本4.5.1.48)和Python(版本3.8.5)进行立体声校准和校正的问题

我在同一轴上放置了两个摄像头,如下图所示:

左(上)摄像机以640x480分辨率拍照,右(下)摄像机以320x240分辨率拍照。 目标是在右侧图像(320x240)上找到一个对象,然后在左侧图像(640x480)上裁剪出相同的对象。换言之;将构成右图像中对象的矩形传输到左图像。这一想法概述如下

在右图中发现了一个红色的物体,我需要把它的位置转移到左图中,然后裁剪出来。物体被放置在距离相机镜头30厘米的平面上。换言之;从两个摄像头镜头到平面的距离(深度)是恒定的(30cm)

这个主要问题是当两个摄像头并排放置时,当图像具有不同的分辨率时,以及当深度(相当)恒定时,如何将位置从一个图像转移到另一个图像。这不是一个寻找物体的问题

为了解决这个问题,据我所知,必须使用立体声校准,除此之外,我发现了以下文章/代码:

下面是我使用的校准模式示例:

我有25张左右摄像头校准模式的照片。图案为5x9,正方形尺寸为40x40 mm

根据我的知识,我编写了以下代码:

import numpy as np
import cv2
import glob

CALIL = "path-to-left-images"
CALIR = "path-to-right-images"

# Termination criterias
criteria1 = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
criteria2 = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 1e-5)

# Chessboard parameters
checker_size = 40.0         # Square size in world units (mm)
checker_pattern = (5, 9)    # 5 rows, 9 columns

# Flags
findChessboardCorners_flags = 0
#findChessboardCorners_flags |= cv2.CALIB_CB_ADAPTIVE_THRESH
#findChessboardCorners_flags |= cv2.CALIB_CB_NORMALIZE_IMAGE
#findChessboardCorners_flags |= cv2.CALIB_CB_FILTER_QUADS
#findChessboardCorners_flags |= cv2.CALIB_CB_FAST_CHECK

calibrateCamera_flags = 0
#calibrateCamera_flags |= cv2.CALIB_USE_INTRINSIC_GUESS
#calibrateCamera_flags |= cv2.CALIB_FIX_PRINCIPAL_POINT
#calibrateCamera_flags |= cv2.CALIB_FIX_ASPECT_RATIO
#calibrateCamera_flags |= cv2.CALIB_ZERO_TANGENT_DIST
#calibrateCamera_flags |= cv2.CALIB_FIX_K1 # K2, K3...K6
#calibrateCamera_flags |= cv2.CALIB_RATIONAL_MODEL
#calibrateCamera_flags |= cv2.CALIB_THIN_PRISM_MODEL
#calibrateCamera_flags |= cv2.CALIB_FIX_S1_S2_S3_S4
#calibrateCamera_flags |= cv2.CALIB_TILTED_MODEL
#calibrateCamera_flags |= cv2.CALIB_FIX_TAUX_TAUY

stereoCalibrate_falgs = 0
stereoCalibrate_falgs |= cv2.CALIB_FIX_INTRINSIC
#stereoCalibrate_falgs |= cv2.CALIB_USE_INTRINSIC_GUESS
#stereoCalibrate_falgs |= cv2.CALIB_USE_EXTRINSIC_GUESS
#stereoCalibrate_falgs |= cv2.CALIB_FIX_PRINCIPAL_POINT
#stereoCalibrate_falgs |= cv2.CALIB_FIX_FOCAL_LENGTH
#stereoCalibrate_falgs |= cv2.CALIB_FIX_ASPECT_RATIO
#stereoCalibrate_falgs |= cv2.CALIB_SAME_FOCAL_LENGTH
#stereoCalibrate_falgs |= cv2.CALIB_ZERO_TANGENT_DIST
#stereoCalibrate_falgs |= cv2.CALIB_FIX_K1 # K2, K3...K6
#stereoCalibrate_falgs |= cv2.CALIB_RATIONAL_MODEL
#stereoCalibrate_falgs |= cv2.CALIB_THIN_PRISM_MODEL
#stereoCalibrate_falgs |= cv2.CALIB_FIX_S1_S2_S3_S4
#stereoCalibrate_falgs |= cv2.CALIB_TILTED_MODEL
#stereoCalibrate_falgs |= cv2.CALIB_FIX_TAUX_TAUY

stereoRectify_flags = 0
stereoRectify_flags |= cv2.CALIB_ZERO_DISPARITY

# Prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
objp = np.zeros((1, checker_pattern[0] * checker_pattern[1], 3), np.float32)
objp[0, :, :2] = np.mgrid[0:checker_pattern[0],
                          0:checker_pattern[1]].T.reshape(-1, 2)*checker_size

# Arrays to store object points and image points from all the images.
objPoints = []      # 3d point in real world space
imgPointsL = []     # 2d points in image plane, left image (normal)
imgPointsR = []     # 2d points in image plane, right image (thermal)

# Get calibration images
# Get all left (normal) images from directory. Sort them
images_left = glob.glob(CALIL+'*')
images_left.sort()
# Get all right (thermal) images from directory. Sort them
images_right = glob.glob(CALIR+'*')
images_right.sort()

for left_img, right_img in zip(images_left, images_right):
    # Left object points
    imgL = cv2.imread(left_img)
    grayL = cv2.cvtColor(imgL, cv2.COLOR_BGR2GRAY)

    # Find the chessboard corners
    retL, cornersL = cv2.findChessboardCorners(
        grayL, (checker_pattern[0], checker_pattern[1]), findChessboardCorners_flags)

    # Right object points
    imgR = cv2.imread(right_img)
    grayR = cv2.cvtColor(imgR, cv2.COLOR_BGR2GRAY)

    # Find the chessboard corners
    retR, cornersR = cv2.findChessboardCorners(
        grayR, (checker_pattern[0], checker_pattern[1]), findChessboardCorners_flags)

    if retL and retR:
        # If found, add object points, image points (after refining them)
        objPoints.append(objp)
        
        # Left points
        cornersL2 = cv2.cornerSubPix(
            grayL, cornersL, (5, 5), (-1, -1), criteria1)
        imgPointsL.append(cornersL2)
        
        # Right points
        cornersR2 = cv2.cornerSubPix(
            grayR, cornersR, (5, 5), (-1, -1), criteria1)
        imgPointsR.append(cornersR2)

shapeL = grayL.shape[::-1]
shapeR = grayR.shape[::-1]

# Calibrate each camera separately
retL, K1, D1, R1, T1 = cv2.calibrateCamera(
    objPoints, imgPointsL, shapeL, None, None, flags=calibrateCamera_flags)
retR, K2, D2, R2, T2 = cv2.calibrateCamera(
    objPoints, imgPointsR, shapeR, None, None, flags=calibrateCamera_flags)

# Stereo calibrate
ret, K1, D1, K2, D2, R, T, E, F = cv2.stereoCalibrate(
    objPoints, imgPointsL, imgPointsR, K1, D1, K2, D2, shapeR, flags=calibrateCamera_flags, criteria=criteria2)

# Stereo rectify
R1, R2, P1, P2, Q, roi_left, roi_right = cv2.stereoRectify(
    K1, D1, K2, D2, shapeR, R, T, flags=stereoRectify_flags, alpha=1)

# Undistort images
leftMapX, leftMapY = cv2.initUndistortRectifyMap(
    K1, D1, R1, P1, shapeL, cv2.CV_32FC1)
rightMapX, rightMapY = cv2.initUndistortRectifyMap(
    K2, D2, R2, P2, shapeR, cv2.CV_32FC1)

# Remap
left_rectified = cv2.remap(images_left[0], leftMapX, leftMapY,
                           cv2.INTER_LINEAR, cv2.BORDER_CONSTANT)
right_rectified = cv2.remap(images_right[0], rightMapX, rightMapY,
                            cv2.INTER_LINEAR, cv2.BORDER_CONSTANT)
但我得到了一个坏结果:

我尝试了不同的标志,alpha参数,但没有任何效果

问题:

  • 当两幅图像的分辨率不同时,是否有可能进行立体校准并解决此问题
  • 一般工作流程是否正确,或者我是否遗漏了什么?旗帜?阿尔法参数?还有其他解决这个问题的方法吗
编辑

在Micha的精彩评论之后,我发现透视单应是(希望)解决这个问题的方法,而不是立体校准。这是因为需要找到的对象被放置在一个平面上,距离两个相机镜头(30厘米)的长度/深度恒定

基于新信息,我编写了以下代码,其中我使用了第一对图像来获得透视变换矩阵:

imgL = cv2.imread(images_left[0])
imgL = cv2.cvtColor(imgL, cv2.COLOR_BGR2GRAY)
imgR = cv2.imread(images_right[0])
imgR = cv2.cvtColor(imgR, cv2.COLOR_BGR2GRAY)

ret1, corners1 = cv2.findChessboardCorners(imgL, (checker_pattern[0], checker_pattern[1]))
cornersL2 = cv2.cornerSubPix(imgL, corners1, (5, 5), (-1, -1), criteria1)

ret2, corners2 = cv2.findChessboardCorners(imgR, (checker_pattern[0], checker_pattern[1]))
cornersR2 = cv2.cornerSubPix(imgR, corners2, (5, 5), (-1, -1), criteria1)

H, _ = cv2.findHomography(cornersL2, cornersR2)
基于透视变换矩阵H,我可以使用
cv2.warpPerspective()
函数基于右图像和校准板中的棋盘角扭曲左图像

但是,当我尝试扭曲它时,扭曲的图像(下面的上图)相对于另一个(下图)图像有点向右,如下图所示:

裁剪结果如下所示,其中面积不匹配:

我想我需要调整扭曲图像的大小,使其与右侧图像(320x240)的分辨率相同。扭曲图像的分辨率为640x240

问题:

  • 是否应将校准板放置在距相机镜头30厘米的位置,以优化透视变换矩阵的计算
  • 我有25张来自不同角度的校准板图像。是否需要使用所有图像,还是仅使用一个
  • 我正在使用
    cv2.warpPerspective()
    函数,但是裁剪不匹配。我应该使用其他功能吗

我通过使用以下openCV函数解决了这个问题:

  • cv2.findChessboardCorners()
  • cv2.cornerSubPix()
  • cv2.findHomography()
  • cv2.warpPerspective()
我在距离30厘米处使用校准板计算透视变换矩阵H。因此,我可以将对象从右图像映射到左图像。深度必须是恒定的(30厘米),虽然这有点问题,但在我的情况下是可以接受的


感谢@Mika提供了非常好的答案。

对于立体匹配,您通常会计算校正,从而使像素匹配更加容易。但是如果我理解正确的话,你只需要在两幅图像中找到单个点或一组(4)点。在你的情况下,我会寻找比立体校准更通用的方法。如果可以找到未校准图像的极线,则可以在极线上搜索相应的边界框位置。如果你已经有了两个相机的内部和外部,你甚至可以构建从相机中心穿过像素到场景的光线,并为输入找到相应的光线轨迹@Mika。是的,我想我需要在两个图像/摄像机之间进行某种平移、旋转和/或比例因子,这样就可以将一个对象从右图像映射到左图像。也就是说,可以这样做:
img=img[y:y+h,x:x+w]
,其中x、y、w和h是根据右图像上的对象找到的,然后正确地缩放到左图像。不可能有恒定的贴图,因为贴图取决于相机和对象之间的距离。计算两个相机的内部和外部应该和计算等分辨率相机的方法相同。好的,是的,这是有意义的。嗯,计算两个摄像头的内部和外部是用cv2.CalibleCamera完成的,对吗?嗯,好的。听你这么说有点伤心,不过还是要谢谢你的帮助。