def test_direct_projection_undistortion(): """ Test the direct applicaiton of the undistortion model compared to the opencv provided one. """ point = np.array([0.5, 0.5, 1.0]) undistort = Undistort(np.array([[300, 0, 640], [0, 300, 480], [0, 0, 1]]), np.array([0.1, 0.05, -0.002, 0.002, 0.001])) point_cv = undistort.project_point_with_distortion_cv(point) point_direct = undistort.project_point_with_distortion(point) np.testing.assert_array_almost_equal(point_cv, point_direct)
def test_bad_initialization(): """ Test initializer with bad values """ with pytest.raises(TypeError): Undistort(np.identity(3), "not a matrix") with pytest.raises(TypeError): Undistort("not a matrix", [1, 2, 3, 4, 5]) with pytest.raises(RuntimeError): Undistort(np.identity(4), [1, 2, 3, 4, 5]) with pytest.raises(RuntimeError): Undistort(np.identity(3), [1, 2, 3, 4])
def test_file_saving_loading(): """ Test the file saving and loading. """ undistort = Undistort(camera_matrix=np.identity(3), distortion=[0, 0, 0, 1, 2]) with tempfile.NamedTemporaryFile() as fid: undistort.write_file(fid.name) new_object = Undistort.read_json_file(fid.name) assert isinstance(new_object, Undistort) assert np.identity(3) == pytest.approx(new_object.camera_matrix) assert [0, 0, 0, 1, 2] == pytest.approx(new_object.distortion)
def sensor_calibration(): """ Method for getting and setting the sensor cal file. """ success = True message = "" if request.method == "POST": cal_file = request.json try: sensor_cal = json.loads(cal_file, JSONDecoder=decode_sensor_settings) sensor_cal.write_file(SENSOR_CAL_FILE) except: success = False message = "Failed to parse passed sensor calibration." return jsonify({"success": success, "message": message}) else: try: sensor_cal = Undistort.read_json_file(SENSOR_CAL_FILE) except: sensor_cal = None success = False message = "Failed to load sensor xml file." return jsonify({ "sensor_cal_file": sensor_cal, "success": success, "message": message })
def test_default_initializer(): """ Defaults test """ undistort = Undistort(camera_matrix=np.identity(3), distortion=[0, 0, 0, 1, 2]) assert np.identity(3) == pytest.approx(undistort.camera_matrix) assert [0, 0, 0, 1, 2] == pytest.approx(undistort.distortion)
def point_residuals(params, points_3d, points_2d): """ Get residuals of projected 3d points, compared to the imaged points (two points for each points) """ cam_matrix, distortion, rvec, tvec = unpack_params(params) undistort = Undistort(cam_matrix, distortion) transform = Transform(rotation=rvec, translation=tvec) residuals = np.array([ get_projected(point_3d, undistort, transform) - point_2d for point_3d, point_2d in zip(points_3d, points_2d) ]) return residuals.ravel()
def test_get_projected(): """ Test the projection function again opencv """ rvec=np.array(initial_R, dtype="float32") tvec=np.array(initial_t, dtype="float32") undistorter=Undistort(initial_camera_matrix, initial_distortion) transformer=Transform(rvec, tvec) _, translations, points_2d = generate_dataset() for point_2d, point_3d in zip (points_2d, translations): point = sc.get_projected(point_3d, undistorter, transformer) np.testing.assert_array_almost_equal( point_2d, point, decimal=4 )
def generate_dataset(): """ Generate the 3d points, translations of the stage to get there and 2d point correspondences. """ initial_point = np.array([0, 0, 0]) initial_U = Undistort(initial_camera_matrix, initial_distortion) initial_T = Transform (rotation=initial_R, translation=initial_t) #distance: 1.5 cm, FOV Width: (0.17920477879410118, 0.10080268807168191) cm #distance: 2 cm, FOV Width: (0.23893970505880158, 0.13440358409557587) cm #distance: 2.5 cm, FOV Width: (0.29867463132350197, 0.16800448011946983) cm distances = np.array([1.5, 2.0, 2.5]) - initial_t[2] width_x = [0.175, 0.23, 0.29] width_y = [0.10, 0.13, 0.16] translations = [] for d, w, h in zip(distances, width_x, width_y): for x in np.arange(-w, w, w/10): for y in np.arange(-h, h, h/10): translations.append(np.array([x, y, d])) points_3d = [] points_2d = [] trans_out = [] for t in translations: T = Transform(translation=t) point_3d = initial_T.transform_point(T.transform_point(initial_point)) point_2d = initial_U.project_point_with_distortion(point_3d) if np.abs(point_2d[0]) > initial_camera_matrix[0, 2] or np.abs(point_2d[1]) > initial_camera_matrix[1, 2]: continue points_3d.append(point_3d) points_2d.append(point_2d) trans_out.append(t) return (points_3d, trans_out, points_2d)
def calibrate_from_3d_points(points_3d, observed_points_2d, camera_matrix=None, distortion=None, rvec=None, tvec=None): """ Given a set of points in 3d, the observed points in 2d, solve for the camera parameters and inital R and t. """ if not isinstance(camera_matrix, np.ndarray): camera_matrix = np.array([[4000, 0, 650], [0, 4000, 350], [0, 0, 1]]) if not isinstance(distortion, np.ndarray): distortion = np.array([0, 0, 0, 0, 0]) if not isinstance(rvec, np.ndarray): rvec = np.array([0, 0, 0]) if not isinstance(tvec, np.ndarray): tvec = np.array([0.005, -0.002, 0.0237]) parameters = [ camera_matrix[0, 0], camera_matrix[1, 1], camera_matrix[0, 2], camera_matrix[1, 2], distortion[0], distortion[1], distortion[2], distortion[3], distortion[4], rvec[0], rvec[1], rvec[2], tvec[0], tvec[1], tvec[2] ] #res = so.least_squares(point_residuals, parameters, jac="3-point", x_scale='jac', method='trf', loss='linear', verbose=2, args=(points_3d, observed_points_2d)) res = so.minimize(single_residual, parameters, args=(points_3d, observed_points_2d), method="Powell", options={"disp": True}) print("Actual Fit:") if res.success: print("Fit sucessful.") else: print("Fit failed.") camera_matrix, distortion, rvecs, tvecs = unpack_params(res.x) print("Camera Matrix:") print(camera_matrix) print("Distortion Matrix") print(distortion) print("rvec") print(rvecs) print("tvec") print(tvecs) return (Undistort(camera_matrix, distortion), camera_matrix, distortion, rvec, tvec)
file_stem = Path(an_image).stem pos = float(re.findall(r'(\d+(?:\.\d+)?)', file_stem)[1]) image = cv2.imread(an_image) image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) print("Loaded {} at height {}".format(an_image, pos)) current_points_total = finder.process(image_gray) current_points_filtered = reject_outlier( np.asarray(current_points_total)) if args.preview: overlayed_image = point_overlay(image, current_points_filtered) resized_image = cv2.resize(overlayed_image, (750, 750)) cv2.imshow('image', resized_image) cv2.waitKey(0) cv2.destroyAllWindows() data_points_list.append(current_points_filtered) distance_list.append(pos / 1000.0) #Convert mm to m. undistort = Undistort.read_json_file(args.input_intrinsics_file) if not undistort: print("Could not load camera parameters from " + args.input_intrinsics_file + ". Exiting...") sys.exit() fitter = LaserFitter(undistort, data_points_list, distance_list) res, laser_plane = fitter.process() print(res) print(laser_plane) laser_plane.write_file(args.output_file)
import argparse import sys from volteracamera.analysis.undistort import Undistort from volteracamera.analysis.plane import Plane from volteracamera.analysis.laser_line_finder import LaserProcessingServer if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("camera_parameters", type=str, help="json file containing undistortion class.") parser.add_argument("laser_plane", type=str, help="json file containing laser plane class.") parser.add_argument("-o", "--output_file", type=str, help="optional output file for the laser data, saved in csv format.") args = parser.parse_args() #load in the calibration files cam_params = Undistort.read_json_file(args.camera_parameters) laser_plane = Plane.read_json_file(args.laser_plane) output_file = args.output_file if cam_params is None: print ("Failed to load camera parameters. Exiting...") sys.exit() if laser_plane is None: print ("Failed to load laser plane parameters. Exiting...") sys.exit() laser_processor = LaserProcessingServer (cam_params, laser_plane) if output_file: laser_processor.save_data (output_file)