-
-
Save lanius/98b7edca1b29c949fcf1 to your computer and use it in GitHub Desktop.
| # -*- coding: utf-8 -*- | |
| import argparse | |
| import cv2 | |
| import numpy as np | |
| def calc_disparity(left_image, right_image): | |
| window_size = 3 | |
| min_disp = 1 | |
| num_disp = 16*2 | |
| stereo = cv2.StereoSGBM( | |
| minDisparity=min_disp, | |
| numDisparities=num_disp, | |
| SADWindowSize=window_size, | |
| uniquenessRatio=10, | |
| speckleWindowSize=100, | |
| speckleRange=32, | |
| disp12MaxDiff=1, | |
| P1=8*3*window_size**2, | |
| P2=32*3*window_size**2, | |
| fullDP=False | |
| ) | |
| return stereo.compute(left_image, right_image).astype(np.float32) / 16.0 | |
| def remove_invalid(disp_arr, points, colors): | |
| mask = ( | |
| (disp_arr > disp_arr.min()) & | |
| np.all(~np.isnan(points), axis=1) & | |
| np.all(~np.isinf(points), axis=1) | |
| ) | |
| return points[mask], colors[mask] | |
| def calc_point_cloud(image, disp, q): | |
| points = cv2.reprojectImageTo3D(disp, q).reshape(-1, 3) | |
| colors = image.reshape(-1, 3) | |
| return remove_invalid(disp.reshape(-1), points, colors) | |
| def project_points(points, colors, r, t, k, dist_coeff, width, height): | |
| projected, _ = cv2.projectPoints(points, r, t, k, dist_coeff) | |
| xy = projected.reshape(-1, 2).astype(np.int) | |
| mask = ( | |
| (0 <= xy[:, 0]) & (xy[:, 0] < width) & | |
| (0 <= xy[:, 1]) & (xy[:, 1] < height) | |
| ) | |
| return xy[mask], colors[mask] | |
| def calc_projected_image(points, colors, r, t, k, dist_coeff, width, height): | |
| xy, cm = project_points(points, colors, r, t, k, dist_coeff, width, height) | |
| image = np.zeros((height, width, 3), dtype=colors.dtype) | |
| image[xy[:, 1], xy[:, 0]] = cm | |
| return image | |
| def rotate(arr, anglex, anglez): | |
| return np.array([ # rx | |
| [1, 0, 0], | |
| [0, np.cos(anglex), -np.sin(anglex)], | |
| [0, np.sin(anglex), np.cos(anglex)] | |
| ]).dot(np.array([ # rz | |
| [np.cos(anglez), 0, np.sin(anglez)], | |
| [0, 1, 0], | |
| [-np.sin(anglez), 0, np.cos(anglez)] | |
| ])).dot(arr) | |
| def run(left_image, right_image, focal_length, tx): | |
| image = right_image | |
| height, width, _ = image.shape | |
| disp = calc_disparity(left_image, right_image) | |
| q = np.array([ | |
| [1, 0, 0, -width/2], | |
| [0, 1, 0, -height/2], | |
| [0, 0, 0, focal_length], | |
| [0, 0, -1/tx, 0] | |
| ]) | |
| points, colors = calc_point_cloud(image, disp, q) | |
| r = np.eye(3) | |
| t = np.array([0, 0, -100.0]) | |
| k = np.array([ | |
| [focal_length, 0, width/2], | |
| [0, focal_length, height/2], | |
| [0, 0, 1] | |
| ]) | |
| dist_coeff = np.zeros((4, 1)) | |
| def view(r, t): | |
| cv2.imshow('projected', calc_projected_image( | |
| points, colors, r, t, k, dist_coeff, width, height | |
| )) | |
| view(r, t) | |
| angles = { # x, z | |
| 'w': (-np.pi/6, 0), | |
| 's': (np.pi/6, 0), | |
| 'a': (0, np.pi/6), | |
| 'd': (0, -np.pi/6) | |
| } | |
| while 1: | |
| key = cv2.waitKey(0) | |
| if key not in range(256): | |
| continue | |
| ch = chr(key) | |
| if ch in angles: | |
| ax, az = angles[ch] | |
| r = rotate(r, -ax, -az) | |
| t = rotate(t, ax, az) | |
| view(r, t) | |
| elif ch == '\x1b': # esc | |
| cv2.destroyAllWindows() | |
| break | |
| def main(): | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument('left_image') | |
| parser.add_argument('right_image') | |
| parser.add_argument('focal_length', type=float) | |
| parser.add_argument('distance_between_cameras', type=float) | |
| args = parser.parse_args() | |
| left_image = cv2.imread(args.left_image) | |
| right_image = cv2.imread(args.right_image) | |
| f = args.focal_length | |
| tx = args.distance_between_cameras | |
| run(left_image, right_image, f, tx) | |
| if __name__ == '__main__': | |
| main() |
Do you know how to do with an amount of images greater than two? Like use 3 or 4 images?
@WJ75090983 "focal_length, distance_between_cameras" are not files, they are floating point values. focal_length of ur camera and distance_between_cameras is dist between the two stereo cams.
When I run the script with what I think is the correct parameters, I get:
File "no_errors.py", line 25, in calc_disparity
return stereo.compute(left_image, right_image).astype(np.float32) / 16.0
TypeError: Incorrect type of self (must be 'StereoMatcher' or its derivative)
If anyone can help, please let me know.
Hello, @JoeFurfaro I solved this problem by changing the following parameters:
window_size = 5
min_disp = 32
num_disp = 112 - min_disp
stereoTeste = cv2.StereoSGBM_create(minDisparity = min_disp,
numDisparities = num_disp,
blockSize = 16,
P1 = 83window_size2,
P2 = 323window_size2,
disp12MaxDiff = 1,
uniquenessRatio = 10,
speckleWindowSize = 100,
speckleRange = 32
)
@lanius can you post example image of the final result of the reconstruction? I'm not getting great results, and I do not know if it's due to my calibration, or incorrect setup of the StereoSGBM for my particular case. If possable Thx :)
Ps: the focal length and distance between cameras are in mm, cm or m ?
I tried running this code but then I keep getting error 'Nonetype' object has no attribute 'shape', I even double check the path that I'm using for image right and left and still getting this error. Can anyone help?
I finally got this to run an like Lindul, getting a lot of noise on the resultant image, other than calibration is there anyway to improve the 3D image appearance. I already modified Block size and numdisparities to improve the results marginally.
Hello, @JoeFurfaro I solved this problem by changing the following parameters:
window_size = 5
min_disp = 32
num_disp = 112 - min_disp
stereoTeste = cv2.StereoSGBM_create(minDisparity = min_disp,
numDisparities = num_disp,
blockSize = 16,
P1 = 8 * 3 * window_size**2, P2 = 32 * 3 * window_size ** 2, <= for preventing confusing
disp12MaxDiff = 1,
uniquenessRatio = 10,
speckleWindowSize = 100,
speckleRange = 32
)@lanius can you post example image of the final result of the reconstruction? I'm not getting great results, and I do not know if it's due to my calibration, or incorrect setup of the StereoSGBM for my particular case. If possable Thx :)
Ps: the focal length and distance between cameras are in mm, cm or m ?
hi can someone can help me with this
3D test.py: error: the following arguments are required: img1, img2, focal_length, distance_between_cameras
thanks
Can anybody post some sample results
Hello,I want to run your code on my computer,but some problems happened unfortunately, the error is "reconstruct.py: error: the following arguments are required: left_image, right_image, focal_length, distance_between_cameras". I have the left and right images in the folder,but I lack these file:"focal_length, distance_between_cameras",can you share these file to me,Thank you a lot! This is my mail:[email protected]