python - best way to write a list of images - python

I have this code, a list of images.
self.image0 = gtk.Image()
self.image1 = gtk.Image()
self.image2 = gtk.Image()
[...]
self.image20 = gtk.Image()
self.img = # list of all this 20 images. How to write this?
I'm looking for a way to write this list with a short line.
Can you help me ?
Thanks

Using list comprehension:
self.img = [gtk.Image() for i in range(20)]

You can use list comprehensions like:
self.img = [gtk.Image() for _ in xrange(20)]
Images will be accessible via instance.img[0] but not via instance.image0 anymore.

Related

How to scale multiple images with a for loop?

I'm trying to use a for-loop to iterate through a list of self classes. I want to give each one the same scale.
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("Migue/m_normal.png")
self.quieto = pygame.image.load("Migue/m_normal.png")
self.andando = pygame.image.load("Migue/m_andando_normal.png")
self.image = pygame.transform.scale(self.image, sizenorm)
states = [self.quieto, self.andando]
for i in states:
i = pygame.transform.scale(i, sizenorm)
This wont work, but I can achieve the result using this:
self.quieto = pygame.transform.scale(self.quieto, sizenorm)
self.andando = pygame.transform.scale(self.andando, sizenorm)
The problem is that I have to make a lot of more states, and using that for loop would be shorter. However, it doesn't work like the lower example does. I don't know what's wrong with the loop.
You can create a list of the scaled objects and assign the elements of the list to the original attributes:
states = [self.quieto, self.andando]
states = [pygame.transform.scale(i, sizenorm) for i in states]
(self.quieto, self.andando) = states
This can even be written in a single line
(self.quieto, self.andando) = [pygame.transform.scale(i, sizenorm) for i in [self.quieto, self.andando]]
Alternatively, you can simply put the images in a list:
filenames = ["Migue/m_normal.png", "Migue/m_andando_normal.png"]
self.states = [pygame.transform.scale(pygame.image.load(n), sizenorm) for n in filenames]

Correcting use of pool on python iterable

I'm trying to use multithreading.pool to compare images based on similarity. While I have code working on a single core, using a for loop or map() to iterate over the data, it's dreadfully slow on large groups of images. For that reason I've been trying to implement multiprocessing but I can't seem to get it right. My main question is why doesn't getssim() in the below code change the list?
The structure of the iterable looks something like this:
[[("images/000.jpg",np.ndarray),0.923],...]
Where the float is the simiarlity index of an image compared to the current image being tested. Here is the (somewhat abbreviated) non-working code:
import cv2
import glob
from skimage.measure import structural_similarity as ssim
import operator
import multiprocessing
def makeSimilarList(imagesdata):
simImgList = [] #list of images ordered by their similarity
while(imagesdata):
simImg = findSimilar(imagesdata)
simImgList.append(os.path.basename(simImg))
return simImgList
def getssim(imgd):
similarityIndex = ssim(img1,imgd[0][1])
print(similarityIndex) #this prints correctly
imgd[1] = similarityIndex
return imgd #this appears to have no effect
def findSimilar(imagesdata):
limg = imagesdata.pop()
global img1 #making img1 accessible to getssim, a bad idea!
img1 = limg[0][1]
p = multiprocessing.Pool(processes=multiprocessing.cpu_count(),maxtasksperchild=2)
p.map(getssim,imagesdata)
p.close()
p.join()
imagesdata.sort(key=operator.itemgetter(1))
return limg[0][0] #return name of image
images = [f for f in glob.glob(src + "*." + ftype)]
images.reverse()
imagesdata = [[(f,cv2.imread(f,0)),""] for f in images]
finalList = makeSimilarList(imagesdata)
with open("./simlist.txt", 'w') as f:
f.write('\n'.join(finalList))
Thanks for the help!!
You forgot to assign the result from multiprocessing.map to a variable. The key function should probably read
def findSimilar(imagesdata):
limg = imagesdata.pop()
global img1 # making img1 accessible to getssim, a bad idea!
img1 = limg[0][1]
p = multiprocessing.Pool(maxtasksperchild=2)
imagesdata = p.map(getssim, imagesdata)
p.close()
p.join()
imagesdata.sort(key=operator.itemgetter(1))
return limg[0][0] #return name of image
Since you don't give enough details, I could not test your code, but I think this was the crucial point.

Struggling to resize an image within Tkinter

I have developed a console-based adventure game for my Sixth Form Computing class, and now want to migrate it into Tkinter. The main reason for this is that I can make use of pictures, mainly ones from game-icons.net.
So far so good, but the images are such high quality that they appear huge when I display them. Here is an example:
The code works by using a for loop to iterate through a list of items that are in the current area (that the player is in). Here is the code:
if len(itemKeys) > 0:
l = Label(lookWindow, text="Looking around, you see the following items....\n").pack()
for x in range(0, len(itemKeys)):
icon = PhotoImage(file=("icons\\" + itemKeys[x] + ".png"))
l = Label(lookWindow, image=icon)
l.photo = icon
l.pack()
l = Label(lookWindow, text=("" + itemKeys[x].title())).pack()
l = Label(lookWindow, text=(" " + locations[position][2][itemKeys[x]][0] + "\n")).pack()
else:
l = Label(lookWindow, text="There's nothing at this location....").pack()
The part saying ("icons\\" + itemKeys[x] + ".png") simply goes into the icons folder in the game directory and strings together a file name, which in this case would result in "key.png" because the item we're currently looking at is a key.
Now, however, I want to resize the image. I've tried using PIL (which people say is deprecated but I managed to install just fine?) but so far no luck.
Any help appreciated.
Jake
EDIT:
The question has been marked as a duplicate, but I've already tried to use it, but the person who answered seems to open a file, save it as a ".ppm"(?) file and then display it, but when I try I get a huge error that says that I couldn't display a "PIL.Image.Image".
EDIT 2:
Changed it to this:
im_temp = PILImage.open(("icons\\" + itemKeys[x] + ".png")).resize((250,250), PILImage.ANTIALIAS)
photo = PhotoImage(file=im_temp)
label = Label(lookWindow, image=photo)
label.photo = photo
label.pack()
and now get this:
For python 2 you can do something like this, it should work for python 3 as well after small changes of import
from tkinter import Tk, Label
from PIL import Image, ImageTk
root = Tk()
file = 'plant001.png'
image = Image.open(file)
zoom = 0.5
#multiple image zise by zoom
pixels_x, pixels_y = tuple([int(zoom * x) for x in image.size])
img = ImageTk.PhotoImage(image.resize((pixels_x, pixels_y))) # the one-liner I used in my app
label = Label(root, image=img)
label.image = img # this feels redundant but the image didn't show up without it in my app
label.pack()
root.mainloop()
Instead of resizing those huge images on-the-fly, you could preprocess them before bunding them with your application. I took the 'key' and 'locked chest' images and placed them in a 'icons' subdirectory, then ran this code:
from PIL import Image
import glob
for infn in glob.glob("icons/*.png"):
if "-small" in infn: continue
outfn = infn.replace(".png", "-small.png")
im = Image.open(infn)
im.thumbnail((50, 50))
im.save(outfn)
It created a 'key-small.png' and 'locked-chest-small.png', which you can use in your application instead of the original images.

Raising Image with Tkinter and Python

I have several images that I want to layer in a different order, than the order in which they were created. I am using Python with Tkinter and was wondering if someone could help me with this. The order that I create the images is:
#Using Tkinter
image1 = PhotoImage(file = "imageA.gif")
image2 = PhotoImage(file = "imageB.gif")
image3 = PhotoImage(file = "imageC.gif")
A = canvas.create_image(X,Y,image=image1)
B = canvas.create_image(X,Y,image=image2)
C = canvas.create_image(X,Y,image=image3)
The order in which I create the images cannot be changed, so as of right now C is on top of B which is on top of A.
Is there a way to change the order - without changing the order that I create them - so that B is on top of C, and both on top of A? Perhaps there is some sort of attribute like B.Ontopof(C) ? Thanks for your help in advance.
canvas.tag_raise(item)
at least I think ...

Python for x in list basic question

I am trying to create a function which will load a whole lot of images and map them to appropriate names in PyGame. I'm not all that great with python and this really has me stuck. My current code is this:
tile1 = pygame.image.load("/one.bmp")
tile2 = pygame.image.load("/two.bmp")
tile3 = pygame.image.load("/three.bmp")
and it keeps going on for about 20 tiles. The thing is I just found out that I need a lot more and was wondering how I could do this using a for x in y loop. My basic idea was:
tile = ['/one.bmp', '/two.bmp', '/three.bmp']
tilelist = [1,2,3]
for tile in tile:
tilelist[x] = pygame.image.load(tile)
or something like that but I'm not quite there. I was also wondering if it could be done using dictionaries.
Any help would be appreciated, thanks :)
List comprehensions to the rescue.
tiles = ['/one.bmp', '/two.bmp', '/three.bmp']
tilelist = [pygame.img.load(tile) for tile in tiles]
As #isakkarlsson commented,
...or easier(?) tilelist = map(pygame.img.load, tiles)
To load the data
tile = ['/one.bmp', '/two.bmp', '/three.bmp']
imageMap = {}
for t in tile:
imageMap[t] = pygame.img.load(t)
Then you have all the data in a dictionary and can loop through the file names using imageMap.keys() or the index directly into the dictionary to get a particular image.

Categories