def test_appd_map_resolution_invariance(self): perturbed_K = self.test_image_K * 0.98 perturbed_D = self.test_image_D * 1.02 perturbed_calibration = Calibration(K=perturbed_K, D=perturbed_D, width=self.test_image.shape[1], height=self.test_image.shape[0]) appd_full, dm_full = perturbed_calibration.appd( self.calibration, height=self.test_image.shape[0], width=self.test_image.shape[1], interpolation=cv2.INTER_LANCZOS4, min_cropped_size=None, return_diff_map=True) appd_half, dm_half = perturbed_calibration.appd( self.calibration, height=int(self.test_image.shape[0]), width=int(self.test_image.shape[1]), interpolation=cv2.INTER_LANCZOS4, min_cropped_size=None, return_diff_map=True, map_width=int(self.test_image.shape[1] / 2), map_height=int(self.test_image.shape[0] / 2)) self.assertAlmostEqual(appd_full, appd_half, places=3) self.assertTrue( np.allclose(dm_full, cv2.resize(dm_half, (dm_full.shape[1], dm_full.shape[0]), interpolation=cv2.INTER_LANCZOS4), rtol=1e-1, atol=1e-1))
def test_appd(self): perturbed_K = self.test_image_K * 0.98 perturbed_D = self.test_image_D * 1.01 perturbed_calibration = Calibration(K=perturbed_K, D=perturbed_D, width=self.test_image.shape[1], height=self.test_image.shape[0]) appd1, dm1 = self.calibration.appd(perturbed_calibration, height=self.test_image.shape[0], width=self.test_image.shape[1], interpolation=cv2.INTER_LANCZOS4, min_cropped_size=None, return_diff_map=True) appd2, dm2 = perturbed_calibration.appd( self.calibration, height=self.test_image.shape[0], width=self.test_image.shape[1], interpolation=cv2.INTER_LANCZOS4, min_cropped_size=None, return_diff_map=True) self.assertTrue(np.isclose(appd1, appd2, rtol=1e-2, atol=1e-2)) self.assertTrue(np.allclose(dm1, dm2, rtol=1e-2, atol=1e-2)) self.assertEqual(dm1.shape, (self.test_image.shape[0], self.test_image.shape[1])) cv2.imwrite(path_here("test_appd_diff_map.png"), dm1)
def test_region_of_validity_check(self): perturbed_K = self.test_image_K * 2 perturbed_D = self.test_image_D * 9 perturbed_calibration = Calibration(K=perturbed_K, D=perturbed_D, width=self.test_image.shape[1], height=self.test_image.shape[0]) with self.assertRaises(RuntimeError): _, _ = perturbed_calibration.appd(self.calibration, height=self.test_image.shape[0], width=self.test_image.shape[1], interpolation=cv2.INTER_LANCZOS4, min_cropped_size=None, return_diff_map=True)
def setUp(self): # Load an image an image and its calibration parameters self.test_image = cv2.imread(path_here('test_image_before.png')) self.test_image_D = np.array([ -0.2967039649743125, 0.06795775093662262, 0.0008927768064001824, -0.001327854648098482, 0.0 ]) self.test_image_K = np.array([ 336.7755634193813, 0.0, 333.3575643300718, 0.0, 336.02729840829176, 212.77376312080065, 0.0, 0.0, 1.0 ]).reshape((3, 3)) self.width = self.test_image.shape[1] self.height = self.test_image.shape[0] self.ranges = { 'fx': (0.95 * 336.7755634193813, 1.05 * 336.7755634193813), 'fy': (0.95 * 336.02729840829176, 1.05 * 336.02729840829176), 'cx': (0.95 * 333.3575643300718, 1.05 * 333.3575643300718), 'cy': (0.95 * 212.77376312080065, 1.05 * 212.77376312080065), 'k1': (1.05 * -0.2967039649743125, 0.95 * -0.2967039649743125), 'k2': (0.95 * 0.06795775093662262, 1.05 * 0.06795775093662262), 'p1': (0.95 * 0.0008927768064001824, 1.05 * 0.0008927768064001824), 'p2': (1.05 * -0.001327854648098482, 0.95 * -0.001327854648098482), 'k3': (0.0, 0.0) } # Initialize a reference calibration object self.reference = Calibration(K=self.test_image_K, D=self.test_image_D, width=self.test_image.shape[1], height=self.test_image.shape[0])
def setUp(self): # Load an image an image and its calibration parameters self.test_image = cv2.imread(path_here('test_image_before.png')) self.test_image_D = np.array([ -0.2967039649743125, 0.06795775093662262, 0.0008927768064001824, -0.001327854648098482, 0.0 ]) self.test_image_K = np.array([ 336.7755634193813, 0.0, 333.3575643300718, 0.0, 336.02729840829176, 212.77376312080065, 0.0, 0.0, 1.0 ]).reshape((3, 3)) # Initialize a calibration object self.calibration = Calibration(K=self.test_image_K, D=self.test_image_D, width=self.test_image.shape[1], height=self.test_image.shape[0])
class TestCalibrationMethods(unittest.TestCase): def setUp(self): # Load an image an image and its calibration parameters self.test_image = cv2.imread(path_here('test_image_before.png')) self.test_image_D = np.array([ -0.2967039649743125, 0.06795775093662262, 0.0008927768064001824, -0.001327854648098482, 0.0 ]) self.test_image_K = np.array([ 336.7755634193813, 0.0, 333.3575643300718, 0.0, 336.02729840829176, 212.77376312080065, 0.0, 0.0, 1.0 ]).reshape((3, 3)) # Initialize a calibration object self.calibration = Calibration(K=self.test_image_K, D=self.test_image_D, width=self.test_image.shape[1], height=self.test_image.shape[0]) def test_print_image_dimensions(self): print("Test image dimensions: %s" % str(self.test_image.shape)) self.assertTrue(True) def test_check_ar(self): self.assertAlmostEqual(self.calibration.aspect_ratio, 640.0 / 480) def test_scaling_of_K(self): self.assertTrue( np.allclose(self.test_image_K, self.calibration.get_K(height=480))) def test_storing_of_D(self): self.assertTrue( np.allclose(self.test_image_D, self.calibration.get_D())) def test_check_undistort_maps_original_size(self): width = self.test_image.shape[1] height = self.test_image.shape[0] undistort_x, undistort_y = self.calibration.undistortion_maps( width=width, height=height) self.assertEqual(undistort_x.shape, self.test_image.shape[:2]) def test_check_undistort_maps_reduced_size(self): width = self.test_image.shape[1] height = self.test_image.shape[0] undistort_x, undistort_y = self.calibration.undistortion_maps( width=width, height=height, map_width=int(width / 2), map_height=int(height / 2)) self.assertEqual( undistort_x.shape, (self.test_image.shape[0] / 2, self.test_image.shape[1] / 2)) def test_check_undistortion_maps_preserving_original_size(self): width = self.test_image.shape[1] height = self.test_image.shape[0] undistort_x, undistort_y = self.calibration.undistortion_maps_preserving( width=width, height=height) self.assertEqual(undistort_x.shape, self.test_image.shape[:2]) def test_check_undistortion_maps_preserving_reduced_size(self): width = self.test_image.shape[1] height = self.test_image.shape[0] undistort_x, undistort_y = self.calibration.undistortion_maps_preserving( width=width, height=height, map_width=int(width / 2), map_height=int(height / 2)) self.assertEqual( undistort_x.shape, (self.test_image.shape[0] / 2, self.test_image.shape[1] / 2)) def test_rectified_standard_size(self): # Apply our rectification rect_ours = self.calibration.rectify(self.test_image, mode='standard') self.assertEqual(rect_ours.shape, self.test_image.shape) def test_rectified_reduced_size(self): width = self.test_image.shape[1] height = self.test_image.shape[0] # Apply our rectification rect_ours = self.calibration.rectify(self.test_image, mode='standard', result_width=int(width / 2), result_height=int(height / 2)) self.assertEqual( rect_ours.shape, (self.test_image.shape[0] / 2, self.test_image.shape[1] / 2, self.test_image.shape[2])) def test_rectified_standard_with_ground_truth(self): # Apply our rectification rect_ours = self.calibration.rectify(self.test_image, mode='standard') # Apply directly the OpenCV rectification newCameraMatrix, validPixROI = cv2.getOptimalNewCameraMatrix( self.test_image_K, self.test_image_D, (self.test_image.shape[1], self.test_image.shape[0]), 1.0) map1, map2 = cv2.initUndistortRectifyMap( self.test_image_K, self.test_image_D, np.eye(3), newCameraMatrix, (self.test_image.shape[1], self.test_image.shape[0]), cv2.CV_32FC1) rect_direct = cv2.remap(self.test_image, map1, map2, cv2.INTER_LANCZOS4) cv2.imwrite(path_here("test_rectified_standard_with_ground_truth.png"), np.hstack((rect_direct, rect_ours))) self.assertTrue(np.allclose(rect_direct, rect_ours)) def test_rectified_preserving_with_ground_truth(self): # Apply our rectification rect_ours = self.calibration.rectify(self.test_image, mode='preserving') # Apply directly the OpenCV rectification output_resolution = (self.test_image.shape[1], self.test_image.shape[0]) newCameraMatrix, validPixROI = cv2.getOptimalNewCameraMatrix( self.test_image_K, self.test_image_D, (self.test_image.shape[1], self.test_image.shape[0]), 1.0) map1, map2 = cv2.initUndistortRectifyMap( self.test_image_K, self.test_image_D, np.eye(3), newCameraMatrix, (self.test_image.shape[1], self.test_image.shape[0]), cv2.CV_32FC1) rect_direct = cv2.remap(self.test_image, map1, map2, cv2.INTER_LANCZOS4) # Do the preserving on the direct image target_aspect_ratio = float(rect_direct.shape[1]) / float( rect_direct.shape[0]) validROI = { 'x': (validPixROI[0], validPixROI[0] + validPixROI[2]), 'y': (validPixROI[1], validPixROI[1] + validPixROI[3]) } valid_aspect_ratio = float(validROI['x'][1] - validROI['x'][0]) / ( validROI['y'][1] - validROI['y'][0]) # If the image is taller than it should, cut its legs and head if valid_aspect_ratio < target_aspect_ratio: desired_number_of_rows = int( round((validROI['x'][1] - validROI['x'][0]) / target_aspect_ratio)) cut_top = int(((validROI['y'][1] - validROI['y'][0]) - desired_number_of_rows) / 2) cropped_ROI = { 'x': validROI['x'], 'y': (validROI['y'][0] + cut_top, validROI['y'][0] + cut_top + desired_number_of_rows) } else: desired_number_of_cols = int( round((validROI['y'][1] - validROI['y'][0]) * target_aspect_ratio)) cut_left = int(((validROI['x'][1] - validROI['x'][0]) - desired_number_of_cols) / 2) cropped_ROI = { 'x': (validROI['x'][0] + cut_left, validROI['x'][0] + cut_left + desired_number_of_cols), 'y': validROI['y'] } cropped_image = rect_direct[cropped_ROI['y'][0]:cropped_ROI['y'][1], cropped_ROI['x'][0]:cropped_ROI['x'][1]] resized_image = cv2.resize(cropped_image, output_resolution, interpolation=cv2.INTER_LANCZOS4) # Calculate the cropped maps (need that for the px movement metric calculation) map1 = copy.deepcopy(map1) map2 = copy.deepcopy(map2) map1 = map1[cropped_ROI['y'][0]:cropped_ROI['y'][1], cropped_ROI['x'][0]:cropped_ROI['x'][1]] map1 = cv2.resize(map1, output_resolution, interpolation=cv2.INTER_LANCZOS4) map2 = map2[cropped_ROI['y'][0]:cropped_ROI['y'][1], cropped_ROI['x'][0]:cropped_ROI['x'][1]] map2 = cv2.resize(map2, output_resolution, interpolation=cv2.INTER_LANCZOS4) # Prepare the image output rect_ours_gray = cv2.cvtColor(rect_ours, cv2.COLOR_BGR2GRAY) resized_direct_gray = cv2.cvtColor(resized_image, cv2.COLOR_BGR2GRAY, dstCn=3) overlayed = cv2.addWeighted(rect_ours_gray, 0.5, resized_direct_gray, 0.5, 0) cv2.imwrite( path_here("test_rectified_preserving_with_ground_truth.png"), overlayed) self.assertTrue( np.allclose(rect_ours_gray, resized_direct_gray, rtol=15, atol=15)) def test_appd(self): perturbed_K = self.test_image_K * 0.98 perturbed_D = self.test_image_D * 1.01 perturbed_calibration = Calibration(K=perturbed_K, D=perturbed_D, width=self.test_image.shape[1], height=self.test_image.shape[0]) appd1, dm1 = self.calibration.appd(perturbed_calibration, height=self.test_image.shape[0], width=self.test_image.shape[1], interpolation=cv2.INTER_LANCZOS4, min_cropped_size=None, return_diff_map=True) appd2, dm2 = perturbed_calibration.appd( self.calibration, height=self.test_image.shape[0], width=self.test_image.shape[1], interpolation=cv2.INTER_LANCZOS4, min_cropped_size=None, return_diff_map=True) self.assertTrue(np.isclose(appd1, appd2, rtol=1e-2, atol=1e-2)) self.assertTrue(np.allclose(dm1, dm2, rtol=1e-2, atol=1e-2)) self.assertEqual(dm1.shape, (self.test_image.shape[0], self.test_image.shape[1])) cv2.imwrite(path_here("test_appd_diff_map.png"), dm1) def test_appd_self(self): appd, dm = self.calibration.appd(self.calibration, height=self.test_image.shape[0], width=self.test_image.shape[1], interpolation=cv2.INTER_LANCZOS4, min_cropped_size=None, return_diff_map=True) self.assertTrue(np.isclose(appd, 0.0, rtol=1e-2, atol=1e-2)) self.assertTrue( np.allclose(dm, np.zeros_like(dm), rtol=1e-2, atol=1e-2)) def test_region_of_validity_check(self): perturbed_K = self.test_image_K * 2 perturbed_D = self.test_image_D * 9 perturbed_calibration = Calibration(K=perturbed_K, D=perturbed_D, width=self.test_image.shape[1], height=self.test_image.shape[0]) with self.assertRaises(RuntimeError): _, _ = perturbed_calibration.appd(self.calibration, height=self.test_image.shape[0], width=self.test_image.shape[1], interpolation=cv2.INTER_LANCZOS4, min_cropped_size=None, return_diff_map=True) def test_appd_map_resolution_invariance(self): perturbed_K = self.test_image_K * 0.98 perturbed_D = self.test_image_D * 1.02 perturbed_calibration = Calibration(K=perturbed_K, D=perturbed_D, width=self.test_image.shape[1], height=self.test_image.shape[0]) appd_full, dm_full = perturbed_calibration.appd( self.calibration, height=self.test_image.shape[0], width=self.test_image.shape[1], interpolation=cv2.INTER_LANCZOS4, min_cropped_size=None, return_diff_map=True) appd_half, dm_half = perturbed_calibration.appd( self.calibration, height=int(self.test_image.shape[0]), width=int(self.test_image.shape[1]), interpolation=cv2.INTER_LANCZOS4, min_cropped_size=None, return_diff_map=True, map_width=int(self.test_image.shape[1] / 2), map_height=int(self.test_image.shape[0] / 2)) self.assertAlmostEqual(appd_full, appd_half, places=3) self.assertTrue( np.allclose(dm_full, cv2.resize(dm_half, (dm_full.shape[1], dm_full.shape[0]), interpolation=cv2.INTER_LANCZOS4), rtol=1e-1, atol=1e-1))