I'm trying to pad a RGB image with magenta (255, 0, 255) color with np.pad. But I'm getting an error when using RGB values as constant_values. For example:
import numpy as np
from scipy.misc import face
import matplotlib.pyplot as plt
def pad_img(img, pad_with):
pad_value = max(img.shape[:-1])
img_padded = np.pad(img,
((0, (pad_value - img.shape[0])), # pad bottom
(0, (pad_value - img.shape[1])), # pad right
(0, 0)), # don't pad channels
mode='constant',
constant_values=pad_with)
fig, (ax1, ax2) = plt.subplots(1, 2)
ax1.imshow(img)
ax2.imshow(img_padded)
plt.show()
This works fine (padding with white color):
img = face()
pad_img(img, pad_with=255)
And this not (padding with magenta):
img = face()
pad_img(img, pad_with=(255, 0, 255))
Throwing:
ValueError: operands could not be broadcast together with remapped shapes [original->remapped]: (3,) and requested shape (3,2)
I think what you are looking for is:
img = face()
pad_img(img, pad_with=(((255, 0, 255), (255, 0, 255)), ((255, 0, 255), (255, 0, 255)), (0, 0)))
According to numpy doc constant_values is of form:
((before_1, after_1), ... (before_N, after_N))
And I think that is why the error says it gets shape (3,) ((255, 0, 255)) for pad_width while it requests shape (3,2) ((((255, 0, 255), (255, 0, 255)), ((255, 0, 255), (255, 0, 255)), (0, 0)))
Related
I'm trying to get the rgba values of the pixels of an image.
Google suggests I use code similar to this:
from PIL import Image
im = Image.open("C:/Stuff/image.png", "r")
px = list(im.getdata())
My problem is the data not always being in rgba format.
On some images it does return rgba
[(0, 0, 0, 255), (0, 0, 0, 255), (0, 0, 255, 255), [...]
while on others it returns rgb
[(0, 0, 0), (0, 0, 0), (0, 0, 255), [...]
and on some it returns whatever this is
[0, 0, 1, [...]
Is there a way to always get rgba returned?
I have images (png) that are 128x128 pixels, how do I convert the image so that each pixel in the image is closest in color to the ones in the following array?
The array will probably get bigger with more specific colors, but in this case:
[(0, 255, 100), (100, 100, 100), (255, 255, 255), (0, 0, 0), (156, 126, 210)]
I am using the Semantic Segmentation network (SegNet). I am trying to reduce the number of classes and thus rearranging the network.
Therefore, I am also changing the color-coding of the predictions as well. My problem is I don't get the intended colors in the output image.
For e.g.
pascal_palette = np.array([(0, 0, 0),
(0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0),
(0, 0, 128), (0, 128, 0), (0, 0, 0), (0, 0, 0), (128, 0, 0),
(0, 0, 0), (0, 0, 0)
], dtype=np.uint8)
The above line gives perfect results for the three classes as the pixels are only in 1 channel.
The output is as below:
However, if I modify the line and add values to different channels it gives weird output. The output is attached below:
pascal_palette = np.array([(0, 0, 0),
(0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0),
(0, 0, 128), (124, 252, 0), (0, 0, 0), (0, 0, 0), (128, 0, 0),
(0, 0, 0), (0, 0, 0)
], dtype=np.uint8)
Changed the color code to (124, 252, 0). The code should be for lawn green color. I also checked it on a website like RBG codes
What am I missing here? Any explanation will be helpful.
Prediciton code:
prob = model.predict(net_in)[0]
# Reshape to 2d here since the networks outputs a flat array per channel
prob_edge = np.sqrt(prob.shape[0]).astype(np.int)
prob = prob.reshape((prob_edge, prob_edge, 13))
# Upsample
if args.zoom > 1:
prob = interp_map(prob, args.zoom, image_size[1], image_size[0])
# Recover the most likely prediction (actual segment class)
prediction = np.argmax(prob, axis=2)
# Apply the color palette to the segmented image
color_image = np.array(pascal_palette)[prediction.ravel()].reshape(
prediction.shape + (3,))
print('Saving results to: ', args.output_path)
with open(args.output_path, 'wb') as out_file:
Image.fromarray(np.multiply(color_image,255)).save(out_file)
PS. I have used same model for predictions in both case
The problem is very probably in np.multiply(color_image,255).
As you created a pallete already with values from 0 to 255 and you're simply gathering values from this pallete, you don't need to multiply it by 255.
Use simply Image.fromarray(color_image).save(out_file).
I'm trying to create an image from 1d numpy array of integers so that changes to this array reflects in the image. It seems that Image.frombuffer perfectly fits my needs. There's my attempts:
from PIL import Image
import numpy as np
data = np.full(100, 255, dtype = np.int32)
img = Image.frombuffer('RGB', (10, 10), data)
print(list(img.getdata()))
I expected to see a list of 100 tuples (0, 0, 255). But what I'm actually getting is (0, 0, 255), (0, 0, 0), (0, 0, 0), (0, 255, 0), (0, 0, 0), (0, 0, 0), (255, 0, 0), (0, 0, 0), (0, 0, 255), (0, 0, 0), (255, 0, 0), ...
What is the reason of that behavior?
'RGB' uses three bytes per pixel. The buffer that you provided is an array with data type numpy.int32, which uses four bytes per element. So you have a mismatch.
One way to handle it is to use mode 'RGBA':
img = Image.frombuffer('RGBA', (10, 10), data)
Whether or not that is a good solution depends on what you are going to do with the image.
Also note that whether you get (255, 0, 0, 0) or (0, 0, 0, 255) for the RGBA pixels depends on the endianess of the integers in data.
For an RGB image, here's an alternative:
data = np.zeros(300, dtype=np.uint8)
# Set the blue channel to 255.
data[2::3] = 255
img = Image.frombuffer('RGB', (10, 10), data)
Without more context for the problem, I don't know if that is useful for you.
I have two images, both with alpha channels. I want to put one image over the other, resulting in a new image with an alpha channel, just as would occur if they were rendered in layers. I would like to do this with the Python Imaging Library, but recommendations in other systems would be fantastic, even the raw math would be a boon; I could use NumPy.
This appears to do the trick:
from PIL import Image
bottom = Image.open("a.png")
top = Image.open("b.png")
r, g, b, a = top.split()
top = Image.merge("RGB", (r, g, b))
mask = Image.merge("L", (a,))
bottom.paste(top, (0, 0), mask)
bottom.save("over.png")
Pillow 2.0 now contains an alpha_composite function that does this.
img3 = Image.alpha_composite(img1, img2)
I couldn't find an alpha composite function in PIL, so here is my attempt at implementing it with numpy:
import numpy as np
from PIL import Image
def alpha_composite(src, dst):
'''
Return the alpha composite of src and dst.
Parameters:
src -- PIL RGBA Image object
dst -- PIL RGBA Image object
The algorithm comes from http://en.wikipedia.org/wiki/Alpha_compositing
'''
# http://stackoverflow.com/a/3375291/190597
# http://stackoverflow.com/a/9166671/190597
src = np.asarray(src)
dst = np.asarray(dst)
out = np.empty(src.shape, dtype = 'float')
alpha = np.index_exp[:, :, 3:]
rgb = np.index_exp[:, :, :3]
src_a = src[alpha]/255.0
dst_a = dst[alpha]/255.0
out[alpha] = src_a+dst_a*(1-src_a)
old_setting = np.seterr(invalid = 'ignore')
out[rgb] = (src[rgb]*src_a + dst[rgb]*dst_a*(1-src_a))/out[alpha]
np.seterr(**old_setting)
out[alpha] *= 255
np.clip(out,0,255)
# astype('uint8') maps np.nan (and np.inf) to 0
out = out.astype('uint8')
out = Image.fromarray(out, 'RGBA')
return out
For example given these two images,
img1 = Image.new('RGBA', size = (100, 100), color = (255, 0, 0, 255))
draw = ImageDraw.Draw(img1)
draw.rectangle((33, 0, 66, 100), fill = (255, 0, 0, 128))
draw.rectangle((67, 0, 100, 100), fill = (255, 0, 0, 0))
img1.save('/tmp/img1.png')
img2 = Image.new('RGBA', size = (100, 100), color = (0, 255, 0, 255))
draw = ImageDraw.Draw(img2)
draw.rectangle((0, 33, 100, 66), fill = (0, 255, 0, 128))
draw.rectangle((0, 67, 100, 100), fill = (0, 255, 0, 0))
img2.save('/tmp/img2.png')
alpha_composite produces:
img3 = alpha_composite(img1, img2)
img3.save('/tmp/img3.png')