Lendo todas as imagens de uma pasta
Exemplo de execução carregando 110 imagens medievais coletadas pelo artista e educador Daniel Seda.
Tendo visto previamente como ler e usar imagens de arquivos externos com loadImage()
, e a estrutura de dados lista (list
) neste exemplo mais avançado vamos permitir que a pessoa escolha uma pasta e o sketch vai carregar todas as imagens nela encontradas.
A seleção da pasta começa com uma chamada da função selectFolder()
, quando pressioanada a tecla ‘o’ (na função de evento keyPressed()
).
def keyPressed():
if key == 'o':
selectFolder("Selecione uma pasta", "adicionar_imagens")
Note que o primeiro argumento de selectFolder()
é "Selecione uma pasta"
o texto (string) que vai como título da janela de seleção. O segundo argumento "adicionar_imagens"
é mais curioso, trata-se de um string com o nome de uma função que será chamada quando a pessoa terminar de interagir com a janela de seleção de pasta (diretório / folder). Isso é uma estratégia conhecida em programação como designar uma “função de retorno” ou, em inglês, callback.
Na estratégia com callback uma função definida é chamada para nós quando algum evento acontece. Neste nosso caso, a função adicionar_imagens()
é chamada no encerramento da janela de selecionar pastas (esta parte de abrir a janela para selecionar pastas é iniciada com a execução de selectFolder()
, mas o momento do encerramento depende da pessoa usando o programa).
É preciso criar uma variável global para guardar as informações dos arquivos encontrados, fazemos isso com esta linha antes do setup()
que cria uma lista vazia e aponta o nome imagens
para ela:
imagens = []
A função adicionar_imagens()
é executada só quando a pessoa terminou de escolher uma pasta ou se tiver cancelado o processo, ela tem um parâmetro selection
que recebe a pasta selecionada ou o valor especial None
(se a pessoa fechou a janela sem selecionar uma pasta):
def adicionar_imagens(selection):
if selection == None:
print("Seleção cancelada.")
else:
dir_path = selection.getAbsolutePath()
print("Pasta selecionada: " + dir_path)
for file_name, file_path in lista_imagens(dir_path):
img = loadImage(file_path)
img_name = file_name.split('.')[0]
print("imagem " + img_name + " carregada.")
imagens.append((img_name, img))
print('Número de imagens: ' + str(len(imagens)))
Saiba que o código que cuida da janela do sistema operacional para escolhermos a pasta, e também o código da função adicionar_imagens()
, chamada em seguida, são executados em linhas de execução (threads) separadas do sketch principal, isto é correm em separado, e por conta disso não interrompem execução do draw()
, o chamado ‘laço principal de repetição’ do Processing.
O carregamento das imagens é um procedimento razoavelmente lento e por isso é possível vê-las aparecendo aos poucos na tela, conforme são acrescentadas na lista imagens
pela execução do laço for
em adicionar_imagens()
.
Uma boa parte da solução da nossa tarefa, na verdade, está encapsulada em lista_imagens()
, função que usamos em adicionar_imagens()
. Ela recebe o caminho completo da pasta selecionada e devolve uma lista com tuplas dos nomes dos arquivos das imagens e o caminho completo delas para ser usado no loadImage()
:
def lista_imagens(dir=None):
from os import listdir
from os.path import isfile, join
data_path = dir or sketchPath('data')
try:
f_list = [(f, join(data_path, f)) for f in listdir(data_path)
if isfile(join(data_path, f)) and imgext(f)]
except Exception as e:
print("Erro ({0}): {1}".format(e.errno, e.strerror))
return []
return f_list
Não vamos entrar em detalhes aqui, mas você pode querer ler mais sobre compreensão de listas (a maneira compacta de produzir uma lista usada para criar a f_list
) e tratamento de exceções (o trecho dentro dentro de try:
e except... :
) para entender melhor a função lista_imagens()
.
Repare que usamos a pequena função has_image_ext()
para responder se os nomes fornecidos por os.listdir()
tem a terminação mencionada na tupla valid_ext
.
def has_image_ext(file_name):
# extensões dos formatos de imagem que o Processing aceita!
valid_ext = ('jpg', 'png', 'jpeg', 'gif', 'tif', 'tga')
file_ext = file_name.split('.')[-1]
return file_ext.lower() in valid_ext
Por fim, aqui vai o código completo do sketch, que desenha uma grade de imagens no draw()
com os itens da lista imagens
:
from __future__ import unicode_literals , division
imagens = []
w, h = 80, 55
def setup():
global colunas, linhas
size(880, 550)
colunas, linhas = width // w, height // h
print('Posições na grade: ' + str(colunas * linhas))
def draw():
background(0)
# Desenha grade com `imagens` com colunas fixas de largura `w`, imagens mais largas são sobrepostas
contador = 0
for c in range(colunas):
x = c * w
for l in range(linhas):
y = l * h
if contador < len(imagens):
img = imagens[contador][1]
fator = h / img.height
image(img, x, y, img.width * fator, img.height * fator)
contador += 1
def keyPressed():
if key == 'o':
selectFolder("Selecione uma pasta", "adicionar_imagens")
if key == ' ':
imagens[:] = []
if key == 'p':
saveFrame('####.png')
def adicionar_imagens(selection):
if selection == None:
print("Seleção cancelada.")
else:
dir_path = selection.getAbsolutePath()
print("Pasta selecionada: " + dir_path)
for file_name, file_path in lista_imagens(dir_path):
img = loadImage(file_path)
img_name = file_name.split('.')[0]
print("imagem " + img_name + " carregada.")
imagens.append((img_name, img))
print('Número de imagens: ' + str(len(imagens)))
def lista_imagens(dir=None):
"""
Devolve uma a lista de tuplas com os nomes dos arquivos de imagem e os caminhos
completos para cada uma das images na pasta `dir` ou na pasta /data/ do sketch.
Requer a função has_image_ext() para decidir quais extensões aceitar.
"""
from os import listdir
from os.path import isfile, join
data_path = dir or sketchPath('data')
try:
f_list = [(f, join(data_path, f)) for f in listdir(data_path)
if isfile(join(data_path, f)) and has_image_ext(f)]
except Exception as e:
print("Erro ({0}): {1}".format(e.errno, e.strerror))
return []
return f_list
def has_image_ext(file_name):
# extensões dos formatos de imagem que o Processing aceita!
valid_ext = ('jpg', 'png', 'jpeg', 'gif', 'tif', 'tga')
file_ext = file_name.split('.')[-1]
return file_ext.lower() in valid_ext
Uma variante do draw()
que permite largura variável das imagens, fixando a altura, como no exemplo anterior, mas :
def draw():
background(0)
# Desenha `imagens` em filas de altura 'h', deslocando na horizontal com largura de cada imagem.
x = y = 0
for nome, img in imagens:
print(img)
fator = h / img.height
if x + img.width * fator> width:
x = 0
y += h
image(img, x, y, img.width * fator, img.height * fator)
x += img.width * fator
Assuntos relacionados
- Estrutura de pixels das imagens em Pixels e imagens
- Lendo e escrevendo texto em arquivos (file IO)