[OpenCV’s color image segmentation technology based on HSV space reports an error: ValueError: the input array must be have a shape =]= (.., ..,[ ..,]

Article directory

    • summary
    • Image segmentation concept
    • Segment blue target
    • Split yellow target
    • Split orange target
    • Split green target
    • summary

Summary

Whenever you see an image, it is usually made up of various elements and objects. In some cases, you may want to extract a specific object from an image. What do you do? The first thing that comes to mind is to perform crop related operations, which is feasible to a certain extent, but this will usually also include some irrelevant pixels, which I am sure is not desired in most cases. In fact, image processing techniques can be used to obtain objects of interest.

Image segmentation concept

Image segmentation refers to the process of dividing an image into its component parts or sub-objects. Common techniques include edge detection, threshold processing, region-based segmentation, etc.

HSV color space

The goal is to segment each bag by HSV color space. But how to do it? Generally speaking, HSV stands for hue, saturation, and brightness, and the information from the HSV color space will be used later when segmenting the image.

First convert the RGB image to HSV using the following code:

from skimage.io import imread, imshow
from skimage.color import rgb2hsv
import matplotlib.pyplot as plt
from PIL import Image

bags = Image.open('img_3.png')

bags_hsv = rgb2hsv(img)
fig, ax = plt.subplots(1, 3, figsize=(12,4))
ax[0].imshow(bags_hsv[:,:,0], cmap='gray')
ax[0].set_title('Hue')
ax[1].imshow(bags_hsv[:,:,1], cmap='gray')
ax[1].set_title('Saturation')
ax[2].imshow(bags_hsv[:,:,2], cmap='gray')
ax[2].set_title('Value')
plt.show()

D:\anaconda\envs\yolov5\python.exe E:\yolo project\Opencv-project-main\Opencv-project-main\CVZone\guangliu\two.py
Traceback (most recent call last):
  File "E:\yolo project\Opencv-project-main\Opencv-project-main\CVZone\guangliu\two.py", line 7, in <module>
    bags_hsv = rgb2hsv(bags)
  File "D:\anaconda\envs\yolov5\lib\site-packages\skimage\color\colorconv.py", line 248, in rgb2hsv
    arr = _prepare_colorarray(rgb)
  File "D:\anaconda\envs\yolov5\lib\site-packages\skimage\color\colorconv.py", line 145, in _prepare_colorarray
    raise ValueError(msg)
ValueError: the input array must be have a shape == (.., ..,[ ..,] 3)), got (683, 932, 4)

Process finished with exit code 1

This error is due to the fact that the input expected by the rgb2hsv function is an RGB image, and its shape should be (height, width, 3), representing three color channels. However, the image appears to have four channels, possibly in RGBA format (RGB + Alpha, indicating transparency).
The solution from the previous article still works:

# Convert image to RGB mode
img = bags.convert('RGB')
from skimage.io import imread, imshow
from skimage.color import rgb2hsv
import matplotlib.pyplot as plt
from PIL import Image

bags = Image.open('img_3.png')
#Convert image to RGB mode
img = bags.convert('RGB')

bags_hsv = rgb2hsv(img)
fig, ax = plt.subplots(1, 3, figsize=(12,4))
ax[0].imshow(bags_hsv[:,:,0], cmap='gray')
ax[0].set_title('Hue')
ax[1].imshow(bags_hsv[:,:,1], cmap='gray')
ax[1].set_title('Saturation')
ax[2].imshow(bags_hsv[:,:,2], cmap='gray')
ax[2].set_title('Value')
plt.show()

Result:
However, the above grayscale image does not help us much yet. We need to get the intensity value of each HSV channel to help guide our segmentation later. To do this, a colored bar is created by implementing the following code:

from skimage.io import imread, imshow
from skimage.color import rgb2hsv
import matplotlib.pyplot as plt
from PIL import Image

bags = Image.open('img_3.png')
#Convert image to RGB mode
img = bags.convert('RGB')

bags_hsv = rgb2hsv(img)

fig, ax = plt.subplots(1, 3, figsize=(15, 5))
ax[0].imshow(bags_hsv[:,:,0],cmap='hsv')
ax[0].set_title('hue')
ax[1].imshow(bags_hsv[:,:,1],cmap='hsv')
ax[1].set_title('transparency')
ax[2].imshow(bags_hsv[:,:,2],cmap='hsv')
ax[2].set_title('value')
fig.colorbar(imshow(bags_hsv[:,:,0],cmap='hsv'))
fig.tight_layout()
plt.show()

Wow! See the colored bar on the right? We will refer to this when splitting the bag. Lower mask (reference hue channel)

Upper mask (reference hue channel)

Saturation mask (referring to the transparency channel)

When selecting a threshold, pay attention to the colored bars. For example, if we are segmenting the blue bag. Suitable lower and upper mask values would be 0.6 and 0.7 respectively.

Segment blue target

Based on the above analysis, we use the following code to segment the blue bag. The code is as follows:

Insert code snippet here

Error reported:

D:\anaconda\envs\yolov5\python.exe E:\yolo project\Opencv-project-main\Opencv-project-main\CVZone\guangliu\two.py
Traceback (most recent call last):
  File "E:\yolo project\Opencv-project-main\Opencv-project-main\CVZone\guangliu\two.py", line 20, in <module>
    red = bags[:, :, 0] * mask
TypeError: 'PngImageFile' object is not subscriptable

Process finished with exit code 1

You can convert a PIL Image to a Numpy array using the numpy.asarray() method.

from skimage.io import imread, imshow
from skimage.color import rgb2hsv
import matplotlib.pyplot as plt
from PIL import Image
import numpy as np

#Open image file
bags = Image.open('img_3.png')
#Convert image to RGB mode
img = bags.convert('RGB')

# Convert PIL Image to Numpy array
bags_array = np.asarray(img)

# Convert the image to HSV color space
bags_hsv = rgb2hsv(bags_array)

# refer to hue channel (in the colorbar)
lower_mask = bags_hsv[:, :, 0] > 0.6
# refer to hue channel (in the colorbar)
upper_mask = bags_hsv[:, :, 0] < 0.7
# refer to saturation channel (in the colorbar)
saturation_mask = bags_hsv[:, :, 1] > 0.3

mask = upper_mask * lower_mask * saturation_mask

red = bags_array[:, :, 0] * mask
green = bags_array[:, :, 1] * mask
blue = bags_array[:, :, 2] * mask

bags_masked = np.dstack((red, green, blue))
imshow(bags_masked)
plt.show()

Segmentation results:

Segment the yellow target

Modify the corresponding mask

# refer to hue channel (in the colorbar)
lower_mask = bags_hsv[:, :, 0] > 0.1
# refer to hue channel (in the colorbar)
upper_mask = bags_hsv[:, :, 0] < 0.2
# refer to saturation channel (in the colorbar)
saturation_mask = bags_hsv[:, :, 1] > 0.6

Split orange target

#refer to hue channel (in the colorbar)
lower_mask = bags_hsv[:,:,0] > 0.0
#refer to hue channel (in the colorbar)
upper_mask = bags_hsv[:,:,0] < 0.09
#refer to transparency channel (in the colorbar)
saturation_mask = bags_hsv[:,:,1] > 0.4

Segment green target

#refer to hue channel (in the colorbar)
lower_mask = bags_hsv[:,:,0] > 0.3
#refer to hue channel (in the colorbar)
upper_mask = bags_hsv[:,:,0] < 0.5
#refer to transparency channel (in the colorbar)
saturation_mask = bags_hsv[:,:,1] > 0.6

Summary

The use of HSV color space in the field of image segmentation is explained through a specific example. It mainly analyzes different thresholds on the corresponding channels of HSV to set different masks, and then segment different objects.
Change the color by judging the numerical value of the corresponding color threshold.