From 64e5ff860cd2db6cf841dd4a13748c34e2e6ef9f Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Wed, 5 Apr 2023 06:45:01 +1000 Subject: [PATCH] Fix failing regionprop_table for multichannel properties (#6861) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add test for multichannel weighted centroid * Return table is a dict, not a dataframe * Check shape with np.shape to support array-likes * test shape for rp0 as well as rp1 and rpm Co-authored-by: Lars GrĂ¼ter --- skimage/measure/_regionprops.py | 11 ++++------- skimage/measure/tests/test_regionprops.py | 24 +++++++++++++++++++++++ 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/skimage/measure/_regionprops.py b/skimage/measure/_regionprops.py index d28b05d34dc..e9d7e2d900e 100644 --- a/skimage/measure/_regionprops.py +++ b/skimage/measure/_regionprops.py @@ -854,15 +854,10 @@ def _props_to_dict(regions, properties=('label', 'bbox'), separator='-'): column_buffer[i] = regions[i][prop] out[orig_prop] = np.copy(column_buffer) else: - if isinstance(rp, np.ndarray): - shape = rp.shape - else: - shape = (len(rp),) - # precompute property column names and locations modified_props = [] locs = [] - for ind in np.ndindex(shape): + for ind in np.ndindex(np.shape(rp)): modified_props.append( separator.join(map(str, (orig_prop,) + ind)) ) @@ -872,7 +867,9 @@ def _props_to_dict(regions, properties=('label', 'bbox'), separator='-'): n_columns = len(locs) column_data = np.empty((n, n_columns), dtype=dtype) for k in range(n): - rp = regions[k][prop] + # we coerce to a numpy array to ensure structures like + # tuple-of-arrays expand correctly into columns + rp = np.asarray(regions[k][prop]) for i, loc in enumerate(locs): column_data[k, i] = rp[loc] diff --git a/skimage/measure/tests/test_regionprops.py b/skimage/measure/tests/test_regionprops.py index 3f0224f6d34..5c3f9916b2e 100644 --- a/skimage/measure/tests/test_regionprops.py +++ b/skimage/measure/tests/test_regionprops.py @@ -33,6 +33,9 @@ INTENSITY_SAMPLE = SAMPLE.copy() INTENSITY_SAMPLE[1, 9:11] = 2 INTENSITY_FLOAT_SAMPLE = INTENSITY_SAMPLE.copy().astype(np.float64) / 10.0 +INTENSITY_FLOAT_SAMPLE_MULTICHANNEL = ( + INTENSITY_FLOAT_SAMPLE[..., np.newaxis] * [1, 2, 3] + ) SAMPLE_MULTIPLE = np.eye(10, dtype=np.int32) SAMPLE_MULTIPLE[3:5, 7:8] = 2 @@ -714,6 +717,27 @@ def test_solidity(): assert_almost_equal(solidity, target_solidity) +def test_multichannel_centroid_weighted_table(): + """Test for https://github.com/scikit-image/scikit-image/issues/6860.""" + intensity_image = INTENSITY_FLOAT_SAMPLE_MULTICHANNEL + rp0 = regionprops(SAMPLE, intensity_image=intensity_image[..., 0])[0] + rp1 = regionprops(SAMPLE, intensity_image=intensity_image[..., 0:1])[0] + rpm = regionprops(SAMPLE, intensity_image=intensity_image)[0] + np.testing.assert_almost_equal(rp0.centroid_weighted, + np.squeeze(rp1.centroid_weighted)) + np.testing.assert_almost_equal(rp0.centroid_weighted, + np.array(rpm.centroid_weighted)[:, 0]) + assert np.shape(rp0.centroid_weighted) == (SAMPLE.ndim,) + assert np.shape(rp1.centroid_weighted) == (SAMPLE.ndim, 1) + assert np.shape(rpm.centroid_weighted) == (SAMPLE.ndim, + intensity_image.shape[-1]) + + table = regionprops_table(SAMPLE, intensity_image=intensity_image, + properties=('centroid_weighted',)) + # check the number of returned columns is correct + assert len(table) == np.size(rpm.centroid_weighted) + + def test_moments_weighted_central(): wmu = regionprops(SAMPLE, intensity_image=INTENSITY_SAMPLE )[0].moments_weighted_central