0

What I'm trying to do is essentially removing all rows h,s in a 3D numpy array a if a[h,s,v] = some value for all v

More specifically, I have a loaded image from cv2 which contains some transparent pixels. I'd like to create an HSV histogram without including the transparent pixels (i.e. k=255)

Here's what I have now:

import cv2
import numpy as np

IMAGE_FILE = './images/2024-11-17/00.png'  # load image with some transparent pixels

# Read image into HSV
image = cv2.imread(IMAGE_FILE)
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)

# Remove all pixels with V = 255
hsv_removed_transparency = []
i = np.where(hsv[:, :, 2] == 255)  # indices of pixels with V = 255
for i1 in range(len(i[0])):
    hsv_removed_transparency.append(np.delete(hsv[i[0][i1]], i[1][i1], axis=0)
2
  • 1
    You can't. In a 2D array, you can remove a whole row or a whole column. But you can't remove a single element. That would not be a 2D array anymore. Likewise, in a 3D array, you can remove a whole plane (plane h=?, or plane s=?, or plane v=?), but you can't remove a single row (if you are convinced of what I said about 2D array, then, it is easy to be convinced about 3D array: a 3D array, after all, is nothing more than a 2D array of "rows") Commented Jan 19 at 7:16
  • 1
    Now, you've layed out your XY-problem yourself. Your real question isn't "remove a row from a 3D array", your real question is "create a hsv histogram without including transparent pixels". That is probably possible. But you need to clarify what form that histogram would take, and how you intend to build it. But roughly: just don't count pixels with v=255. For example by counting only pixels of np.where(hsv[:,:,2]!=255) Commented Jan 19 at 7:24

1 Answer 1

1

If you want to compute a histogram with a mask, just do that. No need to alter the image. cv2.calcHist takes a mask parameter:

import cv2

image = cv2.imread('squirrel_cls.jpg') # https://raw.githubusercontent.com/opencv/opencv/refs/heads/4.x/samples/data/squirrel_cls.jpg
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
# add some more values with V = 255
hsv[100:350, 150:350, 2] = 255

# compute the histogram for the Hue
h_hist_all = cv2.calcHist([hsv], [0], None, [256], [0, 256])
# compute the histogram for the Saturation
s_hist_all = cv2.calcHist([hsv], [1], None, [256], [0, 256])

mask = (hsv[..., 2] != 255).astype(np.uint8)
# compute the histogram for the Hue with mask
h_hist = cv2.calcHist([hsv], [0], mask, [256], [0, 256])
# compute the histogram for the Saturation with mask
s_hist = cv2.calcHist([hsv], [1], mask, [256], [0, 256])


import matplotlib.pyplot as plt

plt.plot(h_hist_all, label='H (all)')
plt.plot(h_hist, label='H (mask)')
plt.plot(s_hist_all, label='S (all)')
plt.plot(s_hist, label='S (mask)')
plt.legend()

Output:

opencv histogram with mask

For a 2D histogram (H vs S):

f, (ax1, ax2) = plt.subplots(ncols=2, sharey=True)

ax1.imshow(np.log(cv2.calcHist([hsv], [0, 1], None, [256, 256], [0, 256, 0, 256])),
           cmap='Greys')
ax2.imshow(np.log(cv2.calcHist([hsv], [0, 1], mask, [256, 256], [0, 256, 0, 256])),
           cmap='Greys')
ax1.set_title('all')
ax2.set_title('mask')
ax1.set_xlabel('H')
ax1.set_ylabel('S')

Output:

opencv 2D histogram with mask

Likewise, if you want to use np.histogram, just filter out the values from the channel:

h_hist_mask, bins = np.histogram(hsv[..., 0][hsv[..., 2] != 255])

Used images:

input images opencv

Sign up to request clarification or add additional context in comments.

5 Comments

what's the point of the s_hist* results?
@ChristophRackwitz Just if you want the histogram on the S channel of HSV (I didn't plot it here)
I'm just saying, strip it, because both *_hist_all assignments have the same RHS expression, i.e. should be equal.
@ChristophRackwitz you're right I had missed the typo. That's fixed now and I added comments + new curves to be explicit. Thanks for your feedback :)
great example of calcHist usage. I never could figure out what they were thinking when they came up with that function signature, nor do I remember the docs having been entirely "clear".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.