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:
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:
- What's wrong with my result images?
- Why do I get this error message when I swapping this two lines of code and how should I fix it?