Storing multiple image files in a dictionary - python

I'm relatively inexperienced in python and was writing a shooter game for a school project. I'm trying to de-duplicate some variables which hold images:
wavetransition=pygame.image.load("TransitionScreen.png")
wavetransition=pygame.transform.scale(wavetransition,(WIDTH,HEIGHT))
wavetransition2=pygame.image.load("TransitionScreen1.png")
wavetransition2=pygame.transform.scale(wavetransition2,(WIDTH,HEIGHT))
wavetransition3=pygame.image.load("TransitionScreen2.png")
wavetransition3=pygame.transform.scale(wavetransition3,(WIDTH,HEIGHT))
wavetransition4=pygame.image.load("TransitionScreen3.png")
wavetransition4=pygame.transform.scale(wavetransition4,(WIDTH,HEIGHT))
wavetransition5=pygame.image.load("TransitionScreen4.png")
wavetransition5=pygame.transform.scale(wavetransition5,(WIDTH,HEIGHT))
these images are used as transition screens between levels in the game. They are then called in a random.randrange() variable:
rander=random.randrange(1,4)#Just For These Numbers To Redefine
if rander2==1:#The Random Backgrounds Displayed On The Wave Screen
screen2.blit(wavetransition,(0,0))
if rander2==2:
screen2.blit(wavetransition2,(0,0))
if rander2==3:
screen2.blit(wavetransition3,(0,0))
if rander2==4:
screen2.blit(wavetransition4,(0,0))
if rander2==5:
screen2.blit(wavetransition5,(0,0))
is there any way to make this appear 'shorter'? Thanks

Use lists and iterations:
# image paths
img_paths = ["TransitionScreen.png", "TransitionScreen1.png", ...]
wavetransitions = []
for img_path in img_paths:
# loads, resizes and adds image to wavetransitions list
img = pygame.image.load(img_path)
img = pygame.transform.scale(img, (WIDTH, HEIGHT))
wavetransitions.append(img)
# as rander2 is the index+1 of the image, you can simply do
screen2.blit(wavetransitions[rander2 - 1], (0, 0))

You could use a list for images and a dict for wavetransitions:
import re
import random
images = ["TransitionScreen0.png", # Note, added 0 to the filename
"TransitionScreen1.png",
"TransitionScreen2.png",
"TransitionScreen3.png",
"TransitionScreen4.png"]
wavetransitions = dict()
for image in images:
m = re.search(r'(\d+)$', image.split('.')[0]).group(0)
key = "wavetransition" + m # m is the number that ends the name of image
value = pygame.image.load(image)
value = pygame.transform.scale(value, (WIDTH, HEIGHT))
wavetransitions[key] = value
wavetransitions_keys = wavetransitions.keys()
screen2.blit(wavetransitions[random.choice(wavetransitions_keys)], (0, 0))

Related

Have padding white space between each image

In a previous question on the following link Concatenate muliple images with pillow in python, I got the following code that merges each four images together. The code is working very well and I appreciate that to #CrazyChucky
from pathlib import Path
from more_itertools import chunked
from PIL import Image
def concat_images(*images):
"""Generate composite of all supplied images."""
# Get the widest width.
width = max(image.width for image in images)
# Add up all the heights.
height = sum(image.height for image in images)
composite = Image.new('RGB', (width, height))
# Paste each image below the one before it.
y = 0
for image in images:
composite.paste(image, (0, y))
y += image.height
return composite
if __name__ == '__main__':
# Define the folder to operate on (currently set to the current
# working directory).
images_dir = Path('.')
# Define where to save the output (shown here, will be in `output`
# inside the images dir).
output_dir = images_dir / 'output'
# Create the output folder, if it doesn't already exist.
output_dir.mkdir(exist_ok=True)
# Iterate through the .png files in groups of four, using an index
# to name the resulting output.
png_paths = images_dir.glob('*.png')
for i, paths in enumerate(chunked(png_paths, 4), start=1):
images = [Image.open(path) for path in paths]
composite = concat_images(*images)
composite.save(output_dir / f'{i}.png')
My question is how to add padding white space between each image?
I have found this function that helps me a lot (I put it for others to make use of it)
def add_margin(pil_img, top, right, bottom, left, color):
width, height = pil_img.size
new_width = width + right + left
new_height = height + top + bottom
result = Image.new(pil_img.mode, (new_width, new_height), color)
result.paste(pil_img, (left, top))
return result
This seems pretty clear. You just need to pad the height for the image.
def concat_images(*images):
"""Generate composite of all supplied images."""
# Get the widest width.
width = max(image.width for image in images)
# Add up all the heights.
padding = 10
height = sum(image.height+padding for image in images) - padding
composite = Image.new('RGB', (width, height))
# Paste each image below the one before it.
y = 0
for image in images:
composite.paste(image, (0, y))
y += image.height + padding
return composite

Program to Create an image grid dynamically from a folder with images in it

I have a folder with a set of images in it. I want to create any type of program that can take in the path of the folder, number of rows and columns and give me output with an image grid. I am not sure how to do that.
Primitive example.
It uses sys.argv to get arguments pattern instead of path (like "path/*.jpg"), rows, columns
python script 'images/dot-*.png' 2 3
It uses module PIL/pillow to read images, resize them and paste on output image.
import sys
import glob
from PIL import Image
# for test only
#sys.argv += ['images/dot-*.png', 2, 3]
# get arguments
pattern = sys.argv[1]
rows = int(sys.argv[2])
cols = int(sys.argv[3])
# get filenames
filenames = glob.glob(pattern)
# load images and resize to (100, 100)
images = [Image.open(name).resize((100, 100)) for name in filenames]
# create empty image to put thumbnails
new_image = Image.new('RGB', (cols*100, rows*100))
# put thumbnails
i = 0
for y in range(rows):
if i >= len(images):
break
y *= 100
for x in range(cols):
x *= 100
img = images[i]
new_image.paste(img, (x, y, x+100, y+100))
print('paste:', x, y)
i += 1
# save it
new_image.save('output.jpg')

Is there a faster alternative to PIL's Image.paste for multiple images?

I am trying to use image.paste to paste many images onto one background.
My images contain their x,y offset values in their filenames (eg. Image_1000_2000.png is offset 1000,2000).
The code below works, but it's painfully slow. Here's what I've got:
import re
import glob
from PIL import Image
# Disable Decompression Bomb Protection
Image.MAX_IMAGE_PIXELS = None
# Set the dimensions of the blank canvas
newheight = 13000
newwidth = 13000
# Glob all the PNG images in the folder and create the blank canvas
photos = glob.glob("*.png")
blankbackground = Image.new('RGB', (newheight, newwidth), (0, 0, 0))
blankbackground.save(r'..\bg999.png', "PNG")
for photo in photos:
blankbackground = Image.open(r'..\bg999.png')
photog = Image.open(photo)
# Get the x , y offsets from the filenames using re
y_value = re.findall(r"0_(\d*).", photo)[0]
y = int(y_value)
x_value = re.findall(r'_(\d*).', photo)[0]
x = int(x_value)
# The actual paste operation, and save the image to be re-opened later
blankbackground.paste(photog,(x,y))
blankbackground.save(r"..\bg999.png")
print(photo)
Any suggestions on a speedier alternative?
EDIT: As per the comments below, it is not necessary to save / reload the image with every photo. This makes it considerably faster.
As pointed out by Siyuan and Dan, Image.save does not require you to save the image and re-load it every loop.
Move the Image.open to before the loop, and move the Image.save to after the loop, as shown:
import re
import glob
from PIL import Image
# Disable Decompression Bomb Protection
Image.MAX_IMAGE_PIXELS = None
# Set the dimensions of the blank canvas
newheight = 13000
newwidth = 13000
# Glob all the PNG images in the folder and create the blank canvas
photos = glob.glob("*.png")
blankbackground = Image.new('RGB', (newheight, newwidth), (0, 0, 0))
blankbackground.save(r'..\bg999.png', "PNG")
# MOVE THE IMAGE.OPEN BEFORE THE LOOP
blankbackground = Image.open(r'..\bg999.png')
for photo in photos:
photog = Image.open(photo)
# Get the x , y offsets from the filenames using re
y_value = re.findall(r"0_(\d*).", photo)[0]
y = int(y_value)
x_value = re.findall(r'_(\d*).', photo)[0]
x = int(x_value)
# The actual paste operation
blankbackground.paste(photog,(x,y))
print(photo)
# MOVE THE IMAGE.SAVE AFTER THE LOOP
blankbackground.save(r"..\bg999.png")
Thus, it goes from ten minutes to ten seconds.

python image scrambeling porgram

I'm writing an image scrambling and Unscrambling program. I'm transfering a custom seed to the random function in order scramble the image pixels in a way that I could unscramble them with the same seed. The scramble part works fine but when I unscramble the scrambled image it leaves some pixels black, I tired using png format since its not being compressed but still no good.
Here is my code:
from PIL import Image
import random
from datetime import datetime
class Scrambler:
#staticmethod
def scramble(key,fileName):
image = Image.open(fileName)
pixels = image.load()
new_image = Image.new(image.mode,image.size)
new_image_pix = new_image.load()
seed = 0
for c in key:
seed+=ord(c)
random.seed(seed)
for i in range(0,(image.size)[0]):
for j in range(0,(image.size)[1]):
new_image_pix[i,j] = pixels[random.randint(0,image.size[0]-1),
random.randint(0,image.size[1]-1)]
new_image.show()
new_image.save('scrambeld.png')
#staticmethod
def unscramble(key,fileName):
image = Image.open(fileName)
pixels = image.load()
new_image = Image.new(image.mode,image.size)
new_image_pix = new_image.load()
seed = 0
for c in key:
seed+=ord(c)
random.seed(seed)
for i in range(0,(image.size)[0]):
for j in range(0,(image.size)[1]):
new_image_pix[random.randint(0,image.size[0]-1),
random.randint(0,image.size[1]-1)] = pixels[i,j]
new_image.show()
new_image.save('unscarmbeld.png')
original image:
scrambeld image:
image after Un Scrambeling:
Much appreciate any help.
You don't insure that every pixel in the original images gets placed (assigned from) in the scrambled image, which means that those pixels won't get filled in in the unscrambled image.

Making image brightened in python using putdata

This is the question:
Write a program in Python which opens the file 'pixerror.png', removes the S&P noise and will correct the brightness of the image, save the processed photo under another name. You have to look pixel for pixel and cannot use blurb functions.
My fist task is to get the image brighter.
I used this question code, but i cannot solve my error that I have. This error:
_
ruisclasse.py 41
putdata exceptions.SystemError:
new style getargs format but argument is not a tuple
_
And this is my code.
_
from __future__ import division #for floating number
from PIL import Image
import cv2
filename='pixerror.png'
action = 'lighten'
extent = 10
#load the original image into a list
original_image = Image.open(filename, 'r')
pixels = original_image.getdata()
#initialise the new image
new_image = Image.new('RGB', original_image.size)
new_image_list = []
brightness_multiplier = 1.1
if action == 'lighten':
brightness_multiplier += (extent/100)
else:
brightness_multiplier -= (extent/100)
#for each pixel, append the brightened or darkened version to the new image list
for pixel in pixels:
new_pixel = (int(pixel[0] * brightness_multiplier),
int(pixel[1] * brightness_multiplier),
int(pixel[2] * brightness_multiplier))
#check the new pixel values are within rgb range
new_pixel= [max(min(channel, 255), 0) for channel in new_pixel]
new_image_list.append(new_pixel)
#save the new image
new_image.putdata(new_image_list)
new_image.save('colour_brightness.jpg')
cv2.waitKey(0)
cv2.destroyAllWindows()
new_pixel= [max(min(channel, 255), 0) for channel in new_pixel]
new_image_list.append(new_pixel)
You're appending lists to new_image_list, but you should be appending tuples.
new_pixel= [max(min(channel, 255), 0) for channel in new_pixel]
new_image_list.append(tuple(new_pixel))

Categories

Resources