代码之家  ›  专栏  ›  技术社区  ›  Pablo Gonzalez

如何从一个二维图像获得真实世界的距离使用棋盘作为参考

  •  0
  • Pablo Gonzalez  · 技术社区  · 6 年前

    enter image description here

    在检查了几段代码之后,我拍了几张照片,找到了棋盘上的角点,并用它们得到了相机矩阵、失真系数、旋转和平移向量。现在,有人能告诉我需要哪个python opencv函数来计算现实世界中与2D图像的距离吗?项目点?例如,使用棋盘作为参考(见图),如果瓷砖尺寸为5cm,则4块瓷砖的距离应为20cm。我看到了一些函数,如projectPoints,findHomography,solvePnP,但我不知道我需要哪一个来解决我的问题,并得到相机世界和棋盘世界之间的转换矩阵。 1台摄像机,所有情况下摄像机的位置相同,但不完全在棋盘上,棋盘放在平面物体(桌子)上

    # prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
        objp = np.zeros((nx * ny, 3), np.float32)
        objp[:, :2] = np.mgrid[0:nx, 0:ny].T.reshape(-1, 2)
    
        # Arrays to store object points and image points from all the images.
        objpoints = []  # 3d points in real world space
        imgpoints = []  # 2d points in image plane.
    
        # Make a list of calibration images
        images = glob.glob(path.join(calib_images_dir, 'calibration*.jpg'))
        print(images)
        # Step through the list and search for chessboard corners
        for filename in images:
    
            img = cv2.imread(filename)
    
            imgScale = 0.5
            newX,newY = img.shape[1]*imgScale, img.shape[0]*imgScale
            res = cv2.resize(img,(int(newX),int(newY)))
    
            gray = cv2.cvtColor(res, cv2.COLOR_BGR2GRAY)
    
            # Find the chessboard corners
            pattern_found, corners = cv2.findChessboardCorners(gray, (nx,ny), None)
    
            # If found, add object points, image points (after refining them)
            if pattern_found is True:
                objpoints.append(objp)
    
                # Increase accuracy using subpixel corner refinement
                cv2.cornerSubPix(gray,corners,(5,5),(-1,-1),(cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.1 ))
                imgpoints.append(corners)
    
                if verbose:
                    # Draw and display the corners
                    draw = cv2.drawChessboardCorners(res, (nx, ny), corners, pattern_found)
                    cv2.imshow('img',draw)
                    cv2.waitKey(500)
    
        if verbose:
            cv2.destroyAllWindows()
    
        #Now we have our object points and image points, we are ready to go for calibration
        # Get the camera matrix, distortion coefficients, rotation and translation vectors
        ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
        print(mtx)
        print(dist)
        print('rvecs:', type(rvecs),' ',len(rvecs),' ',rvecs)
        print('tvecs:', type(tvecs),' ',len(tvecs),' ',tvecs)
    
        mean_error = 0
        for i in range(len(objpoints)):
            imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist)
            error = cv2.norm(imgpoints[i],imgpoints2, cv2.NORM_L2)/len(imgpoints2)
            mean_error += error
    
        print("total error: ", mean_error/len(objpoints))
    
    
        imagePoints,jacobian = cv2.projectPoints(objpoints[0], rvecs[0], tvecs[0], mtx, dist)
        print('Image points: ',imagePoints)
    
    0 回复  |  直到 6 年前
        1
  •  7
  •   Douglas Brion    6 年前

    https://en.wikipedia.org/wiki/Perspective-n-Point .)

    cv2.solvePnP(objectPoints, imagePoints, cameraMatrix, distCoeffs[, rvec[, tvec[, useExtrinsicGuess[, flags]]]]) → retval, rvec, tvec
    

    在您的例子中,imagePoints将是棋盘的角,因此它看起来像:

    ret, rvec, tvec = cv2.solvePnP(objpoints, corners, mtx, dist)
    

    使用返回的平移向量,可以计算相机到棋盘的距离。solvePnP的输出转换与objectPoints中指定的单位相同。

    d = math.sqrt(tx*tx + ty*ty + tz*tz).
    
        2
  •  0
  •   ElConrado    6 年前

    您的问题主要与相机校准有关,尤其是在解决相机分辨率执行不佳的情况下 distortion 在opencv中。你必须通过在棋盘的不同坐标中进行几次距离探测来近似相机镜头的畸变函数。好主意是先在len的中心走一小段距离,然后走一个正方形的距离,再走一小段距离,然后重复操作到边界。它会给你失真函数的系数。 Matlab has own library 要精确地解决你的问题,不幸的是它相当昂贵。
    根据:

    我想 this article

    cv2.GetRealDistance(...)