def test_selem(self): """Test results if selem is given.""" selem_cross = np.array( [[0, 1, 0], [1, 1, 1], [0, 1, 0]], dtype=np.bool) result_selem_cross = extrema.local_maxima( self.image, selem=selem_cross) assert result_selem_cross.dtype == np.bool assert_equal(result_selem_cross, self.expected_cross) for selem in [ ((True,) * 3,) * 3, np.ones((3, 3), dtype=np.float64), np.ones((3, 3), dtype=np.uint8), np.ones((3, 3), dtype=np.bool), ]: # Test different dtypes for selem which expects a boolean array but # will accept and convert other types if possible result_selem_square = extrema.local_maxima(self.image, selem=selem) assert result_selem_square.dtype == np.bool assert_equal(result_selem_square, self.expected_default) selem_x = np.array([[1, 0, 1], [0, 1, 0], [1, 0, 1]], dtype=np.bool) expected_selem_x = np.array( [[1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0], [1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0]], dtype=np.bool ) result_selem_x = extrema.local_maxima(self.image, selem=selem_x) assert result_selem_x.dtype == np.bool assert_equal(result_selem_x, expected_selem_x)
def test_nd(self): """Test one- and three-dimensional case.""" # One-dimension x_1d = np.array([1, 1, 0, 1, 2, 3, 0, 2, 1, 2, 0]) expected_1d = np.array([1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0], dtype=np.bool) result_1d = extrema.local_maxima(x_1d) assert result_1d.dtype == np.bool assert_equal(result_1d, expected_1d) # 3-dimensions (adapted from old unit test) x_3d = np.zeros((8, 8, 8), dtype=np.uint8) expected_3d = np.zeros((8, 8, 8), dtype=np.bool) # first maximum: only one pixel x_3d[1, 1:3, 1:3] = 100 x_3d[2, 2, 2] = 200 x_3d[3, 1:3, 1:3] = 100 expected_3d[2, 2, 2] = 1 # second maximum: three pixels in z-direction x_3d[5:8, 1, 1] = 200 expected_3d[5:8, 1, 1] = 1 # third: two maxima in 0 and 3. x_3d[0, 5:8, 5:8] = 200 x_3d[1, 6, 6] = 100 x_3d[2, 5:7, 5:7] = 200 x_3d[0:3, 5:8, 5:8] += 50 expected_3d[0, 5:8, 5:8] = 1 expected_3d[2, 5:7, 5:7] = 1 # four : one maximum in the corner of the square x_3d[6:8, 6:8, 6:8] = 200 x_3d[7, 7, 7] = 255 expected_3d[7, 7, 7] = 1 result_3d = extrema.local_maxima(x_3d) assert result_3d.dtype == np.bool assert_equal(result_3d, expected_3d)
def test_footprint(self): """Test results if footprint is given.""" footprint_cross = np.array([[0, 1, 0], [1, 1, 1], [0, 1, 0]], dtype=bool) result_footprint_cross = extrema.local_maxima( self.image, footprint=footprint_cross) assert result_footprint_cross.dtype == bool assert_equal(result_footprint_cross, self.expected_cross) for footprint in [ ((True, ) * 3, ) * 3, np.ones((3, 3), dtype=np.float64), np.ones((3, 3), dtype=np.uint8), np.ones((3, 3), dtype=bool), ]: # Test different dtypes for footprint which expects a boolean array # but will accept and convert other types if possible result_footprint_square = extrema.local_maxima(self.image, footprint=footprint) assert result_footprint_square.dtype == bool assert_equal(result_footprint_square, self.expected_default) footprint_x = np.array([[1, 0, 1], [0, 1, 0], [1, 0, 1]], dtype=bool) expected_footprint_x = np.array( [[1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0], [1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0]], dtype=bool) result_footprint_x = extrema.local_maxima(self.image, footprint=footprint_x) assert result_footprint_x.dtype == bool assert_equal(result_footprint_x, expected_footprint_x)
def test_nd(self): """Test one- and three-dimensional case.""" # One-dimension x_1d = np.array([1, 1, 0, 1, 2, 3, 0, 2, 1, 2, 0]) expected_1d = np.array([1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0], dtype=np.bool) result_1d = extrema.local_maxima(x_1d) assert result_1d.dtype == np.bool assert_equal(result_1d, expected_1d) # 3-dimensions (adapted from old unit test) x_3d = np.zeros((8, 8, 8), dtype=np.uint8) expected_3d = np.zeros((8, 8, 8), dtype=np.bool) # first maximum: only one pixel x_3d[1, 1:3, 1:3] = 100 x_3d[2, 2, 2] = 200 x_3d[3, 1:3, 1:3] = 100 expected_3d[2, 2, 2] = 1 # second maximum: three pixels in z-direction x_3d[5:8, 1, 1] = 200 expected_3d[5:8, 1, 1] = 1 # third: two maxima in 0 and 3. x_3d[0, 5:8, 5:8] = 200 x_3d[1, 6, 6] = 100 x_3d[2, 5:7, 5:7] = 200 x_3d[0:3, 5:8, 5:8] += 50 expected_3d[0, 5:8, 5:8] = 1 expected_3d[2, 5:7, 5:7] = 1 # four : one maximum in the corner of the square x_3d[6:8, 6:8, 6:8] = 200 x_3d[7, 7, 7] = 255 expected_3d[7, 7, 7] = 1 result_3d = extrema.local_maxima(x_3d) assert result_3d.dtype == np.bool assert_equal(result_3d, expected_3d)
def test_selem(self): """Test results if selem is given.""" selem_cross = np.array( [[0, 1, 0], [1, 1, 1], [0, 1, 0]], dtype=np.bool) result_selem_cross = extrema.local_maxima( self.image, selem=selem_cross) assert result_selem_cross.dtype == np.bool assert_equal(result_selem_cross, self.expected_cross) for selem in [ ((True,) * 3,) * 3, np.ones((3, 3), dtype=np.float64), np.ones((3, 3), dtype=np.uint8), np.ones((3, 3), dtype=np.bool), ]: # Test different dtypes for selem which expects a boolean array but # will accept and convert other types if possible result_selem_square = extrema.local_maxima(self.image, selem=selem) assert result_selem_square.dtype == np.bool assert_equal(result_selem_square, self.expected_default) selem_x = np.array([[1, 0, 1], [0, 1, 0], [1, 0, 1]], dtype=np.bool) expected_selem_x = np.array( [[1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0], [1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0]], dtype=np.bool ) result_selem_x = extrema.local_maxima(self.image, selem=selem_x) assert result_selem_x.dtype == np.bool assert_equal(result_selem_x, expected_selem_x)
def test_empty(self): """Test result with empty image.""" result = extrema.local_maxima(np.array([]), indices=False) assert result.size == 0 assert result.dtype == np.uint8 result = extrema.local_maxima(np.array([]), indices=True) assert result.size == 0 assert result.dtype == np.intp
def test_indices(self): """Test output if indices of peaks are desired.""" # Connectivity 1 expected_conn1 = np.nonzero(self.expected_cross) result_conn1 = extrema.local_maxima(self.image, connectivity=1, indices=True) assert_equal(result_conn1, expected_conn1) # Connectivity 2 expected_conn2 = np.nonzero(self.expected_default) result_conn2 = extrema.local_maxima(self.image, connectivity=2, indices=True) assert_equal(result_conn2, expected_conn2)
def test_indices(self): """Test output if indices of peaks are desired.""" # Connectivity 1 expected_conn1 = np.nonzero(self.expected_cross) result_conn1 = extrema.local_maxima(self.image, connectivity=1, indices=True) assert_equal(result_conn1, expected_conn1) # Connectivity 2 expected_conn2 = np.nonzero(self.expected_default) result_conn2 = extrema.local_maxima(self.image, connectivity=2, indices=True) assert_equal(result_conn2, expected_conn2)
def test_connectivity(self): """Test results if selem is a scalar.""" # Connectivity 1: generates cross shaped structuring element result_conn1 = extrema.local_maxima(self.image, connectivity=1) assert_equal(result_conn1, self.expected_cross) # Connectivity 2: generates square shaped structuring element result_conn2 = extrema.local_maxima(self.image, connectivity=2) assert_equal(result_conn2, self.expected_default) # Connectivity 3: generates square shaped structuring element result_conn3 = extrema.local_maxima(self.image, connectivity=3) assert_equal(result_conn3, self.expected_default)
def test_connectivity(self): """Test results if footprint is a scalar.""" # Connectivity 1: generates cross shaped footprint result_conn1 = extrema.local_maxima(self.image, connectivity=1) assert result_conn1.dtype == bool assert_equal(result_conn1, self.expected_cross) # Connectivity 2: generates square shaped footprint result_conn2 = extrema.local_maxima(self.image, connectivity=2) assert result_conn2.dtype == bool assert_equal(result_conn2, self.expected_default) # Connectivity 3: generates square shaped footprint result_conn3 = extrema.local_maxima(self.image, connectivity=3) assert result_conn3.dtype == bool assert_equal(result_conn3, self.expected_default)
def test_local_maxima(self): "local maxima for various data types" data = np.array([[10, 11, 13, 14, 14, 15, 14, 14, 13, 11], [11, 13, 15, 16, 16, 16, 16, 16, 15, 13], [13, 15, 40, 40, 18, 18, 18, 60, 60, 15], [14, 16, 40, 40, 19, 19, 19, 60, 60, 16], [14, 16, 18, 19, 19, 19, 19, 19, 18, 16], [15, 16, 18, 19, 19, 20, 19, 19, 18, 16], [14, 16, 18, 19, 19, 19, 19, 19, 18, 16], [14, 16, 80, 80, 19, 19, 19, 100, 100, 16], [13, 15, 80, 80, 18, 18, 18, 100, 100, 15], [11, 13, 15, 16, 16, 16, 16, 16, 15, 13]], dtype=np.uint8) expected_result = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=np.uint8) for dtype in [np.uint8, np.uint64, np.int8, np.int64]: test_data = data.astype(dtype) out = extrema.local_maxima(test_data) error = diff(expected_result, out) assert error < eps assert out.dtype == expected_result.dtype
def get_maxima_points(boundary_points, img, sigma=0.3 ): width = img.shape[0] height = img.shape[1] canvas = Image.new('L', (width, height), 0) ImageDraw.Draw(canvas).polygon(boundary_points, outline=1, fill=1) mask = np.array(canvas) transformed_image = ndimage.distance_transform_edt(mask) normalized_ti =transformed_image/np.max(transformed_image) laplacian2 = ndimage.gaussian_laplace(normalized_ti, sigma=sigma) plt.figure(figsize=(10,10)) plt.imshow(laplacian2) plt.colorbar() plt.show() local_maxima = extrema.local_maxima(1-laplacian2) label_maxima = label(local_maxima) plt.figure(figsize=(10,10)) plt.imshow(label_maxima) plt.colorbar() plt.show() np.unique(label_maxima) all_inside_y, all_inside_x = np.where(label_maxima>1) all_points =[] for x,y in zip(all_inside_x, all_inside_y): all_points.append(tuple((x,y))) return all_points
def test_exceptions(self): """Test if input validation triggers correct exceptions.""" # Mismatching number of dimensions with raises(ValueError, match="number of dimensions"): extrema.local_maxima(self.image, selem=np.ones((3, 3, 3))) with raises(ValueError, match="number of dimensions"): extrema.local_maxima(self.image, selem=np.ones((3,))) # All dimensions in selem must be of size 3 with raises(ValueError, match="dimension size"): extrema.local_maxima(self.image, selem=np.ones((2, 3))) with raises(ValueError, match="dimension size"): extrema.local_maxima(self.image, selem=np.ones((5, 5))) with raises(TypeError, match="float16 which is not supported"): extrema.local_maxima(np.empty(1, dtype=np.float16))
def test_dtypes_old(self): """ Test results with default configuration and data copied from old unit tests for all supported dtypes. """ data = np.array( [[10, 11, 13, 14, 14, 15, 14, 14, 13, 11], [11, 13, 15, 16, 16, 16, 16, 16, 15, 13], [13, 15, 40, 40, 18, 18, 18, 60, 60, 15], [14, 16, 40, 40, 19, 19, 19, 60, 60, 16], [14, 16, 18, 19, 19, 19, 19, 19, 18, 16], [15, 16, 18, 19, 19, 20, 19, 19, 18, 16], [14, 16, 18, 19, 19, 19, 19, 19, 18, 16], [14, 16, 80, 80, 19, 19, 19, 100, 100, 16], [13, 15, 80, 80, 18, 18, 18, 100, 100, 15], [11, 13, 15, 16, 16, 16, 16, 16, 15, 13]], dtype=np.uint8 ) expected = np.array( [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=np.uint8 ) for dtype in self.supported_dtypes: image = data.astype(dtype) result = extrema.local_maxima(image) assert_equal(result, expected)
def test_extrema_float(self): """Specific tests for float type.""" # Copied from old unit test for local_maxma image = np.array( [[0.10, 0.11, 0.13, 0.14, 0.14, 0.15, 0.14, 0.14, 0.13, 0.11], [0.11, 0.13, 0.15, 0.16, 0.16, 0.16, 0.16, 0.16, 0.15, 0.13], [0.13, 0.15, 0.40, 0.40, 0.18, 0.18, 0.18, 0.60, 0.60, 0.15], [0.14, 0.16, 0.40, 0.40, 0.19, 0.19, 0.19, 0.60, 0.60, 0.16], [0.14, 0.16, 0.18, 0.19, 0.19, 0.19, 0.19, 0.19, 0.18, 0.16], [0.15, 0.182, 0.18, 0.19, 0.204, 0.20, 0.19, 0.19, 0.18, 0.16], [0.14, 0.16, 0.18, 0.19, 0.19, 0.19, 0.19, 0.19, 0.18, 0.16], [0.14, 0.16, 0.80, 0.80, 0.19, 0.19, 0.19, 1.0, 1.0, 0.16], [0.13, 0.15, 0.80, 0.80, 0.18, 0.18, 0.18, 1.0, 1.0, 0.15], [0.11, 0.13, 0.15, 0.16, 0.16, 0.16, 0.16, 0.16, 0.15, 0.13]], dtype=np.float32) inverted_image = 1.0 - image expected_result = np.array( [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=np.bool) # Test for local maxima with automatic step calculation result = extrema.local_maxima(image) assert result.dtype == np.bool assert_equal(result, expected_result) # Test for local minima with automatic step calculation result = extrema.local_minima(inverted_image) assert result.dtype == np.bool assert_equal(result, expected_result)
def test_3d(self): """tests the detection of maxima in 3D.""" img = np.zeros((8, 8, 8), dtype=np.uint8) local_maxima = np.zeros((8, 8, 8), dtype=np.uint8) # first maximum: only one pixel img[1, 1:3, 1:3] = 100 img[2, 2, 2] = 200 img[3, 1:3, 1:3] = 100 local_maxima[2, 2, 2] = 1 # second maximum: three pixels in z-direction img[5:8, 1, 1] = 200 local_maxima[5:8, 1, 1] = 1 # third: two maxima in 0 and 3. img[0, 5:8, 5:8] = 200 img[1, 6, 6] = 100 img[2, 5:7, 5:7] = 200 img[0:3, 5:8, 5:8] += 50 local_maxima[0, 5:8, 5:8] = 1 local_maxima[2, 5:7, 5:7] = 1 # four : one maximum in the corner of the square img[6:8, 6:8, 6:8] = 200 img[7, 7, 7] = 255 local_maxima[7, 7, 7] = 1 se = ndi.generate_binary_structure(3, 1) out = extrema.local_maxima(img, se) error = diff(local_maxima, out) assert error < eps
def test_empty(self): """Test result with empty image.""" result = extrema.local_maxima(np.array([[]]), indices=False) assert result.size == 0 assert result.dtype == np.bool assert result.shape == (1, 0) result = extrema.local_maxima(np.array([]), indices=True) assert isinstance(result, tuple) assert len(result) == 1 assert result[0].size == 0 assert result[0].dtype == np.intp result = extrema.local_maxima(np.array([[]]), indices=True) assert isinstance(result, tuple) assert len(result) == 2 assert result[0].size == 0 assert result[0].dtype == np.intp assert result[1].size == 0 assert result[1].dtype == np.intp
def test_empty(self): """Test result with empty image.""" result = extrema.local_maxima(np.array([[]]), indices=False) assert result.size == 0 assert result.dtype == np.bool assert result.shape == (1, 0) result = extrema.local_maxima(np.array([]), indices=True) assert isinstance(result, tuple) assert len(result) == 1 assert result[0].size == 0 assert result[0].dtype == np.intp result = extrema.local_maxima(np.array([[]]), indices=True) assert isinstance(result, tuple) assert len(result) == 2 assert result[0].size == 0 assert result[0].dtype == np.intp assert result[1].size == 0 assert result[1].dtype == np.intp
def test_allow_borders(self): """Test maxima detection at the image border.""" # Use connectivity 1 to allow many maxima, only filtering at border is # of interest result_with_boder = extrema.local_maxima( self.image, connectivity=1, allow_borders=True) assert_equal(result_with_boder, self.expected_cross) expected_without_border = np.array( [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0], [0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=np.uint8 ) result_without_border = extrema.local_maxima( self.image, connectivity=1, allow_borders=False) assert_equal(result_without_border, expected_without_border)
def test_constant(self): """Test behaviour for 'flat' images.""" const_image = np.full((7, 6), 42, dtype=np.uint8) expected = np.zeros((7, 6), dtype=np.uint8) for dtype in self.supported_dtypes: const_image = const_image.astype(dtype) # test for local maxima result = extrema.local_maxima(const_image) assert_equal(result, expected) # test for local minima result = extrema.local_minima(const_image) assert_equal(result, expected)
def test_small_array(self): """Test output for arrays with dimension smaller 3. If any dimension of an array is smaller than 3 and `allow_borders` is false a structuring element, which has at least 3 elements in each dimension, can't be applied. This is an implementation detail so `local_maxima` should still return valid output (see gh-3261). If `allow_borders` is true the array is padded internally and there is no problem. """ warning_msg = "maxima can't exist .* any dimension smaller 3 .*" x = np.array([0, 1]) extrema.local_maxima(x, allow_borders=True) # no warning with warns(UserWarning, match=warning_msg): result = extrema.local_maxima(x, allow_borders=False) assert_equal(result, [0, 0]) assert result.dtype == np.bool x = np.array([[1, 2], [2, 2]]) extrema.local_maxima(x, allow_borders=True, indices=True) # no warning with warns(UserWarning, match=warning_msg): result = extrema.local_maxima(x, allow_borders=False, indices=True) assert_equal(result, np.zeros((2, 0), dtype=np.intp)) assert result[0].dtype == np.intp assert result[1].dtype == np.intp
def test_small_array(self): """Test output for arrays with dimension smaller 3. If any dimension of an array is smaller than 3 and `allow_borders` is false a structuring element, which has at least 3 elements in each dimension, can't be applied. This is an implementation detail so `local_maxima` should still return valid output (see gh-3261). If `allow_borders` is true the array is padded internally and there is no problem. """ warning_msg = "maxima can't exist .* any dimension smaller 3 .*" x = np.array([0, 1]) extrema.local_maxima(x, allow_borders=True) # no warning with warns(UserWarning, match=warning_msg): result = extrema.local_maxima(x, allow_borders=False) assert_equal(result, [0, 0]) assert result.dtype == np.bool x = np.array([[1, 2], [2, 2]]) extrema.local_maxima(x, allow_borders=True, indices=True) # no warning with warns(UserWarning, match=warning_msg): result = extrema.local_maxima(x, allow_borders=False, indices=True) assert_equal(result, np.zeros((2, 0), dtype=np.intp)) assert result[0].dtype == np.intp assert result[1].dtype == np.intp
def test_selem(self): """Test results if selem is an array.""" selem_cross = np.array([[0, 1, 0], [1, 1, 1], [0, 1, 0]]) result_selem_cross = extrema.local_maxima(self.image, selem=selem_cross) assert_equal(result_selem_cross, self.expected_cross) selem_square = np.ones((3, 3), dtype=np.uint8) result_selem_square = extrema.local_maxima(self.image, selem=selem_square) assert_equal(result_selem_square, self.expected_default) selem_x = np.array([[1, 0, 1], [0, 1, 0], [1, 0, 1]]) expected_selem_x = np.array( [[1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0], [1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0]], dtype=np.uint8) result_selem_x = extrema.local_maxima(self.image, selem=selem_x) assert_equal(result_selem_x, expected_selem_x)
def test_extrema_float(self): "specific tests for float type" data = np.array( [[0.10, 0.11, 0.13, 0.14, 0.14, 0.15, 0.14, 0.14, 0.13, 0.11], [0.11, 0.13, 0.15, 0.16, 0.16, 0.16, 0.16, 0.16, 0.15, 0.13], [0.13, 0.15, 0.40, 0.40, 0.18, 0.18, 0.18, 0.60, 0.60, 0.15], [0.14, 0.16, 0.40, 0.40, 0.19, 0.19, 0.19, 0.60, 0.60, 0.16], [0.14, 0.16, 0.18, 0.19, 0.19, 0.19, 0.19, 0.19, 0.18, 0.16], [0.15, 0.182, 0.18, 0.19, 0.204, 0.20, 0.19, 0.19, 0.18, 0.16], [0.14, 0.16, 0.18, 0.19, 0.19, 0.19, 0.19, 0.19, 0.18, 0.16], [0.14, 0.16, 0.80, 0.80, 0.19, 0.19, 0.19, 1.0, 1.0, 0.16], [0.13, 0.15, 0.80, 0.80, 0.18, 0.18, 0.18, 1.0, 1.0, 0.15], [0.11, 0.13, 0.15, 0.16, 0.16, 0.16, 0.16, 0.16, 0.15, 0.13]], dtype=np.float32) inverted_data = 1.0 - data expected_result = np.array( [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=np.uint8) # test for local maxima with automatic step calculation out = extrema.local_maxima(data) error = diff(expected_result, out) assert error < eps # test for local minima with automatic step calculation out = extrema.local_minima(inverted_data) error = diff(expected_result, out) assert error < eps out = extrema.h_maxima(data, 0.003) expected_result = np.array( [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=np.uint8) error = diff(expected_result, out) assert error < eps out = extrema.h_minima(inverted_data, 0.003) error = diff(expected_result, out) assert error < eps
def test_selem(self): """Test results if selem is an array.""" selem_cross = np.array([[0, 1, 0], [1, 1, 1], [0, 1, 0]]) result_selem_cross = extrema.local_maxima( self.image, selem=selem_cross) assert_equal(result_selem_cross, self.expected_cross) selem_square = np.ones((3, 3), dtype=np.uint8) result_selem_square = extrema.local_maxima( self.image, selem=selem_square) assert_equal(result_selem_square, self.expected_default) selem_x = np.array([[1, 0, 1], [0, 1, 0], [1, 0, 1]]) expected_selem_x = np.array( [[1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0], [1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0]], dtype=np.uint8 ) result_selem_x = extrema.local_maxima(self.image, selem=selem_x) assert_equal(result_selem_x, expected_selem_x)
def test_local_extrema_uniform(self): "local extrema tests for uniform arrays with various data types" data = np.full((7, 6), 42, dtype=np.uint8) expected_result = np.zeros((7, 6), dtype=np.uint8) for dtype in [np.uint8, np.uint64, np.int8, np.int64]: data = data.astype(dtype) # test for local maxima out = extrema.local_maxima(data) error = diff(expected_result, out) assert error < eps assert out.dtype == expected_result.dtype # test for local minima out = extrema.local_minima(data) error = diff(expected_result, out) assert error < eps assert out.dtype == expected_result.dtype
def test_extrema_float(self): """Specific tests for float type.""" # Copied from old unit test for local_maxma image = np.array( [[0.10, 0.11, 0.13, 0.14, 0.14, 0.15, 0.14, 0.14, 0.13, 0.11], [0.11, 0.13, 0.15, 0.16, 0.16, 0.16, 0.16, 0.16, 0.15, 0.13], [0.13, 0.15, 0.40, 0.40, 0.18, 0.18, 0.18, 0.60, 0.60, 0.15], [0.14, 0.16, 0.40, 0.40, 0.19, 0.19, 0.19, 0.60, 0.60, 0.16], [0.14, 0.16, 0.18, 0.19, 0.19, 0.19, 0.19, 0.19, 0.18, 0.16], [0.15, 0.182, 0.18, 0.19, 0.204, 0.20, 0.19, 0.19, 0.18, 0.16], [0.14, 0.16, 0.18, 0.19, 0.19, 0.19, 0.19, 0.19, 0.18, 0.16], [0.14, 0.16, 0.80, 0.80, 0.19, 0.19, 0.19, 1.0, 1.0, 0.16], [0.13, 0.15, 0.80, 0.80, 0.18, 0.18, 0.18, 1.0, 1.0, 0.15], [0.11, 0.13, 0.15, 0.16, 0.16, 0.16, 0.16, 0.16, 0.15, 0.13]], dtype=np.float32 ) inverted_image = 1.0 - image expected_result = np.array( [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=np.bool ) # Test for local maxima with automatic step calculation result = extrema.local_maxima(image) assert result.dtype == np.bool assert_equal(result, expected_result) # Test for local minima with automatic step calculation result = extrema.local_minima(inverted_image) assert result.dtype == np.bool assert_equal(result, expected_result)
def distance_transform_seeds(image_data): """Create seed locations maximally distant from thresholded raw image. Parameters ---------- image_data : ndarray Returns ------- list of ndarray """ seeds = [] if image_data.dtype == np.bool: #assuming membrane zero and cells one labeled thresh = image_data else: # otsu thresholding thresh = image_data < filters.threshold_otsu(image_data) transform = ndimage.distance_transform_cdt(thresh) skmax = extrema.local_maxima(transform) seeds = np.transpose(np.nonzero(skmax)) return seeds
def localMaximaBlobDetection(image_path: str): image = io.imread(image_path) local_maxima = extrema.local_maxima(image)
def test_extrema_float(self): "specific tests for float type" data = np.array([[0.10, 0.11, 0.13, 0.14, 0.14, 0.15, 0.14, 0.14, 0.13, 0.11], [0.11, 0.13, 0.15, 0.16, 0.16, 0.16, 0.16, 0.16, 0.15, 0.13], [0.13, 0.15, 0.40, 0.40, 0.18, 0.18, 0.18, 0.60, 0.60, 0.15], [0.14, 0.16, 0.40, 0.40, 0.19, 0.19, 0.19, 0.60, 0.60, 0.16], [0.14, 0.16, 0.18, 0.19, 0.19, 0.19, 0.19, 0.19, 0.18, 0.16], [0.15, 0.182, 0.18, 0.19, 0.204, 0.20, 0.19, 0.19, 0.18, 0.16], [0.14, 0.16, 0.18, 0.19, 0.19, 0.19, 0.19, 0.19, 0.18, 0.16], [0.14, 0.16, 0.80, 0.80, 0.19, 0.19, 0.19, 1.0, 1.0, 0.16], [0.13, 0.15, 0.80, 0.80, 0.18, 0.18, 0.18, 1.0, 1.0, 0.15], [0.11, 0.13, 0.15, 0.16, 0.16, 0.16, 0.16, 0.16, 0.15, 0.13]], dtype=np.float32) inverted_data = 1.0 - data expected_result = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=np.uint8) # test for local maxima with automatic step calculation out = extrema.local_maxima(data) error = diff(expected_result, out) assert error < eps # test for local minima with automatic step calculation out = extrema.local_minima(inverted_data) error = diff(expected_result, out) assert error < eps out = extrema.h_maxima(data, 0.003) expected_result = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=np.uint8) error = diff(expected_result, out) assert error < eps out = extrema.h_minima(inverted_data, 0.003) error = diff(expected_result, out) assert error < eps
def buttonSave(arg): copy = arg[1] imageTemp = arg[2] filterTry = filterVar.get() if (filterTry == 1): copy = cv2.GaussianBlur(copy, (5, 5), 0) elif (filterTry == 2): copy = cv2.Canny(copy, 100, 150) elif (filterTry == 3): copy = filters.roberts(imageTemp) elif (filterTry == 4): copy = filters.sato(imageTemp) elif (filterTry == 5): copy = filters.scharr(imageTemp) elif (filterTry == 6): copy = filters.sobel(imageTemp) elif (filterTry == 7): copy = filters.unsharp_mask(copy, radius=30, amount=3) elif (filterTry == 8): #copy = filters.median(imageTemp, disk(5)) b, g, r = cv2.split(copy) b = filters.median(b, disk(5)) g = filters.median(g, disk(5)) r = filters.median(r, disk(5)) copy = cv2.merge((b, g, r)) elif (filterTry == 9): copy = filters.prewitt(imageTemp) elif (filterTry == 10): copy = filters.rank.modal(imageTemp, disk(5)) flag = 0 if (np.ndim(copy) == 2): flag = 0 else: flag = 1 if (hEsitleme.get() or hGrafik.get()): if (flag): copy = cv2.cvtColor(copy, cv2.COLOR_BGR2GRAY) if (hGrafik.get()): plt.hist(copy.ravel(), 256, [0, 256]) plt.show() if (hEsitleme.get()): copy = cv2.equalizeHist(copy) if (uzaysalVars[0].get()): reScaleRatio = float(uzaysalVarsInputs[0].get()) if (np.ndim(copy) == 3): b, g, r = cv2.split(copy) b = transform.rescale(b, reScaleRatio) g = transform.rescale(g, reScaleRatio) r = transform.rescale(r, reScaleRatio) copy = cv2.merge((b, g, r)) else: copy = transform.rescale(copy, reScaleRatio) if (uzaysalVars[1].get()): resizeY = float(uzaysalVarsInputs[1].get()) resizeX = float(uzaysalVarsInputs[2].get()) if (np.ndim(copy) == 3): b, g, r = cv2.split(copy) b = transform.resize( b, (b.shape[0] // resizeX, b.shape[1] // resizeY), anti_aliasing=True) g = transform.resize( g, (g.shape[0] // resizeX, g.shape[1] // resizeY), anti_aliasing=True) r = transform.resize( r, (r.shape[0] // resizeX, r.shape[1] // resizeY), anti_aliasing=True) copy = cv2.merge((b, g, r)) else: copy = transform.resize( copy, (copy.shape[0] // resizeX, copy.shape[1] // resizeY), anti_aliasing=True) if (uzaysalVars[2].get()): copy = transform.swirl(copy, rotation=0, strength=10, radius=120) if (uzaysalVars[3].get()): copy = transform.rotate(copy, int(uzaysalVarsInputs[3].get()), resize=True) if (uzaysalVars[4].get()): copy = copy[:, ::-1] if (yogunlukVars[0].get() or yogunlukVars[1].get()): if (yogunlukVars[0].get()): startINX = int(yogunlukVars[2].get()) finishINX = int(yogunlukVars[3].get()) copy = exposure.rescale_intensity(copy, in_range=(startINX, finishINX)) if (yogunlukVars[1].get()): startOUTX = int(yogunlukVars[4].get()) finishOUTX = int(yogunlukVars[5].get()) copy = exposure.rescale_intensity(copy, out_range=(startOUTX, finishOUTX)) morfoTry = morfVar.get() morfoGirisN = 0 if (np.ndim(copy) == 3): morfoGirisN = 1 if (morfoTry == 1): if (morfoGirisN): b, g, r = cv2.split(copy) b = morphology.area_closing(b, 128, 9) g = morphology.area_closing(g, 128, 9) r = morphology.area_closing(r, 128, 9) copy = cv2.merge((b, g, r)) else: copy = morphology.area_closing(copy) elif (morfoTry == 2): if (morfoGirisN): b, g, r = cv2.split(copy) b = morphology.area_opening(b, 128, 9) g = morphology.area_opening(g, 128, 9) r = morphology.area_opening(r, 128, 9) copy = cv2.merge((b, g, r)) else: copy = morphology.area_opening(copy) elif (morfoTry == 3): if (morfoGirisN): b, g, r = cv2.split(copy) b = morphology.erosion(b, disk(6)) g = morphology.erosion(g, disk(6)) r = morphology.erosion(r, disk(6)) copy = cv2.merge((b, g, r)) else: copy = morphology.erosion(copy, disk(6)) elif (morfoTry == 4): if (morfoGirisN): b, g, r = cv2.split(copy) b = morphology.dilation(b, disk(6)) g = morphology.dilation(g, disk(6)) r = morphology.dilation(r, disk(6)) copy = cv2.merge((b, g, r)) else: copy = morphology.dilation(copy, disk(6)) elif (morfoTry == 5): if (morfoGirisN): b, g, r = cv2.split(copy) b = morphology.opening(b, disk(6)) g = morphology.opening(g, disk(6)) r = morphology.opening(r, disk(6)) copy = cv2.merge((b, g, r)) else: copy = morphology.opening(copy, disk(6)) elif (morfoTry == 6): if (morfoGirisN): b, g, r = cv2.split(copy) b = morphology.closing(b, disk(6)) g = morphology.opening(g, disk(6)) r = morphology.opening(r, disk(6)) copy = cv2.merge((b, g, r)) else: copy = morphology.opening(copy, disk(6)) elif (morfoTry == 7): if (morfoGirisN): b, g, r = cv2.split(copy) b = morphology.white_tophat(b, disk(6)) g = morphology.white_tophat(g, disk(6)) r = morphology.white_tophat(r, disk(6)) copy = cv2.merge((b, g, r)) else: copy = morphology.white_tophat(copy, disk(6)) elif (morfoTry == 8): if (morfoGirisN): b, g, r = cv2.split(copy) b = morphology.black_tophat(b, disk(6)) g = morphology.black_tophat(g, disk(6)) r = morphology.black_tophat(r, disk(6)) copy = cv2.merge((b, g, r)) else: copy = morphology.black_tophat(copy, disk(6)) elif (morfoTry == 10): if (morfoGirisN): copy = cv2.cvtColor(copy, cv2.COLOR_BGR2GRAY) copy = exposure.rescale_intensity(copy) local_maxima = extrema.local_maxima(copy) label_maxima = measure.label(local_maxima) copy = color.label2rgb(label_maxima, copy, alpha=0.7, bg_label=0, bg_color=None, colors=[(1, 0, 0)]) elif (morfoTry == 9): if (morfoGirisN): copy = cv2.cvtColor(copy, cv2.COLOR_BGR2GRAY) copy = exposure.rescale_intensity(copy) h = 0.05 h_maxima = extrema.h_maxima(copy, h) label_h_maxima = measure.label(h_maxima) copy = color.label2rgb(label_h_maxima, copy, alpha=0.7, bg_label=0, bg_color=None, colors=[(1, 0, 0)]) arg[1] = copy arg[2] = imageTemp cv2.imshow("org", copy) cv2.waitKey(0) cv2.destroyAllWindows() """
img = color.rgb2gray( io.imread('E:/OwnWork/Leaf/TestImage/Deliveryimage/1.jpg')) # the rescaling is done only for visualization purpose. # the algorithms would work identically in an unscaled version of the # image. However, the parameter h needs to be adapted to the scale. img = exposure.rescale_intensity(img) ############################################################## # MAXIMA DETECTION # Maxima in the galaxy image are detected by mathematical morphology. # There is no a priori constraint on the density. # We find all local maxima local_maxima = extrema.local_maxima(img) label_maxima = label(local_maxima) overlay = color.label2rgb(label_maxima, img, alpha=0.7, bg_label=0, bg_color=None, colors=[(1, 0, 0)]) # We observed in the previous image, that there are many local maxima # that are caused by the noise in the image. # For this, we find all local maxima with a height of h. # This height is the gray level value by which we need to descent # in order to reach a higher maximum and it can be seen as a local # contrast measurement. # The value of h scales with the dynamic range of the image, i.e.
def test_dtypes(self): """Test results with default configuration for all supported dtypes.""" for dtype in self.supported_dtypes: result = extrema.local_maxima(self.image.astype(dtype)) assert result.dtype == np.bool assert_equal(result, self.expected_default)
def test_dtypes(self): """Test results with default configuration for all supported dtypes.""" for dtype in self.supported_dtypes: result = extrema.local_maxima(self.image.astype(dtype)) assert result.dtype == np.bool assert_equal(result, self.expected_default)
from PIL import Image from skimage.feature import peak_local_max # %% img = Image.open('C:\\Users\\Dell\\Desktop\\od_zacatku\\train_img\\train4.tiff') imarray = np.array(img) h = 0.3 x_0 = 70 y_0 = 354 width = 256 height = 256 imarray = exposure.rescale_intensity(imarray) local_maxima = extrema.local_maxima(imarray) label_maxima = label(local_maxima) print(label_maxima.shape) print(imarray.shape) print(label_maxima.dtype) print(imarray.dtype) overlay = color.label2rgb(label_maxima, imarray, alpha=0.3, bg_label=0, bg_color=None, colors=[(1, 0, 0)]) h_maxima = extrema.h_maxima(imarray, h) label_h_maxima = label(h_maxima) overlay_h = color.label2rgb(label_h_maxima, imarray, alpha=0.3, bg_label=0, bg_color=None, colors=[(1, 0, 0)])
img = color.rgb2gray(color_image)[y_0:(y_0 + height), x_0:(x_0 + width)] # the rescaling is done only for visualization purpose. # the algorithms would work identically in an unscaled version of the # image. However, the parameter h needs to be adapted to the scale. img = exposure.rescale_intensity(img) ############################################################## # MAXIMA DETECTION # Maxima in the galaxy image are detected by mathematical morphology. # There is no a priori constraint on the density. # We find all local maxima local_maxima = extrema.local_maxima(img) label_maxima = label(local_maxima) overlay = color.label2rgb(label_maxima, img, alpha=0.7, bg_label=0, bg_color=None, colors=[(1, 0, 0)]) # We observed in the previous image, that there are many local maxima # that are caused by the noise in the image. # For this, we find all local maxima with a height of h. # This height is the gray level value by which we need to descent # in order to reach a higher maximum and it can be seen as a local # contrast measurement. # The value of h scales with the dynamic range of the image, i.e. # if we multiply the image with a constant, we need to multiply # the value of h with the same constant in order to achieve the same result. h = 0.05 h_maxima = extrema.h_maxima(img, h)
def MPE(img, folder, original_img, YN_binary, nbOfRowPerPlot, nbOfColumnPerPlot, globalOrientation, noise, field_image, aff, y_offset, x_offset): ''' Identifies and crop the columns and the rows of the field. 12 inputs: img: array of lists Binary image of the original image read in openCV folder: path Absolute path to the folder in which all is saved original_img: array of lists Original image read in openCV YN_binary: bolean Equals True if the original image is a binary nbOfRowPerPlot: int Number of row per microplot nbOfColumnPerPlot: int Number of column per microplot globalOrientation: str ('V' or 'H') Global orientation of the column as inputted by the user noise: int Noise removal value field_image: Path object absolute path to the original image aff: Affine object OR int (0) Affine transformation matrix associated with the original image georeferencement, project the calculated points into its CRS Equals zero if the original image is not georeferenced y_offset: int The vertical distance that has been cropped and should be considered for the coordinates calculation x_offset: int The horizontal distance that has been cropped and should be considered for the coordinates calculation Outputs: none Returns number if there is an error which will trigger a pop up displaying a message. Returns 'OK' if the end has been reached. ''' ####################################################################### ####################### ROTATE THE BINARY IMAGE ####################### ####################################################################### # get all coordinates of the white pixels i.e. plants coords_angle = np.column_stack(np.where(img > 0)) # use these coordinates to compute a rotated bounding box that contains all # coordinates angle = cv2.minAreaRect(coords_angle)[-1] # the 'cv2.minAreaRect' function returns values in the # range [-90, 0[ ; we want it positive if angle < -45: angle = -(90 + angle) # otherwise, just take the inverse of the angle to make # it positive else: angle = -angle # if the rows are orginally horizontal, we want them to become vertical if globalOrientation == 'H': angle += 90 print('ANGLE: ' + str(angle)) img_binary = img.copy() img_rotated, add_y, add_x = rotate_bound(img.astype(np.uint8), angle, change_bigger=True) cv2.imwrite(str(folder / 'Binary_straight.jpg'), img_rotated) # make a skeleton of the binary image so that clusters will be in the # middle of the rows, then erode and dilate to erase weeds and connect # broken lines # parameters (horizontal array) param_binaryErosion = np.ones((1, 20)) param_skeletonErosion = np.ones((1, 5)) param_skeletonDil = np.ones((1, 100)) # application binary_erode = morphology.binary_erosion(img_rotated, selem=param_binaryErosion) skeleton = morphology.skeletonize( (binary_erode * 1).astype(np.uint8)) * 255 cv2.imwrite(str(folder / 'Skeleton_original.jpg'), skeleton) skeleton = morphology.binary_erosion(skeleton, selem=param_skeletonErosion) skeleton = morphology.binary_dilation(skeleton, selem=param_skeletonDil) * 255 cv2.imwrite(str(folder / 'Skeleton_manipulated.jpg'), skeleton) ####################################################################### ########################### GET THE COLUMNS ########################### ####################################################################### # get local maxima on the whole binary picture local_maxima = extrema.local_maxima(skeleton) # sum the number of local maxima into a one-line array (i.e. number of # maxima in each column) sum_maxima = np.sum(local_maxima, axis=0).astype(float) # make a copy sum_maxima_nan = sum_maxima.copy() # replace 0 with NaN sum_maxima_nan[sum_maxima == 0] = np.nan # get the average number of maxmima for a column mean_line = np.nanmean(sum_maxima_nan) # erase all the values smaller than 1/3 of the average sum_maxima[sum_maxima < mean_line / 3] = 0 # draw the columns and save the corner points of each column area img, cut_points, col_w, img_core_col = draw_separation_lines( sum_maxima, rows_img=img_rotated, col=True) # if no points have been detected, it means the code is not working as it is if cut_points == []: return ('1') # save the image with the columns delimited cv2.imwrite(str(folder / 'Binary_columns_straight.jpg'), img) cv2.imwrite(str(folder / 'Binary_core_columns.jpg'), img_core_col) ## rotate the points of the separation lines and get the lines equations center = (img_binary.shape[0] / 2, img_binary.shape[1] / 2) cut_points = np.array(cut_points) # subtraction of the black pixels which had been added for the rotation cut_points[:, :, 0] = cut_points[:, :, 0] - add_x cut_points[:, :, 1] = cut_points[:, :, 1] - add_y # rotate the points back into the original angle cut_points = rotate(center, cut_points, math.radians(angle)) # get the line equations from points columns_a, columns_b = get_equations(cut_points) # rotate back the core column image img_core_col, _, _ = rotate_bound(img_core_col, -1 * angle) y = int((img_core_col.shape[0] - img_binary.shape[0]) / 2) x = int((img_core_col.shape[1] - img_binary.shape[1]) / 2) img_core_col = img_core_col[y:-y, x:-x] img_core_col = cv2.resize(img_core_col, img_binary.shape[::-1]) cv2.imwrite(str(folder / 'Binary_core.jpg'), img_core_col) ## cut the columns # create all the needed directories / check if existent / delete if necessary if YN_binary == False: sub_folder_columnOriginal = folder / str('Plot_columns_original') sub_folder_columnBinary = folder / str('Plot_columns_binary') sub_folder_columnCoreBinary = folder / str('Plot_columns_core') if not (sub_folder_columnBinary.is_dir()): if YN_binary == False: sub_folder_columnOriginal.mkdir() sub_folder_columnBinary.mkdir() sub_folder_columnCoreBinary.mkdir() # initialization maxY, maxX = img_binary.shape c = str(0).zfill(2) # only exists for saving names # for every detected column, with a step defined by the inputted number # nbOfColumnPerPlot in the GUI for k in range(0, len(columns_a), nbOfColumnPerPlot): # try first as it is (i.e. with that step value) try: n = nbOfColumnPerPlot - 1 #bc we want the end line pt1 = ((0 - columns_b[k][0]) / columns_a[k][0], 0) pt2 = ((0 - columns_b[k + n][1]) / columns_a[k + n][1], 0 ) #could have done [k+n+1][0] -> equivalent pt3 = ((maxY - columns_b[k + n][1]) / columns_a[k + n][1], maxY) pt4 = ((maxY - columns_b[k][0]) / columns_a[k][0], maxY) # all 4 points of one column, counter clock wise roi_corners = np.array([[pt1, pt2, pt3, pt4]], dtype=np.int32) # make a mask and crop out the current column mask = np.zeros(img_binary.shape, dtype=np.uint8) cv2.fillPoly(mask, roi_corners, (255, )) if YN_binary == False: column_original = cv2.bitwise_and(original_img, original_img, mask=mask) cv2.imwrite( str(sub_folder_columnOriginal / str('Plot_column_' + c + '_cropped.jpg')), column_original) # apply the mask and save the images column_binary = cv2.bitwise_and(img_binary, img_binary, mask=mask) cv2.imwrite( str(sub_folder_columnBinary / str('Plot_column_' + c + '_cropped.jpg')), column_binary) column_core = cv2.bitwise_and(img_core_col, img_core_col, mask=mask) cv2.imwrite( str(sub_folder_columnCoreBinary / str('Plot_column_' + c + '_cropped.jpg')), column_core) c = str(int(c) + 1).zfill(2) # if the number inputed is not proportional to the detected number of columns # then do one by one for what is left except IndexError: # same as before but one detected column at a time for i in range(k, len(columns_a)): pt1 = ((0 - columns_b[i][0]) / columns_a[i][0], 0) pt2 = ((0 - columns_b[i][1]) / columns_a[i][1], 0) pt3 = ((maxY - columns_b[i][1]) / columns_a[i][1], maxY) pt4 = ((maxY - columns_b[i][0]) / columns_a[i][0], maxY) # 4 column points, counter clockwise roi_corners = np.array([[pt1, pt2, pt3, pt4]], dtype=np.int32) # mask making mask = np.zeros(img_binary.shape, dtype=np.uint8) cv2.fillPoly(mask, roi_corners, (255, )) if YN_binary == False: column_original = cv2.bitwise_and(original_img, original_img, mask=mask) cv2.imwrite( str(sub_folder_columnOriginal / str('Plot_column_' + str(c) + '_cropped.jpg')), column_original) # applying mask and saving images column_binary = cv2.bitwise_and(img_binary, mask) cv2.imwrite( str(sub_folder_columnBinary / str('Plot_column_' + str(c) + '_cropped.jpg')), column_binary) column_core = cv2.bitwise_and(img_core_col, img_core_col, mask=mask) cv2.imwrite( str(sub_folder_columnCoreBinary / str('Plot_column_' + c + '_cropped.jpg')), column_core) c = str(int(c) + 1).zfill(2) ####################################################################### ############################# GET THE ROWS ############################ ####################################################################### # new angle to get the ROWS in a vertical state (i.e. columns are # oriented horizontally) angle_horiz = angle + 90 print('Horizontal angle : ' + str(angle_horiz)) # get all the files from the previous part, i.e. *binary* columns files = list(sub_folder_columnCoreBinary.glob('*.jpg')) # make all the necessary folders etc sub_folder_horizontalColumn = folder / 'Horizontal_columns' if YN_binary == False: sub_folder_rowOriginal = folder / str('Plot_rows_original') sub_folder_rowOriginalWhole = folder / str('Plot_rows_original_whole') else: sub_folder_rowOriginalWhole = folder / str('Plot_rows_binary_whole') sub_folder_rowBinary = folder / str('Plot_rows_binary') sub_folder_SHP = folder / str('SHP_files') if not (sub_folder_horizontalColumn.is_dir()): sub_folder_horizontalColumn.mkdir() if YN_binary == False: sub_folder_rowOriginal.mkdir() sub_folder_rowOriginalWhole.mkdir() sub_folder_rowBinary.mkdir() sub_folder_SHP.mkdir() # initialization maxY, maxX = img.shape nbOfRowPerColumn = 0 intersection, intersection_geo = [], [] nbOfColumn = len(columns_a) # for every file in the column file for nb in range(0, len(files)): # get the column number nb_column = str(nb).zfill(2) ## identify the rows # read the column file file_img = cv2.imread(str(files[nb]), 0) # rotate it until the column is horizontally oriented column_binary_rotate, add_y, add_x = rotate_bound(file_img, angle_horiz, change_bigger=True) # make the sum of all white pixels on one line sum_rows = np.sum(column_binary_rotate, axis=0).astype(float) # make a copy and replace 0 by nan to get the mean value of the sum without 0 sum_rows_nan = sum_rows.copy() sum_rows_nan[sum_rows == 0] = np.nan mean_line = np.nanmean(sum_rows_nan) # erase the values smaller than half of the mean sum_rows[sum_rows < mean_line / 2] = 0 # identify the rows with the changing pattern _, cut_points, w = draw_separation_lines(np.array(sum_rows), rows_img=column_binary_rotate) # if not separation lines has been detected, the code is not working # as it is if cut_points == []: # save the output image with separation lines for rows return ('2') cv2.imwrite( str(sub_folder_horizontalColumn / str('Rows_horizontal_delimited_column_' + str(nb_column) + '.jpg')), column_binary_rotate) ## get the points in the original angle # original center center = (img_binary.shape[0] / 2, img_binary.shape[1] / 2) cut_points = np.array(cut_points) # points without the added black border (in rotate_bound) cut_points[:, :, 0] = cut_points[:, :, 0] - add_x cut_points[:, :, 1] = cut_points[:, :, 1] - add_y # rotate the points cut_points = rotate(center, cut_points, math.radians(angle_horiz)) # get equations based on the points rows_a, rows_b = get_equations(cut_points) # initialization of various counts c = str(0).zfill(2) # for file names nbStartColumn = nb # start detected column number nbEndColumn = int( nbStartColumn) + nbOfColumnPerPlot - 1 # end detected column print('Column nb: ' + str(nb_column)) ### cut the rows # read the original column image current_column_binary = cv2.imread( str(sub_folder_columnBinary / files[nb].name), 0) if YN_binary == False: current_column_original = cv2.imread( str(sub_folder_columnOriginal / files[nb].name)) else: current_column_original = cv2.imread( str(sub_folder_columnBinary / files[nb].name), 0) # get the number of rows in this column nbOfRowPerColumn += len(rows_a) # for every row in that column, with a step defined by the inputted # number nbOfRowPerPlot in the GUI for k in range(0, len(rows_a), nbOfRowPerPlot): # try with this step first try: ### get the cut points of the row n = nbOfRowPerPlot - 1 # bc we want the end line of the end row pt1 = ((0 - rows_b[k][0]) / rows_a[k][0], 0) pt2 = ((0 - rows_b[k + n][1]) / rows_a[k + n][1], 0 ) #[k+n+1][0] would NOT be equivalent pt3 = ((maxY - rows_b[k + n][1]) / rows_a[k + n][1], maxY) pt4 = ((maxY - rows_b[k][0]) / rows_a[k][0], maxY) # get all the points counter-clockwise roi_corners = np.array([[pt1, pt2, pt3, pt4]], dtype=np.int32) # fill a mask mask = np.zeros(file_img.shape, dtype=np.uint8) cv2.fillPoly(mask, roi_corners, (255, )) # apply the mask to the column images (binary) row_binary = cv2.bitwise_and(current_column_binary, mask) cv2.imwrite( str(sub_folder_rowBinary / str('Plot_column_' + str(nb_column) + '_row_' + str(c) + '_cropped.jpg')), row_binary) # use a bounding box to only get the wanted part of the original # image i.e. the row and not all the black pixels around row_original = cv2.bitwise_and(current_column_original, current_column_original, mask=mask) if YN_binary == False: # get the coords for which pixel value =/= 0 coords = np.argwhere(row_original) # get the first pixels x0, y0, z = coords.min(axis=0) # get the last pixels x1, y1, z = coords.max(axis=0) + 1 # crop row_original_cropped = row_original[x0:x1, y0:y1] # save cv2.imwrite( str(sub_folder_rowOriginal / str('Plot_column_' + str(nb_column) + '_row_' + str(c) + '_cropped.jpg')), row_original_cropped) cv2.imwrite( str(sub_folder_rowOriginalWhole / str('Plot_column_' + str(nb_column) + '_row_' + str(c) + '_whole_pic.jpg')), row_original) # get the intersection of the lines between the considered # column and row (i.e. the 4 cropping points) inter, inter_geo = line_intersection( columns_a[nbStartColumn], columns_a[nbEndColumn], columns_b[nbStartColumn], columns_b[nbEndColumn], rows_a[k], rows_a[k + n], rows_b[k], rows_b[k + n], aff, y_offset, x_offset) # if the georeferenced points exist if type(inter_geo) != type(None): # make the shp files out of the 4 corner points make_shp(sub_folder_SHP, nb_column, c, inter_geo) # prepare the array to be saved inter_geo = [ item for sublist in inter_geo for item in sublist ] inter_geo.insert(0, c) inter_geo.insert(0, nb_column) intersection_geo.append(inter_geo) # if not georeference, use pixel values else: # make the shp files out of the 4 corner point make_shp(sub_folder_SHP, nb_column, c, inter) # get the points in a 8-elements list (no more tuples) inter = [item for sublist in inter for item in sublist] # insert row number at the begining inter.insert(0, c) # insert column number at the beginning inter.insert(0, nb_column) # "save" the list into "intersection" list intersection.append(inter) # add up 1 element for the next row c = str(int(c) + 1).zfill(2) # if the number inputed is not proportional to the detected # number of columns, then do one by one for what is left except IndexError: for i in range(k, len(rows_a)): pt1 = ((0 - rows_b[i][0]) / rows_a[i][0], 0) pt2 = ((0 - rows_b[i][1]) / rows_a[i][1], 0) pt3 = ((maxY - rows_b[i][1]) / rows_a[i][1], maxY) pt4 = ((maxY - rows_b[i][0]) / rows_a[i][0], maxY) roi_corners = np.array([[pt1, pt2, pt3, pt4]], dtype=np.int32) mask = np.zeros(img_binary.shape, dtype=np.uint8) cv2.fillPoly(mask, roi_corners, (255, )) row_binary = cv2.bitwise_and(current_column_binary, current_column_binary, mask=mask) cv2.imwrite( str(sub_folder_rowBinary / str('Plot_column_' + str(nb_column) + '_row_' + str(c) + '_cropped.jpg')), row_binary) row_original = cv2.bitwise_and(current_column_original, current_column_original, mask=mask) if YN_binary == False: coords = np.argwhere(row_original) x0, y0, z = coords.min(axis=0) x1, y1, z = coords.max( axis=0) + 1 # slices are exclusive at the top row_original_cropped = row_original[x0:x1, y0:y1] cv2.imwrite( str(sub_folder_rowOriginal / str('Plot_column_' + str(nb_column) + '_row_' + str(c) + '_cropped.jpg')), row_original_cropped) cv2.imwrite( str(sub_folder_rowOriginalWhole / str('Plot_column_' + str(nb_column) + '_row_' + str(c) + '_whole_pic.jpg')), row_original) # get the intersection between column and row considered inter, inter_geo = line_intersection( columns_a[nbStartColumn], columns_a[nbEndColumn], columns_b[nbStartColumn], columns_b[nbEndColumn], rows_a[i], rows_a[i], rows_b[i], rows_b[i], aff, y_offset, x_offset) if type(inter_geo) != type(None): # make the shp files out of the 4 corner points make_shp(sub_folder_SHP, nb_column, c, inter_geo) # prepare the array to be saved inter_geo = [ item for sublist in inter_geo for item in sublist ] inter_geo.insert(0, c) inter_geo.insert(0, nb_column) intersection_geo.append(inter_geo) # if not georeference, use pixel values else: # make the shp files out of the 4 corner point make_shp(sub_folder_SHP, nb_column, c, inter) inter = [item for sublist in inter for item in sublist] inter.insert(0, c) inter.insert(0, nb_column) intersection.append(inter) c = str(int(c) + 1).zfill(2) ### make a shp file with all individual shp merged # get all the shp absolute paths individual_shp_files = os.listdir(sub_folder_SHP) individual_shp_files = [ str(sub_folder_SHP / f) for f in individual_shp_files if '.shp' in f ] # make a shp file with the meta of the individual shp meta = fiona.open(individual_shp_files[0]).meta # write all the individual shp into the merging file with fiona.open(folder / 'All_plots.shp', 'w', **meta) as output: for k in individual_shp_files: with fiona.open(k) as f: for features in f: output.write(features) # get the average number of row per column nbOfRowPerColumn = nbOfRowPerColumn / nbOfColumn # save the metadata metadata(folder, field_image, noise, nbOfColumnPerPlot, nbOfRowPerPlot, globalOrientation, sub_folder_rowBinary, sub_folder_SHP, angle, nbOfColumn, nbOfRowPerColumn, intersection, aff, intersection_geo) return ('OK')
from skimage.morphology import watershed from skimage.feature import peak_local_max from skimage.morphology import extrema # load dtm image image = color.rgb2gray(io.imread('2092.jpg')) xsize=image.shape[0] ysize=image.shape[1] #img=resize(img, (int(img.shape[0] / 6), int(img.shape[1] / 6))) # k-means clustering of the image (population of pixels intensities) #image = image.reshape((-1, 1)) distance = ndi.distance_transform_edt(image) local_maxi = extrema.local_maxima(distance, image, np.ones((3, 3))) markers = ndi.label(local_maxi)[0] labels = watershed(-distance, markers, mask=image) ##distance = ndi.distance_transform_edt(image) ##local_maxi = peak_local_max( ## distance, indices=False, footprint=np.ones((3, 3)), labels=image) ##markers = measure.label(local_maxi) ##labels_ws = watershed(-distance, markers, mask=image) print(labels.shape) X_clustered=labels X_clustered.shape = image.shape
ax[1].axis('off') ax[1].set_title('Peak local max') fig.tight_layout() plt.show() ########################################### #prepare image for h_maxima and local_maxima functions img = color.rgb2gray(Color_Masked) img = 255 - img img = exposure.rescale_intensity(img) #extract local maxima local_maxima = extrema.local_maxima(img_gs_inv) label_maxima = label(local_maxima) overlay = color.label2rgb(label_maxima, img_gs_inv, alpha=0.7, bg_label=0, bg_color=None, colors=[(1, 0, 0)]) #local maxima with certrain contrast h = 0.05 ding = morphology.selem.disk(radius=3) h_maxima = extrema.h_maxima(img, h, selem=ding) label_h_maxima = label(h_maxima) overlay_h = color.label2rgb(label_h_maxima, img,