3

I have segmented my image using the quickshift method found in the scikit image libary. How can I calculate the average color and the area of a superpixel? How can I interpret the return value of the quickshift() method? The documentation says the return value is "Integer mask indicating segment labels" but this is not clear for me. How can I make a boolean array in the shape of the original image, filled with ones, where the particular superpixel is present, in this presentation my life would be easier(I used to work with this kind of masks in OpenCV). Can you help me with this? My code (simplified example from scikit-image website):

from skimage.data import astronaut
from skimage.segmentation import felzenszwalb, slic, quickshift
from skimage.segmentation import mark_boundaries
from skimage.util import img_as_float

img = img_as_float(astronaut()[::2, ::2])
segments_quick = quickshift(img, kernel_size=3, max_dist=6, ratio=0.5)

print("Quickshift number of segments: %d" % len(np.unique(segments_quick)))
plt.imshow(mark_boundaries(img, segments_quick))

plt.show()
user3598726
  • 951
  • 2
  • 11
  • 27

3 Answers3

8

The skimage.measure.regionprops function returns the properties of labeled regions, including the ones you are interested in: average and area. You use it as follows:

from skimage import measure
regions = measure.regionprops(segments_quick, intensity_image=img)

regions is a list, with each entry a RegionProperty object representing a superpixel. You can query the region properties as follows:

print([r.area for r in regions])
print([r.mean_intensity for r in regions])
Stefan van der Walt
  • 7,165
  • 1
  • 32
  • 41
  • How can I get mean intensity values for a rgb image for each channel? – Raj Apr 22 '21 at 13:48
  • If you run the above code, it will give you exactly that. – Stefan van der Walt Apr 23 '21 at 17:57
  • It gives combined mean intensity. But I need it separately for each channel. – Raj Apr 23 '21 at 20:07
  • ``` import numpy as np from skimage import measure, data cat = data.chelsea() labels = np.zeros_like(cat[..., 0], dtype=int) labels[:100] = 1 labels[100:] = 2 regions = measure.regionprops(labels, intensity_image=cat) print(regions[0].mean_intensity) ``` ``` [142.23179601 106.63430155 83.25536585] ``` – Stefan van der Walt Apr 25 '21 at 20:07
5

Here is a simple, straight forward and generic code to represnt each pixel with the mean of its superpixel.

Here the label array is obtained using SLIC, any other approach can be used to generate the labels.

import numpy as np
import cv2
from skimage import segmentation
from skimage.data import astronaut

img=cv2.cvtColor(astronaut(),cv2.COLOR_BGR2RGB)

enter image description here

label=segmentation.slic(img,compactness=10, n_segments=1000)

def mean_image(image,label):

im_rp=image.reshape((image.shape[0]*image.shape[1],image.shape[2]))
sli_1d=np.reshape(label,-1)    
uni=np.unique(sli_1d)
uu=np.zeros(im_rp.shape)
for i in uni:
    loc=np.where(sli_1d==i)[0]
    #print(loc)
    mm=np.mean(im_rp[loc,:],axis=0)
    uu[loc,:]=mm
oo=np.reshape(uu,[image.shape[0],image.shape[1],image.shape[2]]).astype('uint8')
cv2.imshow('img',oo)

output=mean_image(img,label) # displays the output image.

enter image description here

Cris Luengo
  • 55,762
  • 10
  • 62
  • 120
Khan
  • 1,288
  • 12
  • 11
0

The easiest way for me was this:

from skimage import segmentation, color
from skimage.io import imread
from skimage.future import graph
from matplotlib import pyplot as plt
img = imread('test.jpeg')

img_segments = segmentation.slic(img, compactness=20, n_segments=500)
superpixels = color.label2rgb(img_segments, img, kind='avg')