I would like to extract some shapes and create mask based on shape colours from this image
(the mask should be created for the red shapes) and below the expected figure then I want to determine the area of these shapes.
import cv2
import numpy as np
from matplotlib import pyplot as plt
from colorthief import ColorThief
ct=ColorThief('image_red.png')
domainant_color = ct.get_color(quality=1)
palette = ct.get_palette(color_count=number_colors)
print(palette)
plt.imshow([[palette[i] for i in range(number_colors)]])
plt.show()
#LOAD IMAGE
image_org=cv2.imread("image_red.png",0)
print(image_org.shape)
#FILTER /REMOVE NOISES
img_filter=cv2.medianBlur(image_org, 3)
#### THRESHOLDING..
thresh_value,thresh_img=cv2.threshold(img_filter,0,225,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
low=np.array([251, 4, 4], dtype = "uint8") #this is based on values from palette
upper=np.array([251, 4, 4], dtype = "uint8")#this is based on values from palette
img_f = cv2.cvtColor(thresh_img, cv2.COLOR_BGR2RGB)
mask1=cv2.inRange(img_f,lo,up)
io.imshow(mask1)
plt.show()
I started via the following steps:
The result seems to give me the other phases, not the red color shapes. What can I do to get only the red shapes as I attached expected image file?
Unless your question is misleading, you are simply looking for coloured pixels. These are most readily found by converting to HSV colourspace and looking for pixels with high saturation, since black, white and grey pixels will all have zero saturation.
The code will look like this:
#!/usr/bin/env python3
import numpy as np
import cv2 as cv
# Load image and convert to HSV colourspace
im = cv.imread('YOURIMAGE.jpg')
HSV = cv.cvtColor(im,cv.COLOR_BGR2HSV)
# Select the Saturation channel
S = HSV[:,:,1]
# Save Saturation channel for debug purposes
cv.imwrite('DEBUG-sat.png', S)
# Decide some threshold
# Save thresholded Saturation channel for debug purposes
thr = S>50
cv.imwrite('DEBUG_thr.png', thr*255)
# Count the saturated pixels and total image area
Nsat = np.count_nonzero(thr)
area = im.shape[0]*im.shape[1]
# Output results
print(f'{Nsat=}, {area=}')
That prints:
Nsat=6774, area=436230
And the intermediate, debug image looks like this:
If you want to detect the black pixels, you will want those with low Saturation (i.e. not colourful) and low value (i.e. not bright):
# Mask of black pixels: Any Hue, Low Saturation, Low value
lo = np.array([0, 0, 0], np.uint8)
hi = np.array([255, 50, 30], np.uint8)
blackMask = cv.inRange(HSV, lo, hi)
cv.imwrite('DEBUG-black.png', blackMask)
If you want to detect the light grey pixels, you will want those with low Saturation (i.e. not colourful) and medium value (i.e. neither bright white nor dark black):
# Mask of light grey pixels: Any Hue, Low Saturation, Medium High value
lo = np.array([0, 0, 120], np.uint8)
hi = np.array([255, 50, 200], np.uint8)
greyMask = cv.inRange(HSV, lo, hi)
cv.imwrite('DEBUG-grey.png', greyMask)