# 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()
```