Unexpected Image Display Behavior in Ipython Notebook After Manipulating with Numpy

192 views Asked by At

I was trying to answer @LMNYC question here image palette's dimension reduction using matplotlib and/or numpy to create blocky image and ran into the following issue:

I am trying to reduce the image quality of a png file in ipython notebook. I know that there are other, easier ways to do this (e.g. sklearn image processing, creating blocks using numpy.as_strides function) but I wanted to get a better initial understanding by trying things out myself, so I tried to write an intial script to take an image (of 512 X 512 resolution, e.g) and form a new image of the same resolution, but is instead composed of rectangular "blocks" of arbitrary dimension, where the average color inside of each block composes the new image. The unexpected behavior is that when I take the mean within each block, the original image, which is predominantly orange/red, comes out almost entirely green. However, if instead of taking the mean within each block, I subtract the mean within the block from 255, I get the desired behavior.

My question is why can I not just take the mean? I have two possibly theories. 1) The type of the image array is uint8. 2**8 =256. Is there some overflow in the calculation, so that the mean result is actually mod 256, and so when I subtract I am getting the correct number. 2) Is the calculation correct, but somehow there is another option/setting for the display that I need to tell it what "direction" the colors are measured in. The reason this seems odd is that if I display the numpy representation of the original array, everything works fine.

Thanks in advance, and apologies for not displaying images inline, I need more reputation first!

import matplotlib
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.pyplot import imshow
from IPython.display import Image
from PIL import Image
import copy
%matplotlib inline

filename = 'my.png'
im = Image.open(filename,mode='r')
im_array = np.array(im)

imshow(im)

enter image description here

imshow(im_array)

enter image description here

vert_num_bins, horz_num_bins = 10, 8
im_shape_vert, im_shape_horz = im_array.shape[0], im_array.shape[1]

vert_dist_array = np.array(range(vert_num_bins))
horz_dist_array = np.array(range(horz_num_bins))

seq_mat = np.array(range(vert_num_bins*horz_num_bins)).reshape(vert_num_bins,horz_num_bins)
num_spreads_vert, num_spreads_hor = (im_shape_vert//vert_num_bins+1), (im_shape_horz//horz_num_bins+1)

spread_array_big = np.kron(seq_mat,np.ones((num_spreads_vert,num_spreads_hor),dtype=int))
spread_array = spread_array_big[:im_shape_vert,:im_shape_horz]
new_array = np.empty(shape=im_array.shape,dtype=int)
new_array_wrong = np.empty(shape=im_array.shape,dtype=int)


for slices in range(3):
    temp_array = im_array[:,:,slices]
    transformed_array = np.empty(shape=temp_array.shape,dtype=int)
    transformed_array_wrong = np.empty(shape=temp_array.shape,dtype=int)

    for ind in range(vert_num_bins*horz_num_bins):

        transformed_array_wrong[spread_array==ind] = int(np.mean(temp_array[spread_array==ind]))
        transformed_array[spread_array==ind] = 255-int(np.mean(temp_array[spread_array==ind]))

    new_array_wrong[:,:,slices] = transformed_array_wrong
    new_array[:,:,slices] = transformed_array

new_array_wrong = new_array_wrong.astype(int)
new_array = new_array.astype(int)

imshow(new_array_wrong)

enter image description here

imshow(new_array)

enter image description here

0

There are 0 answers