I'm currently working on image superpixel SLIC segmentation with the package skimage.segmentation
.
My original image is 3042*4032
(12Mpx). In skimage
, the array's shape is (3042,4023,3)
. After the segmentation, I have around 3000 superpixels represented in a 3042*4032
array.
My goal is to find for each superpixel, the proportion of pixel which have their maximum value on the Red channel, the Blue channel and the Green channel.
I already have a function which give me the index of the maximum in the entire image :
def proportion_majoritaire_rgb_image(img):
""" In a pixel, which channel [R,G,B] has the maximum value ?
:param img: image (N,m) skimage rgb
:return: (N,m) array with indexes [0,1,2]
"""
return np.argmax(img, axis=2)
And by filtering the image on a single label, i can get the proportion of max RGB in a single label :
def proportion_majoritaire_rgb_label(img, matrice_label):
"""
:param img: image (N,m) skimage rgb
:param matrice_label: ndarray (N,m) labels SLIC
:return: (K, 3) array of K labels and 3 proportions
"""
indice_max_rgb = proportion_majoritaire_rgb_image(img)
n_pixel_max_rgb = []
for k in np.unique(image_grains_ble_slic).flat:
label_data = indice_max_rgb[matrice_label == k]
n_pixel_max_rgb.append(np.unique(label_data, return_counts=True)[1] / np.shape(label_data)[0])
return n_pixel_max_rgb
The issue is how to get this information for all my 3000 labels without this for loop ? It takes too much time to compute, is there any other way ?
The final output should be a ndarray (K,3) with K labels and for each channel RGB the proportion of pixels which have the maximum value.
Thanks in advance !
EDIT : Using np.unique(image_grains_ble_slic).flat
as an iterator for the loop seems to be faster, but my goal of avoiding the for loop still stands
It's a little hacky because of a long-standing feature request for skimage.measure.regionprops
to allow measuring multichannel images. But, we can hack it together with some repeated calls to regionprops_table
, which gives us vectorised output:
from skimage import measure
index_max_rgb = np.argmax(image, axis=2)
max_index_images = [
(index_max_rgb == i).astype(float) for i in range(3)
]
proportions_per_channel = [
measure.regionprops_table(
image_grains_ble_slic,
intensity_image=intensity,
properties=('mean_intensity',),
)['mean_intensity']
for intensity in max_index_images
]
proportions = np.stack(proportions, axis=1)
By the way, be sure that you use start_label=1
with SLIC because regionprops ignores the 0 label as belonging to the background.