Uma das tecnologias mais interessantes e de grande utilidade na atualidade são as imagens digitais. Com elas, podemos armazená-las em diversos tipos de bancos de dados com mais segurança e facilidade. Por exemplo, a rede social Instagram as utiliza para que possamos compartilhar diversos momentos de nossas vidas com outras pessoas. Mas como o computador armazena e lida com as imagens digitais?
Uma imagem digital não é nada mais e nada menos do que um conjunto de pixels armazenados nos elementos de uma matriz, essa responsável por conter todos os dados de uma imagem. Esses pixels são separados por três camadas distintas: Vermelho, Verde e Azul. Pode-se fazer uma combinação linear dessas três cores para se trabalhar com inúmeras paletas de cores, essas que são armazenadas em códigos binários e processados pela máquina decodificadora.
Vamos começar a desmembrar uma imagem digital usando a linguagem de progamação Python. Primeiro, vamos plotar uma imagem.
Observação: A imagem a ser escolhida deve estar presente no ambiente de trabalhado a qual você esteja utilizando. Faça o upload da imagem na plataforma de uso em questão para usar este progama .ipynb e as referencie devidamente como o exemplo abaixo.
# importando a biblioteca numpy do Python
import numpy as np
# importando a biblioteca matplotlib do Python
import matplotlib.pyplot as plt
%matplotlib inline
# atribuindo a variável imagem o arquivo jpg a qual se referencia a imagem digital salva no diretório
imagem = plt.imread("melhorramodomundo.jpg")
# definindo as dimensões do gráfico que sustentará a imagem advinda de uma matriz
plt.figure(figsize = (20,6))
# plotando a imagem
plt.imshow(imagem)
# removendo a moldura do gráfico
plt.box(False)
# definindo o título do gráfico
plt.title("Imagem de um Ramo Estudantil Lindo :)")
Text(0.5, 1.0, 'Imagem de um Ramo Estudantil Lindo :)')
Veja com o computador reconhecerá a imagem digital acima utilizada:
# visualizando o tipo da variável na qual a matriz com os dados da imagem está presente
type(imagem)
numpy.ndarray
Como era esperado, a imagem está armazenada em uma matriz, essa que pode ser visualizada abaixo (vale a pena ressaltar que ela não aparece de forma completa, dado que é uma matriz com mais elementos do que pode-se visualizar na tela de um computador de forma clara, repare no uso das reticências).
# plotando o array que armazena os dados referentes a intensidade de cada pixel da imagem
print(imagem)
[[[154 147 141] [154 147 141] [153 146 140] ... [153 144 135] [155 146 137] [157 148 139]] [[154 147 141] [154 147 141] [153 146 140] ... [153 144 135] [156 147 138] [158 149 140]] [[154 147 141] [154 147 141] [153 146 140] ... [154 145 136] [157 148 139] [160 151 142]] ... [[ 39 39 39] [ 42 42 42] [ 47 45 46] ... [181 174 168] [180 173 167] [179 172 166]] [[ 40 40 40] [ 43 43 43] [ 49 47 48] ... [181 174 168] [180 173 167] [179 172 166]] [[ 38 38 38] [ 41 41 41] [ 47 45 46] ... [181 174 168] [180 173 167] [179 172 166]]]
Vamos agora olhar como essa matriz é armazenada, de forma a entender melhor a sua extensão:
# verificando as dimensões dessa matriz
imagem.shape
(6000, 8000, 3)
Repare o seguinte, pode-se ver que a matriz ela está armazenada como um array multidimensional com 6000 linhas e 8000 colunas. Além disso, a matriz possui três camadas, o famoso padrão RGB (Red, Green and Blue). Cada camada é estabelecida por sua própia matriz, de modo que os pixels armazenados estão com diferente intensidades de vermelho, verde e azul, respectivamente em cada uma das camadas.
Como as imagens digitais são representadas através de matrizes, é inerente a disciplina de Álgebra Linear. Como por exemplo, a ideia de combinação linear entre as três camadas de cores que formam um pixel, responsável por nos dar diversos tipos de paletas de cores que juntas formam uma imagem.
Assim como as manipulações que podem ser feitas com matrizes durante o curso de Álgebra Linear, também podemos fazer tais operações utilizando essa matriz que armazena os dados da imagem. Vamos ver a partir de agora algumas dessas aplicações.
Agora, vamos inverter as cores da imagem simplesmente fazendo a inversa da matriz que possui os dados da imagem.
# atribuindo a variável imagemInversa a matriz invertida atribuida a variável imagem
imagemInversa = np.invert(imagem)
# definindo as dimensões da do gráfico que sustentará a imagem advinda de uma matriz
plt.figure(figsize = (20,6))
# plotando a imagemInversa
plt.imshow(imagemInversa)
# removendo a moldura o gráfico
plt.box(False)
# adicionando o título ao gráfico
plt.title("Imagem com Suas Cores Invertidas")
Text(0.5, 1.0, 'Imagem com Suas Cores Invertidas')
Para provar a clareza de todo o processo, vamos inverter novamente a matriz que foi inversa e veja que chegaremos novamente a matriz que representa a imagem original.
# a variável imagem recebe a matriz invertida que está atribuida em matrizInversa
imagem = np.invert(imagemInversa)
# definindo as dimensões do gráfico que sustentará a imagem advinda de uma matriz
plt.figure(figsize = (20,6))
# plotando a imagem
plt.imshow(imagem)
# removendo a moldura do gráfico
plt.box(False)
# adicionando um título ao gráfico
plt.title("Imagem Original Obtida Através da Imagem com Cores Inversas")
Text(0.5, 1.0, 'Imagem Original Obtida Através da Imagem com Cores Inversas')
De forma análoga, podemos fazer a matriz transposta, na qual as linhas viram colunas e colunas viram linhas. Em outras palavras vamos rotacionar a imagem.
# atribuindo a variável imagemTransposta a matriz transposta que armazena os dados da imagem
imagemTransposta = np.transpose(imagem)
# vamos reajustar a ordem das matrizes, dado que não só invertemos as linhas e as colunas,
# mas também a posição delas entre as camadas (como já foi explicado acima)
imagemTransposta = np.swapaxes(imagemTransposta, 0, 1)
imagemTransposta = np.swapaxes(imagemTransposta, 1, 2)
# definindo as dimensões do gráfico que sustentará a imagem advinda de uma matriz
plt.figure(figsize = (6,20))
# plotando a imagemTransposa
plt.imshow(imagemTransposta)
# removendo a moldura do gráfico
plt.box(False)
# adicionando um título ao gráfico
plt.ylabel("Matriz Transposta da Imagem")
Text(0, 0.5, 'Matriz Transposta da Imagem')
Vamos agora usar o exemplo de matrizes de rotação para rotacionarmos a imagem dado um ângulo qualquer. Nesse exemplo, vamos usar uma função pronta do Python. Mas há progamas anteriores em que você pode se inteirar sobre esse assunto. Nela, discutimos como podemos alterar a base utilizada para representar os vetores, aplicando uma transformação linear, de modo que a nova base transformada leve os vetores da base original a outra base em que eles adquirem a propidade de rotacionar em um ângulo qualquer, dado uma matriz de transformação que utiliza propriedades da trigonometria.
Vamos importar as bibliotecas necessárias para esse progama:
# importando a biblioteca scipy do python
import scipy
from scipy import ndimage
Observe como podemos rotacionar uma imagem em 90º usando uma transformação linear através de uma matriz de rotação:
# a variável imagemRotacionada recebe a matriz da variável imagem após sofrer uma transformação linear
# usando uma matriz de rotação. O ângulo é 90°
imagemRotacionada = ndimage.rotate(imagem, 90)
# definindo as dimensões do gráfico que sustentará a imagem advinda de uma matriz
plt.figure(figsize = (6,20))
# plotando a imagemRotacionada
plt.imshow(imagemRotacionada)
# removendo a moldura da imagem
plt.box(False)
# adicionando um título ao gráfico
plt.ylabel("Imagem Rotacionada 90°")
Text(0, 0.5, 'Imagem Rotacionada 90°')
Agora vamos rotacionar 60º a imagem:
# a variável imagemRotacionada recebe a matriz da variável imagem após sofrer uma transformação linear
# usando uma matriz de rotação. O ângulo é 60°
imagemRotacionada = ndimage.rotate(imagem, 60)
# definindo as dimensões do gráfico que sustentará a imagem advinda de uma matriz
plt.figure(figsize = (20,6))
# plotando a imagemRotacionada
plt.imshow(imagemRotacionada)
# removendo a moldura da imagem
plt.box(False)
# adicionando um título ao gráfico
plt.title("Imagem Rotacionada 60°")
Text(0.5, 1.0, 'Imagem Rotacionada 60°')
Vimos acima que cada pixel é composto pela combinação linear entre três cores fundamentais: Vermelho, Verde e Azul (Padrão RGB), e como os pixels são armazenados em matrizes, temos que a imagem é composta por três matrizes, cada uma que corresponde a intensidade de cor de cada camada. Desse modo, vamos visualizar cada camada individualmente.
# vamos pegar cada camada de matrizes que compõem a imagem
# primeiro a variável R recebe uma cópia da matriz que posssui os dados da imagem
# segundo vamos zeras as outras duas camadas, levando em considaderação todas as suas linhas e colunas
R = imagem.copy()
R[:, :, [1, 2]] = 0
# primeiro a variável G recebe uma cópia da matriz que posssui os dados da imagem
# segundo vamos zeras as outras duas camadas, levando em considaderação todas as suas linhas e colunas
G = imagem.copy()
G[:, :, [0,2]] = 0
# primeiro a variável B recebe uma cópia da matriz que posssui os dados da imagem
# segundo vamos zeras as outras duas camadas, levando em considaderação todas as suas linhas e colunas
B = imagem.copy()
B[:, :, [0, 1]] = 0
# definindo as dimensões do gráfico que sustentará a imagem advinda de uma matriz
plt.figure(figsize = (20,6))
# o comando subplot tem a finalidade de plotar mais de um gráfico em uma única compilação
# as entradas subplot(1,3,1) indicam que o gráfico tem uma linha, 3 colunas e o próximo gráfico a ser
# plotado ficará na posição 1
plt.subplot(1,3,1)
# definindo o título do primeiro gráfico
plt.title("Camada R")
# plota a matriz R
plt.imshow(R)
# remove a moldura do gráfico
plt.box(False)
# as entradas subplot(1,3,2) indicam que o gráfico tem uma linha, 3 colunas e o próximo gráfico a ser
# plotado ficará na posição 2
plt.subplot(1,3,2)
# definindo o título do segundo gráfico
plt.title("Camada G")
# plota a matriz G
plt.imshow(G)
# remove a moldura do gráfico
plt.box(False)
# as entradas subplot(1,3,3) indicam que o gráfico tem uma linha, 3 colunas e o próximo gráfico a ser
# plotado ficará na posição 3
plt.subplot(1,3,3)
# definindo o título do terceiro gráfico
plt.title("Camada B")
# plotando a matriz B
plt.imshow(B)
# remove a moldura do gráfico
plt.box(False)
Agora você pode perceber o comportamento de cada matriz individualmente. Vamos agora usar essas três matrizes e combiná-las linearmente, de modo a obter novamente a matriz original.
# mesmo tendo zerado as camadas que não são aquelas referenciadas na matriz, elas ainda existem.
# Portando, para evitar erros de compilação, vamos pegar as linhas, colunas e camadas individuais da matriz
imagemRGB = np.array([R[:, :, 0], G[:, :, 1], B[:, :, 2]])
# novamente, as matrizes de camadas estão desordenadas no array multidimensional imagem.
# Vamos fazer permutações entre as camadas de forma que elas fiquem na ordem desejada
imagemRGB = np.swapaxes(imagemRGB, 0, 1)
imagemRGB = np.swapaxes(imagemRGB, 1, 2)
# definindo as dimensões do gráfico que sustentará a imagem advinda de uma matriz
plt.figure(figsize = (20,6))
# o comando subplot tem a finalidade de plotar mais de um gráfico em uma única compilação
# as entradas subplot(1,4,1) indicam que o gráfico tem uma linha, 4 colunas e o próximo gráfico a ser
# plotado ficará na posição 1
plt.subplot(1,4,1)
# definindo o título do primeiro gráfico
plt.title("Camada R")
# plota a matriz R
plt.imshow(R)
# remove a moldura do gráfico
plt.box(False)
# as entradas subplot(1,4,2) indicam que o gráfico tem uma linha, 4 colunas e o próximo gráfico a ser
# plotado ficará na posição 2
plt.subplot(1,4,2)
# definindo o título do segundo gráfico
plt.title("Camada G")
# plota a matriz G
plt.imshow(G)
# remove a moldura do gráfico
plt.box(False)
# as entradas subplot(1,4,3) indicam que o gráfico tem uma linha, 4 colunas e o próximo gráfico a ser
# plotado ficará na posição 3
plt.subplot(1,4,3)
# definindo o título do terceiro gráfico
plt.title("Camada B")
# plotando a matriz B
plt.imshow(B)
# remove a moldura do gráfico
plt.box(False)
# as entradas subplot(1,4,4) indicam que o gráfico tem uma linha, 4 colunas e o próximo gráfico a ser
# plotado ficará na posição 4
plt.subplot(1,4,4)
# definindo o título do quarto gráfico
plt.title("imagem RGB")
# plotando a matriz imagem, resultante da combinação linear das camadas R, G e B
plt.imshow(imagemRGB)
# remove a moldura do gráfico
plt.box(False)
Podemos também inverter a ordem em que as camadas são estabelecidas. Temos a ordem padrão RGB, mas vamos mostrar como seria, com essa mesma imagem trabalhada como exemplo, as formas BGR e GRB.
# mesmo tendo zerado as camadas que não são aquelas referenciadas na matriz, elas ainda existem.
# Portando, para evitar erros de compilação, vamos pegar as linhas, colunas e camadas individuais da matriz
imagemBGR = np.array([B[:, :, 2], G[:, :, 1], R[:, :, 0]])
# novamente, as matrizes de camadas estão desordenadas no array multidimensional imagem.
# Vamos fazer permutações entre as camadas de forma que elas fiquem na ordem desejada
imagemBGR = np.swapaxes(imagemBGR, 0, 1)
imagemBGR = np.swapaxes(imagemBGR, 1, 2)
# mesmo tendo zerado as camadas que não são aquelas referenciadas na matriz, elas ainda existem.
# Portando, para evitar erros de compilação, vamos pegar as linhas, colunas e camadas individuais da matriz
imagemGRB = np.array([G[:, :, 1], R[:, :, 0], B[:, :, 2]])
# novamente, as matrizes de camadas estão desordenadas no array multidimensional imagem.
# Vamos fazer permutações entre as camadas de forma que elas fiquem na ordem desejada
imagemGRB = np.swapaxes(imagemGRB, 0, 1)
imagemGRB = np.swapaxes(imagemGRB, 1, 2)
# definindo as dimensões do gráfico que sustentará a imagem advinda de uma matriz
plt.figure(figsize = (20,6))
# o comando subplot tem a finalidade de plotar mais de um gráfico em uma única compilação
# as entradas subplot(1,3,1) indicam que o gráfico tem uma linha, 3 colunas e o próximo gráfico a ser
# plotado ficará na posição 1
plt.subplot(1,3,1)
# definindo o título do gráfico
plt.title("Imagem RGB")
# plotando a matriz imagemRGB
plt.imshow(imagemRGB)
# removendo a moldura do gráfico
plt.box(False)
# as entradas subplot(1,3,2) indicam que o gráfico tem uma linha, 3 colunas e o próximo gráfico a ser
# plotado ficará na posição 2
plt.subplot(1,3,2)
# definindo o título do gráfico
plt.title("Imagem BGR")
# plotando a matriz imagem BGR
plt.imshow(imagemBGR)
# removendo a moldura do gráfico
plt.box(False)
# as entradas subplot(1,3,3) indicam que o gráfico tem uma linha, 3 colunas e o próximo gráfico a ser
# plotado ficará na posição 3
plt.subplot(1,3,3)
# definindo o título do gráfico
plt.title("imagemGRB")
# plotando a matriz imagemGRB
plt.imshow(imagemGRB)
# removendo a moldura do gráfico
plt.box(False)
Quem faz uso de aplicativos que editam imagens, já pode ter uma noção mínima de como o processo ocorre após estudar esses assunto. Para finalizar, podemos adicionar valores a cada elemento da matriz, de forma que será possível mudar as intensidades pré-estabelecidas para os pixels que constituem a imagem. Assim, é possível modificar as propiedades da mesma visando obter um novo resultado.
Vamos ver um exemplo básico abaixo:
# adiciona 10 a cada elemento da matriz na camada R, esssa que representará uma nova mudança na intensidade
# dos pixels
R[:, :, 0] += 10
# adiciona 20 a cada elemento da matriz na camada G, esssa que representará uma nova mudança na intensidade
# dos pixels
G[:, :, 1] += 20
# adiciona 15 a cada elemento da matriz na camada B, esssa que representará uma nova mudança na intensidade
# dos pixels
B[:, :, 2] += 15
# define novamente a matrizRGB, através da combinação linear entre as três camadas
imagemRGB = np.array([R[:, :, 0], G[:, :, 1],B[:, :, 2]])
# novamente, as matrizes de camadas estão desordenadas no array multidimensional imagem.
# Vamos fazer permutações entre as camadas de forma que elas fiquem na ordem desejada
imagemRGB = np.swapaxes(imagemRGB, 0, 1)
imagemRGB = np.swapaxes(imagemRGB, 1, 2)
# define as dimensões do gráfico que sustentará a imagem advinda de uma matriz
plt.figure(figsize = (20,6))
# o comando subplot tem a finalidade de plotar mais de um gráfico em uma única compilação
# as entradas subplot(1,2,1) indicam que o gráfico tem uma linha, 2 colunas e o próximo gráfico a ser
# plotado ficará na posição 1
plt.subplot(1,2,1)
# plota a matriz imagem
plt.imshow(imagem)
# adiciona um título ao gráfico
plt.title("ImagemRGB Original")
# remove a moldura do gráfico
plt.box(False)
# as entradas subplot(1,2,2) indicam que o gráfico tem uma linha, 2 colunas e o próximo gráfico a ser
# plotado ficará na posição 2
plt.subplot(1,2,2)
# plota a matriz imagemRGB
plt.imshow(imagemRGB)
# definindo um título para o gráfico
plt.title("Imagem RGB Modificada")
# removendo a moldura do gráfico
plt.box(False)
Partindo do princípio que algoritmos inteligentes aprendem com os dados através de etapas de treinamento, será que um computador teria a capacidade de reconhecer imagens? A resposta é sim! Através do processamento digital das imagens (como você viu, não são nada mais e nada menos que arrays com dados numéricos), esses dados podem passar por inúmeras etapas, usando geralmente redes neurais artificiais e, através disso, o algoritmo pode identificar padrões nesse dados. Desse modo, podemos criar sistemas inteligentes como o que reconhece pessoas através de câmeras. Vale a pena estudar sobre isso!
Imagens Digitais e Matrizes. Universidade Federal Fluminense (UFF), Gazeta da Matemática. Rio de Janeiro. Acesso em 01 de março de 2020. Disponível em: http://gazeta.spm.pt/getArtigo?gid=407.