domingo, 18 de outubro de 2009

Problema 3.11

Esta questão envolve imagens a preto e branco representadas por listas de listas. Os valores podem ser 0 (branco) e 1 (preto). Na lista inicial cada um dos seus elementos (uma lista!) representa uma linha. Em cada linha os elementos representam os pixeis (preto ou branco). Criar um negativo obriga a transformar os pixeis brancos em pretos e vice-versa. Como são todos temos que percorrer, por certa ordem, todas as posições (pixeis) da imagem. Na realidade, uma lista de listas pode representar qualquer matriz e a nossa questão mais complexa é: como percorrer uma matriz? A resposta não é difícil: usar dois ciclos imbricados. É isso que o programa documenta.


import copy

def negativo(imagem):
copia = copy.deepcopy(imagem)
for linha in range(len(imagem)):
for coluna in range(len(imagem[0])):
if imagem[linha][coluna] == 0:
copia[linha][coluna] = 1
else:
copia[linha][coluna] = 0
return copia


Notar que por razões de segurança (não queremos a imagem original estragada) trabalhamos sobre uma cópia. Para termos garantia absoluta de que a imagem original não é afectada usamos o módulo copy e, dentro deste, a função deepcopy. Não chega fazer apenas copia = lista[:]. Isto porque essa cópia seria apenas ao primeiro nível da lista original (shallow copy). Assim, se tivermos elementos mutáveis a esse nível podemos ter problemas. Como isso acontece no nosso caso (os elementos do primeiro nível são listas) e vamos alterá-los, então teríamos garantidamente problemas caso não se usasse uma cópia profunda (deepcopy) que copia a todos os níveis. Atente~se ainda como se faz a indexação. Neste caso, como é uma lista de listas (uma matriz), precisamos de dois índices. O primeiro, dá-nos a linha, o segundo, a coluna (dentro da linha escolhida). A notação copia[linha,coluna] daria erro.


Mas será esta a única maneira de proceder? Não. Podíamos por exemplo, não usar um if dentro dos dois ciclos.



import copy

def negativo_b(imagem):
copia = imagem[:] # just in case...
for linha in range(len(imagem)):
for coluna in range(len(imagem[0])):
copia[linha][coluna] = (imagem[linha][coluna] +1) % 2
return copia


Notar o código da linha 7.

Sem comentários:

Enviar um comentário