-1

I have an image in which I am interested in a specific region in the image.. for example I want to extract region 5-same pixel value everywhere (and background 0). Meaning region 3 and 4 should not be present in the output image(should be 0). Here is the image looks like.

enter image description here

I can do it with a for loop but since the image is large it takes time.. because I have a 3D stack. Any simpler approach would be appreciated.

Christoph Rackwitz
  • 11,317
  • 4
  • 27
  • 36
Mass17
  • 1,555
  • 2
  • 14
  • 29
  • What do you want in place of 3 and 4? 0 color, transparency? What is the size of the final image? – Colim Jul 08 '22 at 11:09
  • same as the original image.. 3 & 4 should be 0. – Mass17 Jul 08 '22 at 11:17
  • first find the pixel intensity of region 5 (lets say region 5 is between 122 and 132 pixel intensity). Then mask out the remain pixels that are outside that pixel intensity by setting them to 0. – Olasimbo Jul 08 '22 at 11:18
  • 1
    What kind of image is it and how do you define the regions? Do you have (1) a mask for the region, so you know where it is, or (2) different values in the image color channel, defining the region? A very small example would be helpful. – André Jul 08 '22 at 11:19
  • I set region 5 to unique pixel value.. – Mass17 Jul 08 '22 at 11:20
  • so it is like mask with different regions. – Mass17 Jul 08 '22 at 11:21
  • 1
    Do you want to set the values of the other regions to the background value? – André Jul 08 '22 at 11:24
  • similarly region 3/4 are unique values. – Mass17 Jul 08 '22 at 11:26
  • no I am looking for region 5 & 0 (3 & 4 should be replaced by 0, which is background) – Mass17 Jul 08 '22 at 11:29
  • 1
    this question amounts to "how do I threshold". you have enough karma to know [ask] and [mre] and why those rules exist. – Christoph Rackwitz Jul 08 '22 at 12:58

3 Answers3

3

First let's generate some image we can work on.

import numpy as np
import matplotlib.pyplot as plt 

img = np.zeros((250,250), dtype=int)
img += np.arange(-124, 126, 1)**2
img = img.T + np.arange(-124, 126, 1)**2
img += np.arange(1, 251, 1)**2

img = (img/(np.max(img)/4.5)).astype(int)

plt.imshow(img)

Example image

Now we can mask it using np.where:

bg_value = 0 # Background value
want_value = 2 # Value that we are interested in

masked = np.where(img == want_value, img, bg_value)

plt.imshow(masked)

Masked image

André
  • 1,034
  • 9
  • 19
2

If you have images and corresponding masks, you can use np.where as follows:

import numpy as np

N, C, H, W = 11, 3, 32, 64
num_labels = 5

images = np.random.randint(0, 256, size=(N, H, W, C))
masks = np.random.randint(1, num_labels + 1, size=(N, H, W))

masks_5 = np.where(masks == 5, 5, 0)

images_region_5 = np.where(masks_5[..., None], images, 0)

To visualize the process:

import matplotlib.pyplot as plt

image = images[0]
image_5 = images_region_5[0]
mask = masks[0]
mask_5 = masks_5[0]

fig, ((ax_im, ax_masked), (ax_mask, ax_mask_5)) = plt.subplots(nrows=2, ncols=2)

ax_im.imshow(image)
ax_masked.imshow(image_5)
ax_mask.imshow(mask.astype(int))
ax_mask_5.imshow(mask_5.astype(int), cmap="gray")

ax_im.set_title("Original")
ax_masked.set_title("Masked [5]")
ax_mask.set_title("Mask")
ax_mask_5.set_title("Mask [5]")

plt.show()

Plot process

paime
  • 2,901
  • 1
  • 6
  • 17
2

The answer is as simple as:

mask = im == 5

which gives you a Boolean mask which is True wherever the image has a pixel with the value 5. You can then multiply that by 255 if you want it white wherever the image is 5, or by 5 if you want it to have the value 5 wherever the original is 5.

Note also that this solution requires ONE byte per pixel because it gives you a Boolean mask, whereas using unadorned np.where() will take EIGHT bytes per pixel because it gives you an array of np.uint64.

Note also that this is 16 times faster than np.where() on my machine:

%timeit mask = im == 192
937 ns ± 1.8 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

versus:

%timeit a = np.where(im==192, 192, 0)
15.1 µs ± 8.27 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Let's make an example, not with 1 ,2, 3, 4, 5 because they are too dark to see, so let's make squares with brightness 64, 128 and 192:

import numpy as np

# Make black image
im = np.zeros((100,300), np.uint8)

im[20:80, 20:80]   =  64  # dark grey square on left
im[20:80, 120:180] = 128  # mid-grey square in centre
im[20:80, 220:280] = 192  # light grey square on right

enter image description here

And then, the code you need to select the right-hand square which has value 192 is this:

mask = im == 192

enter image description here

Mark Setchell
  • 191,897
  • 31
  • 273
  • 432