Ask Your Question

Revision history [back]

Simple augmented reality using opencv

Hi everyone! I'm totally newbie at opencv and computer vision at all and I face some problems with it. I'm trying to build simple program that's detecting planar object and drawing cube (or at least 3d axis) on it. I used this guide to build it, and here is my code:

import sys
import numpy as np
import cv2

CANNY_LOW = 30
CANNY_HIGH = 200
CGAUSIAN = (5, 5)

MIN_RECT_AREA = 100
IS_CLOSED = True
DELTA = 0.01

BLUE = (255, 0, 0)
GREEN = (0, 255, 0)
RED = (0, 0, 255)
BLACK = (0, 0, 0)


def show(image):
    cv2.namedWindow('image', cv2.WINDOW_NORMAL)
    cv2.imshow('image', image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()


def filt(image):
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    edged = cv2.Canny(image, CANNY_LOW, CANNY_HIGH)
    blured = cv2.GaussianBlur(edged, GAUSIAN, 5)
    return blured


def search_for_table_corners(raw_image):
    filtered = filt(raw_image)
     _, cnts, _ = cv2.findContours(filtered,
            cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
    for cnt in cnts:
        cnt_len = cv2.arcLength(cnt, IS_CLOSED)
        approx = cv2.approxPolyDP(cnt, DELTA * cnt_len, IS_CLOSED)
        if len(approx) == 4:
            cv2.drawContours(raw_image, [approx], -1, BLACK, 4)
            return np.float32(approx)
    return None


def draw(img, corners, imgpts):
    corner = tuple(corners[0].ravel())
    img = cv2.line(img, corner, tuple(imgpts[0].ravel()), BLUE, 5)
    img = cv2.line(img, corner, tuple(imgpts[1].ravel()), GREEN, 5)
    img = cv2.line(img, corner, tuple(imgpts[2].ravel()), RED, 5)
    return img


def generate_camera_matrix(image):
    h, w = image.shape[:2]
    # let it be full frame matrix
    sx, sy = (36, 24)
    # focus length
    f = 50
    fx = w * f / sx
    fy = h * f / sy
    cx = w / 2
    cy = h / 2
    mtx = np.zeros((3, 3), np.float32)
    mtx[0, 0] = fx # [ fx  0  cx ]
    mtx[0, 2] = cx # [  0 fy  cy ]
    mtx[1, 1] = fy # [  0  0   1 ]
    mtx[1, 2] = cy
    mtx[2, 2] = 1
    return mtx


def generate_distorsions():
    return np.zeros((1, 4), np.float32)


def get_object_points(corners):
    x1, y1 = corners[0][0]
    x2, y2 = corners[1][0]
    x3, y3 = corners[2][0]
    x4, y4 = corners[3][0]
    return np.float32([
        # hardbone
        [x2, y2, 0],
        [x1, y1, 0],
        [x3, y3, 0],
        [x4, y4, 0],
    ])


def generate_axis(a):
    axis = np.float32([[a,0,0], [0,a,0], [0,0,-a]]).reshape(-1,3)
    return axis


def get_corners_subpixels(raw_image, corners):
    criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER,
            30, 0.001)
    gray = cv2.cvtColor(raw_image, cv2.COLOR_BGR2GRAY)
    corners_subpxs = cv2.cornerSubPix(gray, corners,
            (11, 11), (-1, -1), criteria)
    return corners_subpxs


def estimate_pose(raw_image, table_corners):
    print('table_corners:\n', table_corners, '\n', '-' * 70)
    object_points = get_object_points(table_corners)
    print('object_points:\n', object_points, '\n', '-' * 70)
    corners_subpxs = get_corners_subpixels(raw_image, table_corners)
    print('corners_subpxs:\n', corners_subpxs, '\n', '-' * 70)
    camera_matrix = generate_camera_matrix(raw_image)
    print('camera_matrix:\n', corners_subpxs, '\n', '-' * 70)
    distorsions = generate_distorsions()
    rotation_vec, translation_vec = cv2.solvePnPRansac(object_points,
            corners_subpxs, camera_matrix, distorsions, iterationsCount=500,
            reprojectionError=50)[1:3]
    print('rotation_vec:\n', rotation_vec, '\n', '-' * 70)
    print('translation_vec:\n', translation_vec, '\n', '-' * 70)
    return rotation_vec, translation_vec, camera_matrix, distorsions, \
        corners_subpxs


def create_canvas(image):
    return image.copy()


def get_projection_points(raw_image, table_corners):
    rvecs, tvecs, mcam, dist, corn2 = estimate_pose(raw_image, table_corners)
    size = round(raw_image.shape[0] / 10)
    axis = generate_axis(size)
    projection_points = cv2.projectPoints(axis, rvecs, tvecs, mcam, dist)[0]
    print('projection_points:\n', projection_points, '\n', '-' * 70)
    return projection_points, corn2


def draw_cube(raw_image, table_corners):
    projection_points, corners_subpxs = get_projection_points(raw_image,
            table_corners)
    canvas = create_canvas(raw_image)
    canvas = draw(raw_image, corners_subpxs, projection_points)
    return canvas


def main():
    path = sys.argv[1]
    raw_image = cv2.imread(path)
    table_corners = search_for_table_corners(raw_image)
    if table_corners is None:
        raise Exception('there is no table!')
    result = draw_cube(raw_image, table_corners)
    show(result)
    return result


def show_filtered():
    path = sys.argv[1]
    raw_image = cv2.imread(path)
    result = filt(raw_image)
    show(result)


if __name__ == '__main__':
    if len(sys.argv) == 3:
        result = main()
        output_path = sys.argv[2]
        cv2.imwrite(output_path, result)
    else:
        show_filtered()

Well, it looks correct, but result is not good: first second

Here is some information that may be useful:

# for first image
table_corners:
 [[[ 617.   62.]]
 [[ 279.  185.]]
 [[  24.  119.]]
 [[ 371.   15.]]]
 ----------------------------------------------------------------------
object_points:
 [[ 279.  185.    0.]
 [ 617.   62.    0.]
 [  24.  119.    0.]
 [ 371.   15.    0.]]
 ----------------------------------------------------------------------
corners_subpxs:
 [[[ 623.54382324   61.92623901]]
 [[ 282.25015259  184.323349  ]]
 [[  14.8296175   119.69662476]]
 [[ 368.79107666   13.57480717]]]
 ----------------------------------------------------------------------
camera_matrix:
 [[ 888.88891602    0.          320.        ]
 [   0.          837.5         201.        ]
 [   0.            0.            1.        ]]
 ----------------------------------------------------------------------
rotation_vec:
 [[  7.69123316e-308]
 [  7.69136897e-308]
 [  7.69136897e-308]]
 ----------------------------------------------------------------------
translation_vec:
 [[ 0.]
 [ 0.]
 [ 0.]]
 ----------------------------------------------------------------------
projection_points:
 [[[ 35875.5546875    201.       ]]
 [[   320.         33701.       ]]
 [[   320.           201.       ]]]
 ----------------------------------------------------------------------


# for second image
table_corners:
 [[[   71.   347.]]
 [[  779.   234.]]
 [[ 1932.   286.]]
 [[ 1372.   417.]]]
 ----------------------------------------------------------------------
object_points:
 [[  779.   234.     0.]
 [   71.   347.     0.]
 [ 1932.   286.     0.]
 [ 1372.   417.     0.]]
 ----------------------------------------------------------------------
corners_subpxs:
 [[[   71.           347.        ]]
 [[  769.44647217   233.23860168]]
 [[ 1935.77246094   283.87097168]]
 [[ 1366.22546387   417.27722168]]]
 ----------------------------------------------------------------------
camera_matrix:
 [[  2.77777783e+03   0.00000000e+00   1.00000000e+03]
 [  0.00000000e+00   4.16666650e+03   1.00000000e+03]
 [  0.00000000e+00   0.00000000e+00   1.00000000e+00]]
 ----------------------------------------------------------------------
rotation_vec:
 [[  7.69136897e-308]
 [  7.69136897e-308]
 [  7.69136897e-308]]
 ----------------------------------------------------------------------
translation_vec:
 [[ 0.]
 [ 0.]
 [ 0.]]
 ----------------------------------------------------------------------
projection_points:
 [[[ 556555.5625    1000.    ]]
 [[   1000.      834333.3125]]
 [[   1000.        1000.    ]]]
 ----------------------------------------------------------------------

And when I swap two lines below # hardbone comment, it gives me this error:

OpenCV Error: Assertion failed (d == 2 && (sizes[0] == 1 || sizes[1] == 1 || sizes[0]*sizes[1] == 0)) in create, file /home/cornbuddy/opencv/modules/core/src/matrix.cpp, line 2355
Traceback (most recent call last):
  File "python/main.py", line 167, in <module>
    result = main()
  File "python/main.py", line 153, in main
    result = draw_cube(raw_image, table_corners)
  File "python/main.py", line 141, in draw_cube
    table_corners)
  File "python/main.py", line 131, in get_projection_points
    rvecs, tvecs, mcam, dist, corn2 = estimate_pose(raw_image, table_corners)
  File "python/main.py", line 119, in estimate_pose
    reprojectionError=50)[1:3]
cv2.error: /home/cornbuddy/opencv/modules/core/src/matrix.cpp:2355: error: (-215) d == 2 && (sizes[0] == 1 || sizes[1] == 1 || sizes[0]*sizes[1] == 0) in function create

So I have two questions:

  1. What's wrong with my result images?
  2. Why do I get this error message when I swapping this two lines of code and how should I fix it?