I am trying to make something split an Image into two and merge the two images back. I tried to use NumPy to minus a random value from each point on the image and store the value to make it a new image. Then I got a 'photo can not open this file because the formating is currently unsupported, or the file is corrupted.' on the second image. So how can I create an image with these values?
import numpy
import random
from PIL import Image
a = Image.new('RGB', [1280, 720], (255, 255, 255))
a = numpy.array(a)
value = []
for x in a:
for y in range(0, len(x)):
temp = [random.randrange(0, 255), random.randrange(
0, 255), random.randrange(0, 255)]
b = numpy.array(temp)
x[y] = x[y]-b
value.append(temp)
a = Image.fromarray(a)
a.show()
#print(value)
#print(len(value)) # 1280*720=921600
c = numpy.array(value)
d = Image.fromarray(c)
d.show()
CodePudding user response:
b = a.copy()
for position, color_value in numpy.ndenumerate(a):
b[position] = abs(color_value - random.randrange(0, 255))
d = Image.fromarray(b)
d.show()
CodePudding user response:
When processing images with Python, you should try and use vectorised Numpy operations because they are much faster, and less prone to errors. If you start using Python lists
and for
loops, you have probably gone wrong already IMHO.
I am not certain, but I think you want to generate a random image and subtract it from an input image so you need both parts to recreate the whole, so I think you want code more like this:
import numpy as np
from PIL import Image
# Open paddington and ensure he is 3-channel RGB rather than palette
im = Image.open('paddington.png').convert('RGB')
# Make Numpy array from him
na = np.array(im)
# Make another Numpy array (i.e. image) same size as Paddington and full of random numbers
rand = np.random.randint(0,256, na.shape, dtype=np.uint8)
# See how that looks
Image.fromarray(rand).show()
# Subtract random image from Paddington - this vectorised Numpy, fast and easy to get right
split = na - rand
# See how that looks
Image.fromarray(split).show()
# Recreate original by adding random image back to split - vectorised Numpy again
joined = split rand
# See how that looks
Image.fromarray(joined).show()
If you prefer to persist with lists and for
loops, there are a few issues in your code:
you keep recycling
a
, so initially it is PILImage
, then it's a Numpyarray
, then a PILImage
so it is hard to refer back to anything you calculated earlierrather than
c = numpy.array(value)
which gives you an array ofnp.int64
, you should usec = numpy.array(value, dtype=np.uint8)
to get an unsigned 8-bit array, because PIL will not like 192-bits/pixelthe shape of the Numpy array you create from the list will be wrong and need reshaping with
d = Image.fromarray(c.reshape(720,1280,3))
rather than calling
random.randrange()
three times for every pixel and converting the result to a Numpy array, you could callnp.random.randint(0,256,(3),dtype=np.uint8)
to get all three values as a Numpy array in one callyou are probably going to have problems with overflows and underflows since you lose the underlying type of values in lists