def test_shape_outline(self): """Test the shape:outline feature.""" path = IMAGES_RECTANGLE[2] k = 20 # Object width and height. w, h = (300, 100) im_path = os.path.join(self.base_dir, path) img = cv2.imread(im_path) if img == None or img.size == 0: raise SystemError("Failed to read %s" % im_path) # Perform segmentation. mask = grabcut(img, 1, None, 1) bin_mask = np.where((mask == cv2.GC_FGD) + (mask == cv2.GC_PR_FGD), 255, 0).astype('uint8') # Obtain contours (all points) from the mask. contour = ft.get_largest_contour(bin_mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) # Get the outline. outline = ft.shape_outline(contour, k) # Assert the length of the return value. self.assertEqual(len(outline), k) # Assert the shape values. for x, y in outline: delta_x = x[0] - x[1] delta_y = y[0] - y[1] self.assertLess(error(delta_y, h, mape), 0.0001) self.assertLess(error(delta_x, w, mape), 0.0001)
def test_shape_outline(self): """Test the shape:outline feature.""" path = IMAGES_RECTANGLE[2] k = 20 # Object width and height. w, h = (300, 100) im_path = os.path.join(self.base_dir, path) img = cv2.imread(im_path) if img == None or img.size == 0: raise SystemError("Failed to read %s" % im_path) # Perform segmentation. mask = grabcut(img, 1, None, 1) bin_mask = np.where((mask==cv2.GC_FGD) + (mask==cv2.GC_PR_FGD), 255, 0).astype('uint8') # Obtain contours (all points) from the mask. contour = ft.get_largest_contour(bin_mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) # Get the outline. outline = ft.shape_outline(contour, k) # Assert the length of the return value. self.assertEqual( len(outline), k ) # Assert the shape values. for x, y in outline: delta_x = x[0] - x[1] delta_y = y[0] - y[1] self.assertLess( error(delta_y, h, mape), 0.0001 ) self.assertLess( error(delta_x, w, mape), 0.0001 )
def test_shape_360(self): """Test the shape:360 feature. Extracts the shape from two slightly rotated versions of the same image. Then the medium square error between the two extracted shapes is calculated and checked. """ max_error = 0.05 shape = [] for i, path in enumerate(IMAGES_ERYCINA): im_path = os.path.join(self.base_dir, path) img = cv2.imread(im_path) if img == None or img.size == 0: raise SystemError("Failed to read %s" % im_path) # Resize the image if it is larger then the threshold. img = scale_max_perimeter(img, MAX_SIZE) # Perform segmentation. mask = grabcut(img, 5, None, 1) # Create a binary mask. Foreground is made white, background black. bin_mask = np.where((mask == cv2.GC_FGD) + (mask == cv2.GC_PR_FGD), 255, 0).astype('uint8') # Obtain contours (all points) from the mask. contour = ft.get_largest_contour(bin_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) # Fit an ellipse on the contour to get the rotation angle. box = cv2.fitEllipse(contour) rotation = int(box[2]) # Extract the shape. intersects, center = ft.shape_360(contour, rotation) # For each angle save the mean distance from center to contour and # the standard deviation for the distances. means = [] sds = [] for angle in range(0, 360): distances = [] for p in intersects[angle]: d = ft.point_dist(center, p) distances.append(d) if len(distances) == 0: mean = 0 sd = 0 else: mean = np.mean(distances, dtype=np.float32) if len(distances) > 1: sd = np.std(distances, ddof=1, dtype=np.float32) else: sd = 0 means.append(mean) sds.append(sd) # Normalize and save result. means = cv2.normalize(np.array(means), None, -1, 1, cv2.NORM_MINMAX) sds = cv2.normalize(np.array(sds), None, -1, 1, cv2.NORM_MINMAX) shape.append([means, sds]) # Check the medium square error for the means. self.assertLess(error(shape[0][0].ravel(), shape[1][0].ravel(), mse), max_error) # Check the medium square error for the standard deviations. self.assertLess(error(shape[0][1].ravel(), shape[1][1].ravel(), mse), max_error)
def test_shape_360(self): """Test the shape:360 feature. Extracts the shape from two slightly rotated versions of the same image. Then the medium square error between the two extracted shapes is calculated and checked. """ max_error = 0.05 shape = [] for i, path in enumerate(IMAGES_ERYCINA): im_path = os.path.join(self.base_dir, path) img = cv2.imread(im_path) if img == None or img.size == 0: raise SystemError("Failed to read %s" % im_path) # Resize the image if it is larger then the threshold. img = scale_max_perimeter(img, MAX_SIZE) # Perform segmentation. mask = grabcut(img, 5, None, 1) # Create a binary mask. Foreground is made white, background black. bin_mask = np.where((mask==cv2.GC_FGD) + (mask==cv2.GC_PR_FGD), 255, 0).astype('uint8') # Obtain contours (all points) from the mask. contour = ft.get_largest_contour(bin_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) # Fit an ellipse on the contour to get the rotation angle. box = cv2.fitEllipse(contour) rotation = int(box[2]) # Extract the shape. intersects, center = ft.shape_360(contour, rotation) # For each angle save the mean distance from center to contour and # the standard deviation for the distances. means = [] sds = [] for angle in range(0, 360): distances = [] for p in intersects[angle]: d = ft.point_dist(center, p) distances.append(d) if len(distances) == 0: mean = 0 sd = 0 else: mean = np.mean(distances, dtype=np.float32) if len(distances) > 1: sd = np.std(distances, ddof=1, dtype=np.float32) else: sd = 0 means.append(mean) sds.append(sd) # Normalize and save result. means = cv2.normalize(np.array(means), None, -1, 1, cv2.NORM_MINMAX) sds = cv2.normalize(np.array(sds), None, -1, 1, cv2.NORM_MINMAX) shape.append([means, sds]) # Check the medium square error for the means. self.assertLess(error(shape[0][0].ravel(), shape[1][0].ravel(), mse), max_error) # Check the medium square error for the standard deviations. self.assertLess(error(shape[0][1].ravel(), shape[1][1].ravel(), mse), max_error)