Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Numpy image slicing returning black patches/ wrong values

The end goal is to take an image and slice it up into samples that I save. The problem is that my slices are randomly returning black/ incorrect patches. Bellow is a small sample program.

import scipy.ndimage as ndimage
import scipy.misc as misc
import numpy as np

image32 = misc.imread("work0.png")
patches = np.zeros((36, 8, 8))
for i in range(4):
  for j in range(4):
    patches[i*4 + j] = image32[i:i+8,j:j+8]
    misc.imsave("{0}{1}.png".format(i,j), patches[i*4 + j])

An example of my image would be:

Letter that I'm getting patches of

Patch of 0,0 of 8x8 patch yields:

enter image description here

like image 584
Dr.Knowitall Avatar asked Dec 19 '22 01:12

Dr.Knowitall


1 Answers

Two things:

  1. You are initializing your patch matrix to be the wrong data type. By default, numpy will make patches matrix a np.float64 type and if you use this with saving, you won't get the results you would expect. Specifically, if you consult Mr. F's answer, there is actually some scaling performed on floating-point images where the minimum and maximum values of the image get scaled to black and white respectively and so if you have an image that is completely uniform in background, both the minimum and maximum will be the same and will get visualized to black. As such, the best thing is to respect the original image's data type, namely setting the dtype of your patches matrix to np.uint8.

  2. Judging from your for loop indexing, you want to extract out 8 x 8 patches that are non-overlapping. This means that if you have a 32 x 32 image with 8 x 8 patches, you have 16 patches in total arranged in a 4 x 4 grid.

Therefore, you need to change the patches statement so that it has 16 in the first dimension, not 36. In addition, you'll have to adjust the way you're indexing into your image to extract out the 8 x 8 patches because right now, the patches are overlapping. Specifically, you want to make the image patch indexing go from 8*i to 8*(i+1) for the rows and 8*j to 8*(j+1) for the columns. If you substitute sample values of i and j yourself, you'll see that we get unique 8 x 8 patches for each grid in your image.


With both of the above things I noted, the modified code should be:

import scipy.ndimage as ndimage
import scipy.misc as misc
import numpy as np

image32 = misc.imread('work0.png')

patches = np.zeros((16,8,8), dtype=np.uint8) # Change

for i in range(4):
    for j in range(4):
        patches[i*4 + j] = image32[8*i:8*(i+1),8*j:8*(j+1)] # Change
        misc.imsave("{0}{1}.png".format(i,j), patches[i*4 + j])

When I do this and take a look at the output images, I get what I expect.


To be absolutely sure, let's plot the segments using matplotlib. You've conveniently saved all of the patches in patches so it shouldn't be a problem showing what we need. However, I'll place some code in comments so that you can read in the images that were saved from disk with your above code so you can verify that it still works, regardless of looking at patches or the images on disk:

import matplotlib.pyplot as plt

plt.figure()
for i in range(4):
    for j in range(4):
        plt.subplot(4, 4, 4*i + j + 1)
        img = patches[4*i + j]
        # or you can do this:
        # img = misc.imread('{0}{1}.png'.format(i,j))
        img = np.dstack([img, img, img])
        plt.imshow(img)

plt.show()

The weird thing about matplotlib.pyplot.imshow is that if you have an image that is single channel (such as your case) that has the same intensity all around, it gets visualized to black no matter what the colour map is, much like what we experienced with imsave. Therefore, I had to artificially make this a RGB image but with all of the channels to be the same so this gets visualized as grayscale before we show the image.

We get:

enter image description here

like image 157
rayryeng Avatar answered Dec 26 '22 10:12

rayryeng