Python Pillow Changing RGB Value Of Pixels? - python

I'm trying to change the pixels on my picture to darker green than I have already made it, I am trying to add + rgb(0,50,0) to it but I can't seem to be able to do so, could you help? I have put my code in below, and freljord2.png is now just a full green image using getcolor(green, "RGBA")
im = Image.open('freljord2.png')
#one_pixel = im.getpixel((0, 0))
#one_pixel[1] = 0;
#im.save('freljord3.png')
(0, 0, 0, 0)
for x in range(0):
for y in range(0):
im.putpixel((x, y), (210, 210, 210))
for x in range(560):
for y in range(557):
print("hi")
hello = ImageColor.get(00B200)
im.putpixel((x, y), )
im.getpixel((0, 0))
(210, 210, 210, 255)
im.getpixel((0, 50))
(169, 169, 169, 255)
im.save('freljord2.png')

You mention that you want to make your image more dark green, but if you add 50 to each pixel value of an image, you only make it brighter (and greener). What you want to do is to place a green transparent overlay over your existing image. You should create a new image for that with the same size as your original with the color you want to add, and an alpha value, which indicates how transparent it is. Next, you need to paste that image over your original image using a mask.
The following code example should do the trick. The result is shown below. You can play around a little bit with the values to tailor to your needs.
'''
Created on Oct 23, 2016
#author: physicalattraction
'''
import os.path
from PIL import Image
def get_img_dir() -> str:
'''
Return the full path to the image directory
:return: string
'''
pkg_dir = os.path.dirname(__file__)
img_dir = os.path.join(pkg_dir, '..', '..', 'img')
return img_dir
def open_img(img_name: str) -> Image:
'''
Open the given file form the image directory
:param img_name: Name including extension of the image
:return: Image object
'''
img_dir = get_img_dir()
full_img_path = os.path.join(img_dir, img_name)
return Image.open(full_img_path)
def save_img(img: Image, img_name: str):
'''
Save the given image to the image directory
:param img: Image object
:param img_name: Name including the extension of the image
'''
img_dir = get_img_dir()
full_img_path = os.path.join(img_dir, img_name)
img.save(full_img_path)
def overlay(img: Image, overlay_color: tuple):
'''
Place an overlay over an existing image
:param img: Image opened with PIL.Image
:param overlay_color: four-tuple with color to add to your image
'''
assert len(overlay_color) == 4, 'Overlay color shall be a 4-tuple'
img_overlay = Image.new(size=img.size, color=overlay_color, mode='RGBA')
img.paste(img_overlay, None, mask=img_overlay)
color_string = '_'.join([str(c) for c in overlay_color])
filename = 'amsterdam_{color}.jpg'.format(color=color_string)
save_img(img, filename)
if __name__ == '__main__':
ams = open_img('amsterdam.jpg')
green = (0, 50, 0, 128)
overlay(ams, green)
Original image:
Darker green image:

Related

How to display an image in Pygame using list of RGBA values of a image [duplicate]

This question already has answers here:
PIL and pygame.image
(2 answers)
Closed 1 year ago.
I am trying to make a pygame project which involves some images. In these images some are very similar and there is just a change of colour. So I came up with idea that why not to use only one image and change its corresponding colour using Python from this article.
from PIL import Image
import pygame as pg
img = Image.open("Assets/image.png")
img = img.convert("RGBA")
d = img.getdata()
new_image = []
for item in d:
if item[:3] == (0,0,0):
new_image.append((255,255,255,0))
if item[:3] == (23,186,255):
new_image.append((255,38,49,item[3]))
else:
new_image.append(item)
img.putdata(new_image)
img.save("a.png","PNG")
But in the last two lines of the above code its saving the image and I don't want that!
I want to use it in the Pygame code for displaying and then when the program exits the image is gone. So how can I use a list of RGBA values new _image to display an image in Pygame.
Any help would be appreciated.
Use pygame.image.frombuffer() to create a pygame.Surface. However you have to convert the list to a byte array. Use the ctypes module to make a byte array from a list:
flat_list = [e for c in new_image for e in c]
bute_array = (ctypes.c_ubyte * len(flat_list))(*flat_list)
surf = pg.image.frombuffer(bute_array, img.size, img.mode).convert_alpha()
See also PIL and pygame.image.
Notice that there is a bug in your algorithm. You need to use elif instead of if in the middle case:
if item[:3] == (0,0,0):
new_image.append((255,255,255,0))
#if item[:3] == (23,186,255):
elif item[:3] == (23,186,255): # <---
new_image.append((255,38,49,item[3]))
else:
new_image.append(item)
Note: if you want to change the background to a white color, you need to make the color opaque:
new_image.append((255,255,255,0))
new_image.append((255, 255, 255, 255))
Minimal example:
The left image is the test image and the right image is the result:
from PIL import Image
import pygame as pg
import ctypes
img = Image.open("Assets/image.png")
img = img.convert("RGBA")
d = img.getdata()
new_image = []
for item in d:
if item[:3] == (0, 0, 0):
new_image.append((255, 255, 255, 0))
#new_image.append((255, 255, 255, 255))
elif item[:3] == (23, 186, 255):
new_image.append((255, 38, 49, item[3]))
else:
new_image.append(item)
pg.init()
window = pg.display.set_mode(img.size)
flat_list = [e for c in new_image for e in c]
bute_array = (ctypes.c_ubyte * len(flat_list))(*flat_list)
surf = pg.image.frombuffer(bute_array, img.size, img.mode).convert_alpha()
run = True
while run:
for event in pg.event.get():
if event.type == pg.QUIT:
run = False
window.fill(0)
window.blit(surf, (0, 0))
pg.display.flip()
pg.quit()
Side note:
You don't need to load the image using PLI you can access the pixels of a pygame.Surface directly. There are different options:
with the methods get_at / set_at
with pygame.PixelArray object
with the pygame.surfarray module
I may be completely missing the point of your question, but as I understand it, you want to load an image and change some colours. I would do it like this:
#!/usr/bin/env python3
from PIL import Image
import pygame as pg
import numpy as np
# Open image and ensure RGBA mode, not palette image
img = Image.open("image.png").convert('RGBA')
# Define some colours for readability
black = [0,0,0]
white = [255,255,255]
red = [255,0,0]
blue = [0,0,255]
# Make image into Numpy array for vectorised processing
na = np.array(img)
# Make re-usable mask of black pixels then change them to white
mBlack = np.all(na[...,:3] == black, axis=-1)
na[mBlack,:3] = white
# Make re-usable mask of red pixels then change them to blue
mRed = np.all(na[...,:3] == red, axis=-1)
na[mRed,:3] = blue
pg.init()
window = pg.display.set_mode(img.size)
surf = pg.image.frombuffer(na.tobytes(), img.size, img.mode)
run = True
while run:
for event in pg.event.get():
if event.type == pg.QUIT:
run = False
window.fill(0)
window.blit(surf, (0, 0))
pg.display.flip()
pg.quit()
Which makes this image:
display like this:
So you can see the power of the masks I made, you can do things like this:
# Make any pixels that were either red or black become magenta
na[mRed|mBlack,:3] = [255,0,255]
Or:
# Make all pixels that were not black into cyan
na[~mBlack,:3] = [0,255,255]

PIL ImageDraw.Draw() doesn't work when used in a function

I made a program that renders the Mandelbrot set to an image. I put the draw.point() method in a function, but it doesn't seem to actually draw on the final image, but if I put im.save() in the function it does work. The full code actually uses multiprocessing and renders the image CineBench style, which is why I can't put the im.save() in the function, or pull the draw.point() out of it. Is there some other way I can solve the problem?
from PIL import Image, ImageDraw
im = Image.new("RGB", (hor_res, vert_res), (0, 0, 0))
draw = ImageDraw.Draw(im)
def mandelbrot():
# mandelbrot code
def box_renderer(x_start: int, x_end: int, y_start: int, y_end: int):
for y in range(y_start, y_end):
for x in range(x_start, x_end):
colour = 255 - int(255*mandelbrot(x, y)/iterations)
draw.point([x, y], (0, 0, colour))
if __name__ == "__main__":
box_renderer(args)
im.save("mandelbrot.png", "PNG")
This is not the entire program, but hopefully enough to make sense
I'm not sure that your sample code is representative, because this version works fine:
from PIL import Image, ImageDraw
hor_res, vert_res = 200, 200
im = Image.new("RGB", (hor_res, vert_res), (255, 0, 0))
draw = ImageDraw.Draw(im)
def box_renderer(x_start: int, x_end: int, y_start: int, y_end: int):
for y in range(y_start, y_end):
for x in range(x_start, x_end):
colour = 128
draw.point([x, y], (0, 0, colour))
if __name__ == "__main__":
box_renderer(x_start=50,x_end=100,y_start=20,y_end=180)
im.save("mandelbrot.png", "PNG")

adding a rectangle to .tif file

Suppose you have .tif file which has 14 pages (multi image tif). I'd like to draw a rectangle on a specific place on a specific page. However, below example does not paste my img which I drew with ImageDraw anywhere on the second page. Where am I failing this?
from PIL import Image, ImageDraw
im = Image.open('tiffile.tif')
for i, page in enumerate(ImageSequence.Iterator(im)):
if i == 1:
height = width = 800
img = Image.new('RGB', (height, width), (255, 0, 0))
draw = ImageDraw.Draw(img)
page.paste(img, (0,0))
im.save('tiffile_b.tif', save_all=True)
Just like #AKX suggested there's no need to create a new image on to paste it onto the current page. Instead draw the rectangle on that page. However, I had to save all the pages in a list and then create a new .tif file out of the new pages in the list.
from PIL import Image, ImageDraw
im = Image.open('tiffile.tif')
frames=[]
for i, page in enumerate(ImageSequence.Iterator(im)):
page = page.copy()
if i == 1:
box = (0, 590, 2272, 2570)
draw = ImageDraw.Draw(page)
draw.rectangle(box, outline=(0), fill=(250))
frames.append(page)
frames[0].save('testfile_b.tif', save_all=True, append_images=frames[1:])

PIL set pixel as transparent/blank

I have a rule set, if a color is in a list for this cell delete the cell like so
image = PILImage.open('revamp'+img_url)
img = image
random_name = random_filename(path="revamp/media/colorfest/")
img.save(random_name, "PNG")
pixels = image.load()
for pos in area_id:
pixel = pixels[pos[0], pos[1]]
pixel = [pixel[0], pixel[1], pixel[2]]
if pixel in colors:
img.putpixel([pos[0], pos[1]], (0, 0, 0, 0))
img.save(random_name, "PNG")
response['status'] = 'ok'
here's what I get, blacked out cells
original image

PIL - make 1 PNG from JPG and PNG frame

I have 2 images:
PNG (99x97) with white, rotated frame and rest is in full transparency.
JPG - is my generated thumbnail (80x80)
Now I want to put thumbnail into my frame so it looks like some kind of painting. What should I do?
EDIT:
I forgot to add, that picture must be under the frame.
Frame image
I have some script but it shows only a frame. There is no picture in it :/
import Image, ImageDraw
img_size = (99,97)
im = Image.open('logo.jpg')
picture = im.crop((0,0,80,80))
frame = Image.open('thumb-frame.png')
picture = picture.convert('RGBA')
background = Image.new('RGBA', img_size, (255, 255, 255, 0))
background.paste(picture, (10,9))
background.paste(frame, (0,0))
background.save('logocopy.png', 'PNG')
EDIT:
Problem solved. I had to add alpha mask to .paste()
import Image
im = Image.open('logo.jpg')
picture = im.crop((0,0,80,80))
picture = picture.convert('RGBA')
frame = Image.open('thumb-frame.png')
background = Image.new('RGBA', frame.size, (255, 255, 255, 0))
background.paste(picture, (10,9))
background.paste(frame, (0,0), frame)
background.save('logocopy.png', 'PNG')
Here you go. This should take original picture and paste transparent frame image above it. Both pictures should be 100x100, but you can add needed resizing.
from PIL import Image
frame = Image.open('frame.png')
img = Image.open('image.jpg')
img_dest = img.copy().convert('RGBA')
img_dest.paste(frame, (0, 0, 100, 100), frame)
img_dest = img_dest.convert('RGB') # Optional, to remove transparency info
img_dest.save('output.png')

Categories

Resources