How to get the area(Pixels count) inside ring-like shape? I have the following image, and I do like to count the pixels inside the ring to get the area.





I did some morphological operations as a kind of post-processing to make the image as much as possible with clear smooth edges.
I tried to do that in different ways as you can see in the code down, but none of them was optimal.
Can you please advice me how to count the pixels inner area of the circle?
Note: some pixels inside are not totally black, they are with low intensity, that's why I was trying to do Otsu thresholding.
Thanks in advance


import numpy as np
import matplotlib.pyplot as plt
from skimage.io import imread, imsave
# import scipy.ndimage as ndi 
from skimage import morphology, filters, feature

seg = np.squeeze(imread('prediction.png')[...,:1])
# meijering alpha=None,
# rem2 = morphology.remove_small_objects(seg, 4)
resf = filters.meijering(seg, sigmas=range(1, 3, 1),  black_ridges=False)

sobel = filters.sobel(resf)
# diam = morphology.diameter_closing(sobel, 64, connectivity=2)
gaussian = filters.gaussian(sobel, sigma= 1)
val = filters.threshold_otsu(gaussian)
resth = gaussian &lt; val 

# Morphology
SE = morphology.diamond(2)
# SE = np.ones((3,3))
# SE = morphology.disk(2)
# SE = square(7)
# SE = rectangle(3,3)
# SE = octagon(3, 3)

erosion  = morphology.binary_erosion( resth, SE).astype(np.uint8)
dilation = morphology.binary_dilation(resth, SE).astype(np.uint8)
opening  = morphology.binary_opening( resth, SE).astype(np.uint8)
closing  = morphology.binary_closing( resth, SE).astype(np.uint8)
#thinner = morphology.thin(erosion, max_iter=4)

rem  = morphology.remove_small_holes(resth, 2)

# entropy  = filters.rank.entropy(resth, SE) 
# print(seg.shape)

plt.figure(num='PProc')
# 1
plt.subplot('335')
plt.imshow(rem,cmap='gray')
plt.title('rem')
plt.axis('off')
# 2
plt.subplot('336')
plt.imshow(dilation,cmap='gray')
plt.title('dilation')
plt.axis('off')
# 3
plt.subplot('337')
plt.imshow(opening,cmap='gray')
plt.title('opening')
plt.axis('off')
# 4
plt.subplot('338')
plt.imshow(closing,cmap='gray')
plt.title('closing')
plt.axis('off')
# 5
plt.subplot('332')
plt.imshow(seg,cmap='gray')
plt.title('segmented')
plt.axis('off')
# 6
plt.subplot('333')
plt.imshow(resf,cmap='gray')
plt.title('meijering')
plt.axis('off')
# 7
# 8
plt.subplot('334')
plt.imshow(resth,cmap='gray')
plt.title('threshold_otsu')
plt.axis('off')
# 9
plt.subplot('339')
plt.imshow(erosion,cmap='gray')
plt.title('erosion')
plt.axis('off')
#
plt.show()
The answer is down from the question on StackOverflow website, thanks for Paul Brodersen the credit of the answer is for him.

#!/usr/bin/env python
"""
Determine areas in image of ring.

SO: https://stackoverflow.com/q/61681565/2912349
"""
import numpy as np
import matplotlib.pyplot as plt

from skimage.io import imread
from skimage.filters import threshold_otsu
from skimage.measure import label, regionprops
from skimage.color import label2rgb

if __name__ == '__main__':

    raw = imread('prediction.png', as_gray=True)
    threshold = threshold_otsu(raw)
    thresholded = raw &gt; threshold
    # Label by default assumes that zeros correspond to "background".
    # However, we actually want the background pixels in the center of the ring,
    # so we have to "disable" that feature.
    labeled = label(thresholded, background=2)
    overlay = label2rgb(labeled)

    fig, axes = plt.subplots(1, 3)
    axes[0].imshow(raw, cmap='gray')
    axes[1].imshow(thresholded, cmap='gray')
    axes[2].imshow(overlay)

    convex_areas = []
    areas = []
    for properties in regionprops(labeled):
        areas.append(properties.area)
        convex_areas.append(properties.convex_area)

    # take the area with the smallest convex_area
    idx = np.argmin(convex_areas)
    area_of_interest = areas[idx]
    print(f"My area of interest has {area_of_interest} pixels.")
    # My area of interest has 714 pixels.
    plt.show()
```