{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# MAC0317/MAC5920\n", "## Introdução ao Processamento de Sinais Digitais\n", "### Seção 1.3: Sinais e imagens" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Inclui os módulos utilizados\n", "import math as m\n", "import numpy as np\n", "from matplotlib.colors import LinearSegmentedColormap\n", "import matplotlib.pyplot as plt\n", "%matplotlib inline\n", "from mpl_toolkits.mplot3d import Axes3D\n", "from IPython.display import Audio\n", "from ipywidgets import Dropdown, Label, FloatSlider, IntSlider, Layout, ToggleButton, ToggleButtons, interactive, VBox, HBox, AppLayout" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Sinais unidimensionais\n", "> - modelados como funções de uma variável real $t\\in[a,b]$ (costuma representar o *tempo*)\n", "> - $f(t)\\in\\mathbb{R}$ pode representar pressão (sonora), corrente/potencial elétric@, velocidade de um objeto, temperatura, etc. \n", "\n", "### Exemplo (Figura 1.1 - Versão interativa): Um sinal analógico com duas componentes senoidais\n", "\n", "Considere a função do exemplo da página 4\n", "\n", "$$ x = a_1\\sin(w_1t)+a_2\\sin(w_2t), $$\n", "para $t\\in[0,4\\pi]$" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#cria os sliders para os parametros\n", "a1 = FloatSlider(min=0, max=1, step=.05, value=0.75, continuous_update=False, description=r'$a_1$')\n", "a2 = FloatSlider(min=0, max=1, step=.05, value=0.5, continuous_update=False, description=r'$a_2$')\n", "w1 = FloatSlider(min=1, max=15, step=.1, value=3, continuous_update=False, description=r'$w_1$')\n", "w2 = FloatSlider(min=1, max=15, step=.1, value=7, continuous_update=False, description=r'$w_2$')\n", "\n", "# Função que plota o sinal \n", "def plt_signal(a1, w1, a2, w2):\n", " # Cria um domínio temporal entre 0 e 4$\\pi$ com 800 amostras/segundo\n", " # (esta é uma amostragem arbitrária, mas que permite plotar/visualizar a função \"como se fosse contínua\")\n", " t = np.arange(0,4 * m.pi, 1/800)\n", " # Cria o sinal x(t) com base nos coeficientes\n", " x = a1 * np.sin(w1 * t) + a2 * np.sin(w2 * t)\n", " # Mostra o gráfico da função;\n", " # o '.' impede os pontos adjacentes de serem conectados por segmentos de reta;\n", " # markersize (ou ms) regula a largura da linha.\n", " plt.figure(figsize=(15,5))\n", " plt.axhline(y=0.0, color='gray', linestyle='--', ms=1)\n", " plt.plot(t, x, '.', markersize=1)\n", " plt.xlim([0, max(t)])\n", " plt.title(r'Sinal $x(t) = {}\\sin({}t)+{}\\sin({}t)$'.format(a1, w1, a2, w2), fontdict = {'fontsize' : 14})\n", " plt.ylabel('amplitude')\n", " plt.xlabel('tempo (s)')\n", " \n", " plt.show()\n", "# Cria o ambiente interativo\n", "w = interactive(plt_signal, a1=a1, w1=w1, a2=a2, w2=w2)\n", "display(VBox([\n", " w.children[4],\n", " HBox([\n", " VBox(w.children[0:2]),\n", " VBox(w.children[2:4])],\n", " layout=Layout(justify_content='center'))\n", " ]))\n", "w.update()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Amostragem temporal\n", "\n", "> - passagem do domínio contínuo ($t\\in[a,b]$) para domínio discreto ($n=0,1,\\ldots,N$)\n", "> - parametrizada pelo intervalo de amostragem ($\\Delta_t=\\frac{b-a}{N}$) ou taxa de amostragem ($SR=\\frac{N}{b-a}$)\n", "\n", "> $$x_n = x(a+n\\Delta_t) = x\\left(a+\\frac{n}{SR}\\right)$$\n", "\n", "> - produz um vetor $x=(x_0,x_1,\\ldots,x_N)\\in\\mathbb{R}^{N+1}$." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": false }, "outputs": [], "source": [ "N = IntSlider(min=1, max=400, step=1, value=100, continuous_update=False, layout=Layout(width='95%'))\n", "analog = ToggleButton(value=False, description='Mostrar Sinal original', icon='check', layout=Layout(width='300px'))\n", "\n", "def plt_sampled_signal(N, analog):\n", " # Cria o sinal x(t) com base nos coeficientes\n", " t = np.arange(0,4 * m.pi, 1/800)\n", " x = 0.75 * np.sin(3 * t) + 0.5 * np.sin(7 * t)\n", " # Cria o sinal Amostrado com N amostras,\n", " xs = [x[i] if i % int(len(x)/N + 1)== 0 else None for i in range(len(x))]\n", " #Cria o gráfico do sinal\n", " plt.figure(figsize=(15,4))\n", " plt.title(r'Sinal $x(t) = 0.75\\sin(3t)+0.5\\sin(7t)$ amostrado com N={} pontos'.format(N),\n", " fontdict = {'fontsize' : 14})\n", " plt.ylabel('amplitude')\n", " plt.xlabel('tempo (s)')\n", " plt.axhline(y=0.0, color='gray', linestyle='--', ms=1)\n", " plt.xlim([0, max(t)])\n", " if analog:\n", " plt.plot(t, x, markersize=1, label='Sinal \"Analógico\"') \n", " plt.plot(t,xs,'.',ms=7, label='Sinal amostrado', color='orange')\n", " plt.legend(loc='upper left', bbox_to_anchor=(1, 1))\n", " plt.show()\n", "\n", "# Cria o ambiente interativo\n", "w = interactive(plt_sampled_signal, N=N, analog=analog)\n", "display(VBox([w.children[2], w.children[0], w.children[1]], layout=Layout(align_items='center')))\n", "w.update()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Quantização\n", "\n", "**Alternativa à Fig. 1.2:** sinal amostrado com N=100 e com quantização de variando de 2 a 8 bits (4 a 256 valores)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "analog = ToggleButton(value=False, description='Mostrar Sinal original', layout=Layout(width='auto'))\n", "error = ToggleButton(value=False, description='Mostrar Erro de Quantização', layout=Layout(width='auto'))\n", "bits = ToggleButtons(value=4, options=[2, 4, 6, 8], description='Profundidade de Bits',\n", " layout=Layout(justify_content='center'), style={'description_width': 'initial'})\n", "\n", "def pltsubsampledsignal(analog, error, bits):\n", " N = 100\n", " t = np.arange(0,4 * m.pi, 1/800)\n", " x = 0.75 * np.sin(3 * t) + 0.5 * np.sin(7 * t)\n", " # Normaliza o sinal amostrado entre 0 e 1\n", " lb = min(x)\n", " ub = max(x)\n", " xsnorm = (x - lb) / (ub - lb)\n", " # Quantiza usando 2^bits valores [0...2^(bits-1)]\n", " steps = 2 ** bits\n", " xqnorm = np.floor(steps * xsnorm)\n", " # Coloca de volta na faixa de valores originais [lb...ub], usando como codewords os valores\n", " # médios das 16 faixas entre lb e ub\n", " xq = (ub - lb) * xqnorm / steps + lb + 0.5 * (ub - lb) / steps\n", " # Amostra o sinal quantizado com N amostras\n", " #xqs = [xq[i] if i % int(len(x)/N + 1)== 0 else None for i in range(len(x))]\n", " # Gera o gráfico\n", " plt.figure(figsize=(15,4))\n", " plt.axhline(y=0.0, color='gray', linestyle='--', ms=1)\n", " if analog:\n", " plt.plot(t, x, label='Sinal \"analógico\"')\n", " if error:\n", " # xqs_err = [xq[i] - x[i] if i % int(len(x)/N + 1)== 0 else None for i in range(len(x))]\n", " plt.plot(t, xq - x, '-', ms=5, label='Erro de quantização', color='green')\n", " plt.plot(t, xq, '-', ms=5, label='Sinal amostrado', color='orange')\n", " plt.ylim([-1.5,1.5])\n", " plt.xlim([0, max(t)])\n", " plt.title(r'Sinal $x(t) = 0.75\\sin(3t)+0.5\\sin(7t)$ quantizado com {} bits'.format(bits),\n", " fontdict = {'fontsize' : 14})\n", " plt.ylabel('amplitude')\n", " plt.xlabel('tempo (s)')\n", " plt.legend(loc='upper left', bbox_to_anchor=(1, 1))\n", " plt.show()\n", " \n", "w = interactive(pltsubsampledsignal, N=N,error=error, analog=analog, bits=bits)\n", "display(VBox([w.children[3], w.children[2], HBox(w.children[0:2],\n", " layout=Layout(justify_content='space-around', margin='10px'))]))\n", "\n", "w.update()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Figura 1.3: acréscimo de ruído aditivo\n", "\n", "$$y_n = x_n+\\varepsilon_n$$ " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "analog = ToggleButton(True, description='Mostrar Sinal original', layout=Layout(width='auto'))\n", "noise = ToggleButton(False, description='Mostrar ruído', layout=Layout(width='auto'))\n", "a = FloatSlider(0.5, min=0, max=1, continuous_update=False, description='nível de ruído',\n", " style={'description_width': 'initial'})\n", "\n", "def pltsubsampledsignal(analog, a, noise):\n", " N = 100\n", " t = np.arange(0,4 * m.pi, 1/800)\n", " x = 0.75 * np.sin(3 * t) + 0.5 * np.sin(7 * t)\n", " # Cria o ruído aleatório e soma ao sinal\n", " ruido = a*(np.random.rand(len(x))-0.5)\n", " xr = x + ruido\n", " # Amostra o sinal quantizado com N amostras\n", " xrs = [xr[i] if i % int(len(x)/N + 1)== 0 else None for i in range(len(x))]\n", " # Gera o gráfico\n", " plt.figure(figsize=(15,4))\n", " plt.axhline(y=0.0, color='gray', linestyle='--', ms=1)\n", " if analog:\n", " plt.plot(t, x, label='Sinal \"analógico\"')\n", " if noise:\n", " plt.plot(t, ruido, '-', ms=1, label='Sinal ruidoso', color='green', alpha=0.5)\n", " plt.plot(t, xrs, '*', ms=5, label='Sinal amostrado', color='orange')\n", " plt.ylim([-1.5,1.5])\n", " plt.xlim([0, max(t)])\n", " plt.title(r'Sinal $x(t) = 0.75\\sin(3t)+0.5\\sin(7t)$ amostrado com N=100 pontos, com ruído',\n", " fontdict = {'fontsize' : 14})\n", " plt.ylabel('amplitude')\n", " plt.xlabel('tempo (s)')\n", " plt.legend(loc='upper left', bbox_to_anchor=(1, 1))\n", " plt.show()\n", " \n", "w = interactive(pltsubsampledsignal, noise=noise, analog=analog, a=a)\n", "display(VBox([w.children[3], HBox(w.children[0:3], layout=Layout(justify_content='space-around', width='850px'))]))\n", "w.update()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Exemplo adicional:** transpõe o sinal para a faixa audível e toca\n", "- gera D=2.5 segundos de sinal a 8000 amostras/segundo\n", "- multiplica as frequências por F=1000 para cairem na faixa audível.\n", "\n", " As frequências originais eram\n", " $\\frac{3}{2\\pi} = 0.477\\ \\mbox{Hz}$\n", " e \n", " $\\frac{7}{2\\pi} = 1.114\\ \\mbox{Hz},$\n", " assim as novas serão $477$ Hz e $1114$ Hz.\n", " \n", " As amplitudes serão reduzidas para garantir que o resultado esteja sempre na faixa $[-1,+1]$ e assim evitar distorções." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "__Exemplo adicional:__ Versão audível com quantização" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a1 = FloatSlider(0.25, min=0, max=0.3, step=.01, continuous_update=False, description=r'$a_1$')\n", "a2 = FloatSlider(0.167, min=0, max=0.3, step=.01, continuous_update=False, description=r'$a_2$')\n", "w1 = FloatSlider(477, min=300, max=3000, step=1, continuous_update=False, description=r'$w_1$')\n", "w2 = FloatSlider(1114, min=300, max=3000, step=1, continuous_update=False, description=r'$w_2$')\n", "# não normalizado\n", "def play_signal(a1, w1, a2, w2):\n", " T = np.arange(0,2.5 ,1/8000)\n", " X = a1 * np.sin(w1 * 2 * m.pi * T) + a2 * np.sin(w2 *2 * m.pi * T)\n", " display(Audio(X, rate=8000))\n", "\n", "orig = interactive(play_signal, a1=a1, w1=w1, a2=a2, w2=w2) \n", "orig.update()\n", "AppLayout(\n", " header=HBox([Label(r'$\\large{x(t) = a_1 \\sin(w_1 2\\pi t) + a_2 \\sin(w_2 2 \\pi t)}$', style={'color': 'red'})], layout=Layout(justify_content='center')),\n", " center=HBox([orig.children[-1]], layout=Layout(justify_content='center')),\n", " footer=HBox([VBox([a1, w1]), VBox([a2, w2])], layout=Layout(justify_content='center')),\n", " pane_heights=[10, 20, 20]\n", ")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "b = ToggleButtons(value=4, options=[2, 4, 6, 8, 10], description='Profundidade de Bits',\n", " layout=Layout(justify_content='center'), style={'description_width': 'initial'})\n", "# Não normalizado\n", "T = np.arange(0, 2.5, 1 / 8000)\n", "X = 0.25 * np.sin(477 * 2 * m.pi * T) + 0.167 * np.sin(1114 * 2 * m.pi * T)\n", "ub, lb = min(X), max(X) \n", "XNORM = (X - lb)/(ub - lb)\n", "def play_quantized(bits):\n", " steps = 2 ** bits\n", " # Quantiza\n", " XQNORM = np.floor(steps * XNORM)\n", " XQ = (ub - lb) * XQNORM / steps + lb + 0.5 * (ub - lb) / steps\n", " display(Audio(XQ, rate=8000, normalize=False))\n", " \n", " \n", "def play_quant_error(bits):\n", " steps = 2 ** bits\n", " # Quantiza\n", " XQNORM = np.floor(steps * XNORM)\n", " XQ = (ub - lb) * XQNORM / steps + lb + 0.5 * (ub - lb) / steps\n", " display(Audio(XQ-X, rate=8000, normalize=False))\n", " \n", "quant, error = interactive(play_quantized, bits=b), interactive(play_quant_error, bits=b)\n", "quant.update(), error.update()\n", "AppLayout(\n", " header=HBox([Label(r'$\\large{x(t) = 0.25 \\sin(477 \\times 2\\pi t) + 0.167 \\sin(1114 \\times 2\\pi t)}$')],\n", " layout=Layout(justify_content='center')),\n", " left_sidebar=VBox([Label('Audio quantizado'), quant.children[-1]], layout=Layout(align_items='center')),\n", " right_sidebar=VBox([Label('Erro de quantização'), error.children[-1]], layout=Layout(align_items='center')),\n", " footer=b\n", ")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "level = FloatSlider(0.167, min=0, max=0.3, step=.01, continuous_update=False, description='amplitude do ruído',\n", " style={'description_width': 'initial'})\n", "def play_noise(a):\n", " global R\n", " T = np.arange(0, 2.5, 1 / 8000)\n", " X = 0.25 * np.sin(1000 * 3 * T) + 0.167 * np.sin(1000 * 7 * T)\n", " R = a * (2 * np.random.rand(len(T)) - 1)\n", " # toca sinal + ruído\n", " display(Audio(X + a * R, rate=8000, normalize=False))\n", "\n", "def play_noise_only(a):\n", " # toca apenas ruído\n", " R = a * (2 * np.random.rand(len(T))- 1)\n", " display(Audio(a * R, rate=8000, normalize=False))\n", "\n", "noise, noise_only = interactive(play_noise, a=level), interactive(play_noise_only, a=level) \n", "noise.update(), noise_only.update()\n", "AppLayout(\n", " header=HBox([Label(r'$\\large{x(t) = 0.25 \\sin(477 \\times 2\\pi t) + 0.167 \\sin(1114 \\times 2\\pi t)}$')],\n", " layout=Layout(justify_content='center')),\n", " left_sidebar=VBox([Label('Audio com ruído'), noise.children[-1]], layout=Layout(align_items='center')),\n", " right_sidebar=VBox([Label('Somente ruído'), noise_only.children[-1]], layout=Layout(align_items='center')),\n", " footer=HBox([level], layout=Layout(justify_content='center'))\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Sinais bidimensionais / imagens\n", "> - modelados como funções de duas variáveis reais $(x,y)\\in[a,b]\\times[c,d]$ (costumam representar o *espaço*)\n", "> - $f(x,y)\\in\\mathbb{R}$ pode representar luminosidade, cor, temperatura, densidade, etc." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Figura 1.4: Uma imagem com 4 componentes senoidais\n", "\n", "$$\\begin{array}{rcl}\n", "f(x,y)&=&1.5\\cos(2x)\\cos(7y)+ 0.75\\cos(5x)\\sin(3y)\\\\\n", "&&-1.3\\sin(9x)cos(15y)+1.1\\sin(13x)sin(11y)\n", "\\end{array}$$" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Define um domínio espacial com 200x200 pontos no retângulo [0,1[x]0,1].\n", "# Lembre-se que os índices crescentes da matriz refletem valores descrescentes do eixo vertical\n", "\n", "density = 200\n", "x = np.arange(0, 1, 1 / density)\n", "y = np.arange(1, 0, -1 / density)\n", "x, y = np.meshgrid(x, y)\n", "f = 1.5 * np.cos(7 * y) * np.cos(2 * x) + 0.75 * np.sin(3 * y) * np.cos(5 * x) \\\n", " -1.3 * np.cos(15 * y) * np.sin(9 * x) + 1.1 * np.sin(11 * y) * np.sin(13 * x)\n", "\n", "fig = plt.figure(figsize=(15, 5))\n", "# Imagem 3D\n", "ax = fig.add_subplot(1, 2, 1, projection='3d')\n", "s = ax.plot_surface(x,y,f,rstride=2, cstride=2, cmap='binary_r', linewidth=0, antialiased=False)\n", "ax.set_title(\"Gráfico de superfície\")\n", "fig.colorbar(s, shrink=1.0, aspect=10)\n", "# Imagem 2D\n", "ax = fig.add_subplot(1, 2, 2)\n", "ax.imshow(f, cmap='binary_r', interpolation='none')\n", "ax.set_title(\"Visão em planta\")\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " __Fig 1.4 - Versão interativa__ : utilizando somente duas componentes senoidais " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a1 = FloatSlider(min=0, max=1, step=.05, value=0.5, continuous_update=False, description=r'$a_1$')\n", "a2 = FloatSlider(min=0, max=1, step=.05, value=0.75, continuous_update=False, description=r'$a_2$')\n", "w1 = FloatSlider(min=1, max=15, step=.1, value=11, continuous_update=False, description=r'$w_1$')\n", "w2 = FloatSlider(min=1, max=15, step=.1, value=8, continuous_update=False, description=r'$w_2$')\n", "\n", "def plot_image(a1, w1, a2, w2):\n", " f = a1*np.cos(w1*y)+ a2*np.sin(w2*x)\n", " # Normaliza a função para o intervalo [0,1], para representar uma imagem em tons de cinza.\n", " lb = np.min(np.min(f)) # lower bound da função\n", " ub = np.max(np.max(f)) # upper bound\n", " g = (f-lb)/(ub-lb) # mapeia linearmente em [0, 1]\n", " plt.figure(figsize=(7, 5))\n", " plt.imshow(g, interpolation='none', cmap='binary_r', vmin=0, vmax=1)\n", " plt.axis('off')\n", " plt.colorbar()\n", " plt.title(r'Sinal $f(t) = {}\\cos({}y)+{}\\sin({}x)$'.format(a1, w1, a2, w2), fontdict = {'fontsize' : 16})\n", " plt.show()\n", " \n", "w = interactive(plot_image, a1=a1, w1=w1, a2=a2,w2=w2)\n", "w.update()\n", "\n", "AppLayout(\n", " center=HBox([w.children[4]], layout=Layout(justify_content='center')),\n", " footer=HBox([VBox(w.children[0:2]), VBox(w.children[2:4])], layout=Layout(justify_content='center'))\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "__Efeito da quantização usando B bits ($2^B$ valores distintos)__\n", "\n", "Note como o aspecto da imagem parece \"pixelizado\", porém essas \"bordas\" acompanham as curvas de nível da função, não tendo relação com a densidade de pontos da matriz.\n", "\n", "Experimente usar outros valores para o parâmetro B." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": false }, "outputs": [], "source": [ "bits = IntSlider(4, min=1, max=8, step=1, description='profundidade de Bits', \n", " continuous_update=False, style={'description_width': 'initial'},\n", " layout=Layout(width='50%'))\n", "def pltimage(B):\n", " f = 0.5*np.cos(11*y)+ 0.75*np.sin(8*x)\n", " # Normaliza a função para o intervalo [0,1], para representar uma imagem em tons de cinza.\n", " lb = np.min(np.min(f)) # lower bound da função\n", " ub = np.max(np.max(f)) # upper bound\n", " g = (f-lb)/(ub-lb) # mapeia linearmente em [0, 1]\n", " gq = np.floor(2**B*g)/2**B+1/2**(B+1)\n", " plt.figure(figsize=(7, 5))\n", " plt.title(r'Sinal $f(t) = 0.5\\cos(11y)+0.75\\sin(8x)$ quantizado com {} bits'.format(B),\n", " fontdict = {'fontsize' : 16})\n", " \n", " plt.imshow(gq, cmap='binary_r', interpolation='none', vmin=0, vmax=1 )\n", " plt.axis('off')\n", " plt.show()\n", "\n", "w = interactive(pltimage, B=bits)\n", "w.update()\n", "\n", "AppLayout(\n", " footer=HBox([w.children[0]], layout=Layout(justify_content='center')),\n", " center=HBox([w.children[1]], layout=Layout(justify_content='center'))\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "__Efeito da amostragem__\n", "\n", "Supondo-se a imagem original contínua (uma função $f(x,y):[a,b]\\times[c,d]\\mapsto\\mathbb{R}$), podemos definir taxas de amostragem $\\Delta_x$ e $\\Delta_y$ e discretizar o domínio da função obtendo uma matriz $\\mathcal{M}\\in\\mathbb{R}^{(M+1)\\times(N+1)}$ com entradas\n", "\n", "$$\\mathcal{M}_{m,n} = f(a+n\\Delta_x,d-m\\Delta_y),$$\n", "\n", "para $m=0,1,\\ldots,M=\\frac{d-c}{\\Delta_y}$ e $n=0,1,\\ldots,N=\\frac{b-a}{\\Delta_x}$.\n", "\n", "Outra estratégia de amostragem toma as amostras no meio dos retângulos de tamanho $\\Delta_x\\times\\Delta_y$, obtendo $\\bar{\\mathcal{M}}\\in\\mathbb{R}^{M\\times N}$ com entradas\n", "\n", "$$\\bar{\\mathcal{M}}_{m,n} = f\\left(a+\\left(n+\\frac{1}{2}\\right)\\Delta_x,d-\\left(m+\\frac{1}{2}\\right)\\Delta_y\\right),$$\n", "\n", "para $m=0,1,\\ldots,M-1$ e $n=0,1,\\ldots,N-1$." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "samples = IntSlider(50, min=1, max=200, step=1, description='Número de amostras', \n", " continuous_update=False, style={'description_width': 'initial'},\n", " layout=Layout(width='100%'))\n", "def plt_sampled_image(N):\n", " f = 0.5*np.cos(11*y)+ 0.75*np.sin(8*x)\n", " # Normaliza a função para o intervalo [0,1], para representar uma imagem em tons de cinza.\n", " lb = np.min(np.min(f)) # lower bound da função\n", " ub = np.max(np.max(f)) # upper bound\n", " g = (f-lb)/(ub-lb) # mapeia linearmente em [0, 1]\n", " indexes = [i * density / N for i in range(N)]\n", " fs = [[g[m.ceil(x), m.ceil(y)] for y in indexes]for x in indexes]\n", " plt.figure(figsize=(7, 5))\n", " plt.title(r'Sinal $f(t) = 0.5\\cos(11y)+0.75\\sin(8x)$, Amostrado com N={}'.format(N),\n", " fontdict = {'fontsize' : 16})\n", " plt.imshow(fs, cmap='binary_r', interpolation='none', vmin=0, vmax=1)\n", " plt.axis('off')\n", " plt.show()\n", "\n", "w = interactive(plt_sampled_image, N=samples)\n", "w.update()\n", "\n", "AppLayout(\n", " footer=HBox([w.children[0]], layout=Layout(justify_content='center')),\n", " center=HBox([w.children[1]], layout=Layout(justify_content='center'))\n", ")\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Figura 1.5: imagem original com ruído aditivo" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "level = FloatSlider(0.1, min=0, max=1, step=0.05, description='Nível de ruído',\n", " continuous_update=False, style={'description_width': 'initial'}, layout=Layout(width='50%'))\n", "analog = ToggleButton(value=True, description='Mostrar imagem')\n", "error = ToggleButton(value=True, description='Mostrar ruído')\n", "\n", "def plt_sampled_image(a, img, ruido):\n", " density = 200\n", " x = np.arange(0,1,1/density)\n", " y = np.arange(1,0,-1/density)\n", " x, y = np.meshgrid(x,y)\n", " f = 0 * x + 0 * y\n", " if img:\n", " f += 0.5*np.cos(11*y)+ 0.75*np.sin(8*x)\n", " lb = np.min(np.min(f)) # lower bound da função\n", " ub = np.max(np.max(f)) # upper bound\n", " f = (f-lb)/(ub-lb) # mapeia linearmente em [0, 1]\n", " if ruido:\n", " f += a * (np.random.rand(f.shape[0], f.shape[1])-0.5)\n", " plt.figure(figsize=(7, 5))\n", " plt.title(r'Sinal $f(t) = 0.5\\cos(11y)+0.75\\sin(8x)$, com adição de ruído',\n", " fontdict = {'fontsize' : 16})\n", " plt.imshow(f, cmap='binary_r', interpolation='none', vmin=0, vmax=1)\n", " plt.axis('off')\n", " plt.show()\n", "\n", "w = interactive(plt_sampled_image, a=level, img=analog, ruido=error)\n", "w.update()\n", "\n", "AppLayout(\n", " center=HBox([w.children[-1]],layout=Layout(justify_content='center')),\n", " footer=VBox([HBox([level], layout=Layout(justify_content='center')),\n", " HBox([analog, error], layout=Layout(justify_content='center'))])\n", ")\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "__Imagens coloridas:__ consistem em várias camadas $f_j(x,y)$ para cada canal de cor $j$." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Create one-color Colormaps\n", "no_color = [[0, 0, 0], [1, 0, 0]]\n", "color = [[0, 0, 0], [1, 1, 1]]\n", "red_cm = LinearSegmentedColormap('red_cm', {'red': color, 'green': no_color, 'blue': no_color})\n", "green_cm = LinearSegmentedColormap('red_cm', {'red': no_color, 'green': color, 'blue': no_color})\n", "blue_cm = LinearSegmentedColormap('red_cm', {'red': no_color, 'green': no_color, 'blue': color})\n", "\n", "# Image dimension in pixels\n", "M, N = 10, 10\n", "# Random colors to be diplayed\n", "C = [ np.random.randint(255,size=(M,N)) for i in range(3) ]\n", "# Plot each channel and the result\n", "f, ax = plt.subplots(1,4,figsize=(15,5))\n", "for i in range(3):\n", " ax[i].imshow(C[i], cmap=[red_cm,green_cm,blue_cm][i], interpolation='none', vmin=0, vmax=255)\n", " ax[i].axis('off')\n", " ax[i].set_title([\"Red\",\"Grenn\", \"Blue\"][i])\n", "ax[3].imshow([[[C[i][m][n] for i in range(3)] for n in range(N)] for m in range(M)], interpolation='none')\n", "ax[3].axis('off')\n", "ax[3].set_title(\"RGB\")\n", "f.show()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.6" } }, "nbformat": 4, "nbformat_minor": 2 }