Carrega as bibliotecas necessárias e a imagem da Lena.

%matplotlib inline

from skimage import color
import urllib, cStringIO
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image as ImagePIL

lenaUrl = 'https://upload.wikimedia.org/wikipedia/en/2/24/Lenna.png'
f = cStringIO.StringIO(urllib.urlopen(lenaUrl).read())

img = ImagePIL.open(f)
img = np.array(img.getdata(), np.uint8).reshape(img.size[1], img.size[0], 3)
img = color.rgb2gray(img)

plt.imshow(img, cmap=plt.cm.gray)
plt.show()

png

Transforma a imagem para o domínio da frequência e plota centralizando utilizando fftshift.

img_freq = np.fft.fft2(img)
plt.imshow(100*np.log(1+abs(np.fft.fftshift(img_freq))), cmap='gray')

png

Cria uma máscara para ser aplicada ao domínio da frequência.

a, b = img.shape[0]/2, img.shape[1]/2 #centro
r = 20 #raio

y,x = np.ogrid[-a:img.shape[0]-a, -b:img.shape[1]-b]
mask = x*x + y*y <= r*r

plt.imshow(mask, cmap='gray')

png

Aplica a máscara ao domínio da frequência

plt.imshow(100*np.log(1+abs(np.fft.fftshift(img_freq) * mask)) , cmap='gray')

png

Resultado da máscara aplicada.

plt.imshow(abs(np.fft.ifft2(np.fft.fftshift(img_freq) * mask)), cmap='gray')

png

Resultada da máscara transformada de volta pro domínio espacial.

plt.imshow(abs(np.fft.ifft2(mask)), cmap='gray')

png

Carrega as bibliotecas necessárias e a imagem da Lena.

%matplotlib inline

from skimage import color
import urllib, cStringIO
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image as ImagePIL

lenaUrl = 'https://upload.wikimedia.org/wikipedia/en/2/24/Lenna.png'
f = cStringIO.StringIO(urllib.urlopen(lenaUrl).read())

img = ImagePIL.open(f)
img = np.array(img.getdata(), np.uint8).reshape(img.size[1], img.size[0], 3)
img = color.rgb2gray(img)

plt.imshow(img, cmap=plt.cm.gray)
plt.show()

png

Foram implementadas duas funções, a conv2d_naive onde a máscara é sobreposta a cada pixel da imagem e conv2d na qual a imagem que desliza sobre a máscara. A função conv2d é muito mais rápida do que a conv2d_naive, sua velocidade é comparada com a função convolve2d da biblioteca scikit. O tempo de execução (Wall time) segue a ordem: conv2d_naive, conv2d e convolve2d (scikit).

def kernel_flatten(k):
    ret = []
    
    mid_w = k.shape[0]/2
    mid_h = k.shape[1]/2
    for i in range(k.shape[0]):
        for j in range(k.shape[1]):
            ret.append((mid_w-i, mid_h-j, k[i, j]))
    
    return ret, mid_w, mid_h

# A naive aproach
def conv2d_naive(img, kernel, border='valid'):
    ret = np.zeros(img.shape)
    shape = img.shape
    
    ker, mid_w, mid_h  = kernel_flatten(kernel)
    
    for i in range(shape[0]):
        for j in range(shape[1]):
            ignore = False
            
            for k, l, value in ker:
                x, y = (i-k), (j-l) #convolução
                
                if border == 'valid' and (x < 0 or x >= shape[0] or y < 0 or y >= shape[1]):
                    ignore = True
                    break
                
                if border == 'same' and (x < 0 or x >= shape[0] or y < 0 or y >= shape[1]):
                    if x < 0:
                        x = shape[0]+x
                    elif x >= shape[0]:
                        x = x-shape[0]
                    
                    if y < 0:
                        y = shape[1]+y
                    elif y >= shape[1]:
                        y = y-shape[1]
                
                ret[i, j] += value*img[x, y]
            
            if ignore:
                ret[i, j] = 0
    
    if border == 'valid':
        ret = ret[mid_w:shape[0]-mid_w,mid_h:shape[1]-mid_h]
    
    return ret

def correlation_2d(img, kernel, border):
    shape = img.shape
    ker, mid_w, mid_h  = kernel_flatten(kernel)
    ret = np.zeros(shape)
    
    tmp = np.tile(img, (3, 3))
    tmp = tmp[shape[0]-mid_w:(shape[0]*2)+mid_w, shape[1]-mid_h:(shape[1]*2)+mid_h]
    
    if border == 'valid':
        tmp[0:mid_w, ::] = 0
        tmp[shape[0]+1:, ::] = 0
        tmp[::, 0:mid_h] = 0
        tmp[::, shape[1]+1:] = 0
    
    for k, l, value in ker:
        x1, x2 = (k+tmp.shape[0]-shape[0]-1, shape[0]+k+1)
        y1, y2 = (l+tmp.shape[1]-shape[1]-1, shape[1]+l+1)
        ret += np.float32(value) * tmp[x1:x2, y1:y2]
    
    if border == 'valid':
        ret = ret[mid_w:shape[0]-mid_w,mid_h:shape[1]-mid_h]
    
    return ret

def conv2d(img, kernel, border='valid'):
    return correlation_2d(img, kernel[::-1, ::-1], border)

mean_kernel = np.array([[1, 1, 1],[1, 1, 1],[1, 1, 1]])
edge_kernel = np.array([[-1, -1, -1],[-1, 8, -1],[-1, -1, -1]])

%time conv1 = conv2d_naive(img, edge_kernel, border='valid')
%time conv2 = conv2d(img, edge_kernel, border='valid')
from scipy import signal
%time conv3 = signal.convolve2d(img, edge_kernel, mode='valid')

plt.imshow(np.absolute(conv2), cmap=plt.cm.gray)
plt.show()

Wall time: 8.71 s
Wall time: 22 ms
Wall time: 14 ms

Resultado da execução da função conv2d utilizando o filtro de Sobel. png

Carrega as bibliotecas necessárias e a imagem da Lena.

%matplotlib inline

from skimage import color
import urllib, cStringIO
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image as ImagePIL

lenaUrl = 'https://upload.wikimedia.org/wikipedia/en/2/24/Lenna.png'
f = cStringIO.StringIO(urllib.urlopen(lenaUrl).read())

img = ImagePIL.open(f)
img = np.array(img.getdata(), np.uint8).reshape(img.size[1], img.size[0], 3)
img = color.rgb2gray(img)

plt.imshow(img, cmap=plt.cm.gray)
plt.show()

png

Cria uma paleta HSV e aplica ela a imagem

def paleta_hsv(img, h_in, h_out):
    h = np.linspace(h_in, h_out, 256).reshape(256) / 360
    s = np.full(256, 0.8)
    v = np.full(256, 0.8)
    
    pallet = np.dstack((np.dstack((h, s)), v))[0]
    
    imgout = np.zeros((img.shape[0], img.shape[1], 3))
    imgout[::, ::] = pallet[np.uint8(img[::, ::]*255)]
    return imgout

ret = paleta_hsv(img, 20, 100)
plt.imshow(color.hsv2rgb(ret))

Resultado: png

Colorização artificial

%matplotlib inline

import urllib, cStringIO
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image as ImagePIL

lenaUrl = 'https://upload.wikimedia.org/wikipedia/en/2/24/Lenna.png'
f = cStringIO.StringIO(urllib.urlopen(lenaUrl).read())

img = ImagePIL.open(f)
img = np.array(img.getdata(), np.uint8).reshape(img.size[1], img.size[0], 3)
img = img[::, ::, 2]

plt.imshow(img, cmap=plt.cm.gray)
plt.show()

png

Utilizando a imagem da Lena acima, vamos colorir ela utilizando uma peleta que varia de R: 0 G: 0 B: 255 (azul) até R: 255 G: 255 B: 255 (branco). Para isto foi implentada a função paleta que recebe de entrada uma imagem e o intervalo utilizado para a criação da paleta.

def paleta(img, rgb_in=(0,0,0), rgb_out=(0,0,0)):
    r = np.linspace(rgb_in[0], rgb_out[0], 256, dtype='uint8').reshape(256)
    g = np.linspace(rgb_in[1], rgb_out[1], 256, dtype='uint8').reshape(256)
    b = np.linspace(rgb_in[2], rgb_out[2], 256, dtype='uint8').reshape(256)
    
    pallet = np.dstack((r, g))
    pallet = np.dstack((pallet, b))
    pallet = pallet[0]
    
    # Mostra a paleta gerada
    tmp = np.tile(pallet, (100, 1, 1)).transpose((1, 0, 2))
    plt.imshow(tmp)
    plt.show()
    
    # Aplica a paleta na imagem
    imgout = np.zeros((img.shape[0], img.shape[1], 3), dtype='uint8')
    imgout[::, ::] = pallet[img[::, ::]]
    
    return imgout

print 'Paleta resultante'
out = paleta(img, (0,0,255), (255,255,255))

print 'Imagem com a paleta aplicada'
plt.imshow(out)
plt.show()

Paleta resultante

png

Imagem com a paleta aplicada

png

Então é isso, até o próximo post!

O mundo real é contínuo, ou seja, entre dois pontos quaisquer existem infinitos pontos. No computador não é possível representar esses infintos pontos, para isso é feita uma amostragem. Fazer a amostragem quer dizer que serão selecionados um número finito de pontos.

%matplotlib inline

import urllib, cStringIO
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image as ImagePIL

lenaUrl = 'https://upload.wikimedia.org/wikipedia/en/2/24/Lenna.png'
f = cStringIO.StringIO(urllib.urlopen(lenaUrl).read())

img = ImagePIL.open(f)
img = np.array(img.getdata(), np.uint8).reshape(img.size[1], img.size[0], 3)

plt.imshow(img)

png

Considerando uma imagem da Lena de resolução 512 pixels de altura e largura, ao aplicar uma amostragem que seleciona metade dos pixels em relação a altura e relação ao largura (down). Depois de aplicar a amostragem down, é obtida uma imagem com altura e largura de 256 pixels (imagem reduzida em 3/4). O amostragem up faz com que sejam repetidos os valores da imagem de forma a criar uma nova imagem com um tamanho maior. (no exemplo a imagem é aumentada 4x)

def amostragem_down(img, n = 2):
    return img[::n, ::n] #corta o array img pelo passo n, tanto na altura quanto pra largura.

def amostragem_up(img, n = 2):
    return np.repeat(np.repeat(img, n, axis=0), n, axis=1)

plt.imshow(amostragem_down(img, 2))
plt.show()
plt.imshow(amostragem_up(img, 2))
plt.show()

png

png

A quantização da imagem é pegar um intervalo de cores (no mundo real é um intervalo não contável) e diminuir para um intervalo finito e contável. Na imagem da Lena vamos transformar cada canal de cor que são representadas no intervalo de 0 a 255 para serem representadas em 0 a N, onde no exemplo o N = 5.

def quantizacao(img, n = 2):
    m = np.amax(img)+1
    a = np.uint8(img/(m/float(n)))
    b = np.uint8((a/(n-1.))*255) #transforma de volta pra 0-255 (para exibir a imagem)
    return b

plt.imshow(quantizacao(img, 5))

png