# Sesc - Programação para Ilustradores ## Edição de imagens com Programação ## `hackmd.io/@villares/prog-ilustra-e3` - o "problema" das máscaras (da aula passada) terem que ter o mesmo tamanho que a imagem original - uma solução - Ideia de função com `return` (com o objetivo de facilitar as máscaras) ```python def setup(): size(500, 500) m = media(100, 3) print(m * 10) def media(a, b): resultado = (a + b) / 2 return resultado # se esquecer esta linha devolve None ``` - criar uma função que produz uma máscara (pode ser menor do que a imagem a ser recortada) - Aplicar esse corte com função `clip_with_mask()` - Mais máscaras de recorte - Glitchando JPGs... - Se der tempo... manipulações de pixels ### Função de gerar tela exemplo ![image](https://hackmd.io/_uploads/rJQh6Md-R.png) ```python= def setup(): size(500, 500) background(0, 100, 0) t = cria_tela(200, 200, 198) image(t, 100, 100) def cria_tela(w, h, d): tela = create_graphics(w, h) # cria tela de apoio # começa com pixels transparentes tela.begin_draw() tela.background(0, 0, 100) tela.fill(255) tela.circle(w / 2, h / 2, d) tela.end_draw() return tela ``` ### Apresentando `clip_with_mask()` Faz **recorte com máscara** ```python= def clip_with_mask(img, mask, x, y): """Clip an image using a mask, its dimensions, and a given position.""" w, h = mask.width, mask.height result = create_image(w, h, ARGB) result.copy(img, int(x), int(y), w, h, 0, 0, w, h) result.mask(mask) return result ``` #### Exemplo de uso com máscara circular ![image](https://hackmd.io/_uploads/SyC7-7_-0.png) ```python= def setup(): size(500, 500) background(0, 100, 0) mc = mascara_circulo(200, 200, 198) img = load_image('zozima.png') imagem_recortada = clip_with_mask(img, mc, 100, 100) image(imagem_recortada, 0, 0) def clip_with_mask(img, mask, x, y): """Clip an image using a mask, its dimensions, and a given position.""" w, h = mask.width, mask.height result = create_image(w, h, ARGB) result.copy(img, int(x), int(y), w, h, 0, 0, w, h) result.mask(mask) return result def mascara_circulo(w, h, d): tela = create_graphics(w, h) # cria tela de apoio tela.begin_draw() # começa com pixels transparentes tela.fill(255) tela.no_stroke() # desliga a borda o circulo tela.circle(w / 2, h / 2, d) tela.end_draw() return tela ``` #### Mais exemplos - Mexendo a posição do recorte com o mouse ```python def setup(): global img, mc size(500, 500) background(0, 100, 0) mc = mascara_circulo(200, 200, 198) img = load_image('zozima.png') def draw(): background(200) imagem_recortada = clip_with_mask(img, mc, mouse_x, mouse_y) image(imagem_recortada, 150, 150) def clip_with_mask(img, mask, x, y): """Clip an image using a mask, its dimensions, and a given position.""" w, h = mask.width, mask.height result = create_image(w, h, ARGB) result.copy(img, int(x), int(y), w, h, 0, 0, w, h) result.mask(mask) return result def mascara_circulo(w, h, d): tela = create_graphics(w, h) # cria tela de apoio tela.begin_draw() # começa com pixels transparentes tela.fill(255) tela.no_stroke() # desliga a borda o circulo tela.circle(w / 2, h / 2, d) tela.end_draw() return tela ``` - https://github.com/villares/sketch-a-day/blob/main/2023/sketch_2023_07_22/sketch_2023_07_22.py - https://github.com/villares/sketch-a-day/blob/main/2023/sketch_2023_07_22/sketch_2023_07_22.py ### Glitch com JPG - Não sei fazer com PNG ![image](https://hackmd.io/_uploads/rySKjX_WA.png) ```python= from PIL import Image import io def setup(): size(800, 400) no_loop() def draw(): with open('piscina-praticas.jpg', 'rb') as f: list_jpg_bytes = list(f.read()) for _ in range(100): loc = random_int(len(list_jpg_bytes) - 1) list_jpg_bytes[loc] = random_int(1, 255) stream = io.BytesIO(bytes(list_jpg_bytes)) new_img = Image.open(stream) try: image(convert_image(new_img), 0, 0) # PIL.Image to py5Image except: # OSError / UnidentifiedImageError: pass def key_pressed(): #save_frame('###.png') redraw() ``` > a imagem original: ![image](https://hackmd.io/_uploads/By0I08ubC.png) ### Manipulando pixels com [Numpy](https://numpy.org) O exemplo incial "quebrado" que investigamos (o canal vermelho fica totalmente 255 em todos os pixels) ![image](https://hackmd.io/_uploads/ryYAcIOZR.png) ```python= import numpy as np from PIL import Image import py5 def setup(): global temp_img py5.size(800, 800) img_path = 'sample.png' # Sample from sketh 2023_07_22 img = py5.load_image(img_path) temp_img = py5.create_image(img.width, img.height, py5.RGB) for n in range(1, 24): apply_threshold(img, n * 10) def apply_threshold(img, threshold): img.load_np_pixels() img_array = img.np_pixels new_array = np.where(img_array > threshold, 255, 0) temp_img.set_np_pixels(new_array, bands='RGB') temp_img.save(f'{threshold}.png') py5.run_sketch() ``` Consultamos a documentação de integração do py5 com o numpy: https://py5coding.org/integrations/numpy.html A versão "corrigida" que acerta as bandas e produz uma imagem saturada: ![128](https://hackmd.io/_uploads/H1SvkDdbA.png) ```python= import numpy as np from PIL import Image import py5 def setup(): global temp_img py5.size(800, 400) img_path = 'piscina.png' # Sample from sketh 2023_07_22 img = py5.load_image(img_path) temp_img = py5.create_image(img.width, img.height, py5.ARGB) #for n in range(1, 24): # gera vários arquivos # apply_threshold(img, n * 10) apply_threshold(img, 128) # só com 128 def apply_threshold(img, threshold): img.load_np_pixels() img_array = img.np_pixels new_array = np.where(img_array > threshold, 255, 0) temp_img.set_np_pixels(new_array, bands='ARGB') temp_img.save(f'{threshold}.png') py5.image(temp_img, 0, 0) # ver na tela o último resultado py5.run_sketch() ```