software para interpolação espacial de imagensmandrade/tvd/galeriadetrabalhos/relatorios... ·...

18
Licenciatura em Engenharia Electrotécnica e de Computadores 5º Ano 1º Semestre 2002/2003 Estica 2002 Software para interpolação espacial de imagens Helder Filipe Patrício Cabral Ferreira ([email protected]) Paulo César Carvalho Pereira ([email protected]) Televisão Digital FEUP, 05/11/2002

Upload: phamcong

Post on 30-Jul-2018

214 views

Category:

Documents


0 download

TRANSCRIPT

Licenciatura em Engenharia

Electrotécnica e de Computadores

5º Ano 1º Semestre

2002/2003

Estica 2002

Software para interpolação espacial de imagens

Helder Filipe Patrício Cabral Ferreira ([email protected]) Paulo César Carvalho Pereira ([email protected])

Televisão Digital

FEUP, 05/11/2002

Objectivos:

Este trabalho tem por objectivo a implementação de um programa que permita manipular ficheiros de imagem. A manipulação desejada consiste em expandir uma determinada imagem seleccionada, ou seja, a partir de uma imagem de tamanho N x M criar uma nova imagem de tamanho a.N x a.M onde a representa o factor de escalamento. No caso da expansão, o factor a tem de ser maior do que zero.

Principios gerais do algoritmo: Para a expansão de uma imagem é necessário definir um método de interpolação para a

atribuição dos novos valores para os pixels. O presente trabalho implementa três métodos distintos, cada um deles revelando-se útil para diferentes situações. Os métodos abordados foram os seguintes:

• Nearest Neighbour • Bilinear • Bicubic

Para os dois últimos métodos, que utilizam operações com janelas de valores, será ainda possível escolher o tipo de operador (média ou mediana).

Quando se expande uma imagem, o número de pixels resultante é obviamente maior.

Sendo assim, há que definir o modo como os novos pixels irão obter um valor a partir da imagem original. Vamos então apresentar e descrever os três métodos de interpolação já referidos, para analisar as diferenças entre eles, e compreendermos as vantagens e desvantagens de cada um. O princípio de mapeamento é comum aos três métodos. Suponhamos que temos duas imagens, de dimensões N x M e a.N x a.M. A posição de coordenadas da nova imagem será mapeada na antiga de acordo com a fórmula

( )

=

ay

axyx ,',' onde os índices x’ e y’ referem-se à imagem expandida e os índices x e y

à imagem original. Normalmente, a não ser que o factor de escalamento seja um múltiplo unitário, as posições resultantes desse mapeamento não são inteiras. As diferenças entre os métodos começam aqui, depois de calculadas as posições estimadas.

Cada um dos métodos implementa uma estratégia distinta para, a partir da imagem

original, atribuir um valor a um pixel na nova imagem.

Televisão Digital, 5º Ano – 1º semestre

Página 2 de 7

Nearest Neighbour

O método de interpolação Nearest Neighbour atribui um valor ao pixel em análise na imagem expandida, que é igual ao valor do pixel do vizinho mais próximo da posição estimada na imagem original.

Se o factor de expansão for, por

exe

Bilinear

método de interpolação Bilinear atri

Bicubic

método de interpolação Bicubic é sem

mplo, duplo, então o método terá como efeito a duplicação das linhas e das colunas.

Obui um valor ao pixel em análise na

imagem expandida, correspondente a uma combinação dos valores de uma vizinhança de 4 elementos (2x2), onde esses elementos correspondem aos 4 vizinhos mais próximos da posição estimada na imagem original.

Oelhante ao Bilinear, residindo a

diferença apenas no tamanho da janela utilizada. Em vez dos 4 vizinhos, este método utiliza 16, sendo também preenchida com os valores dos vizinhos mais próximos da posição estimada na imagem original.

Televisão Digital, 5º Ano – 1º semestre

Página 3 de 7

Ambiente de trabalho: O trabalho foi desenvolvido no Matlab®, Version 6.1.0.450 (R12.1), na já referida

ferramenta “GUIDE, MATLAB’s Graphical User Interface development environment”, tendo sido também utilizadas algumas funções da “Image Processing Toolbox, Version 3.1 (R12.1), 18-May-2001”.

As máquinas onde se fizeram as simulações foram:

- Pentium II a 733 MHz, 128 Mb de RAM - Pentium IV a 1800 MHz, 512Mb de RAM

Implementação: Dos três métodos implementados, apenas o Nearest Neighbour é um método que não

utiliza janelas para o cálculo dos valores dos pixels. O funcionamento da janela pode ser facilmente explicado com o seguinte esquema:

No lado esquerdo temos

uma imagem, a original, e do lado direito uma outra imagem, suponhamos que a expandida. O valor do pixel a sombreado na imagem expandida será dado através de uma combinação dos valores a sombreado na imagem original. Como podemos ver, para um único pixel na imagem expandida, são utilizados vários pixels da imagem original para o cálculo do valor para esse mesmo pixel. No exemplo temos uma janela 3x3, mas os métodos que implementámos, o Bilinear e o Bicubic utilizam janelas de, respectivamente, 2x2 e 4x4. A função que implementa a combinação dos valores da janela, designada no esquema por F, pode ser tanto a “média”, como a “mediana”, bem como uma qualquer combinação de diferentes pesos para cada valor da janela. Normalmente é utilizado o operador “média”. Por uma questão de comparação de resultados e eficiência, implementámos também o operador “mediana”.

As operações com janelas têm vários pontos onde o comportamento é crítico. O que

fazer quando se analisa um ponto extremo de uma imagem, quando a janela teria valores mapeados para além da dimensão da imagem original?

Há várias soluções:

• Atribuir peso 0 aos elementos da janela não representados, mantendo os outros com peso 1.

• Substituir os elementos não representados pelo elemento mais próximo.

• Replicar a imagem original em todas as direcções.

• Espelhar as linhas/colunas limite da imagem original em todas as direcções.

• Outras combinações de pesos para os elementos da janela...

A solução pela qual optamos foi a do espelhamento da imagem original, para evitar o

aparecimento de alterações bruscas de brilhos nas fronteiras entre as imagens.

Televisão Digital, 5º Ano – 1º semestre

Página 4 de 7

Funcionalidades:

Tirando partido da ferramenta “GUIDE, MATLAB’s Graphical User Interface development environment”, foi possível desenvolver uma interface gráfica para maior facilidade e conforto de utilização. A interface1 permite apenas, numa fase inicial, a selecção de uma imagem sobre a qual os algoritmos implementados irão operar. Depois de seleccionada a imagem, pode-se visualizar o respectivo thumbnail, bem como uma lista das principais características da imagem. A partir deste momento, o utilizador pode seleccionar um dos métodos de interpolação e, no caso do método escolhido ser o Bilinear ou Bicubic, é possível ainda escolher o operador para os resultados da janela. Por defeito o factor de expansão está definido como valendo 1, é portanto ainda necessário a alteração deste parâmetro antes de se proceder à expansão da imagem. Depois de seleccionadas as opções pretendidas basta pressionar o botão “Expandir” para dar início à simulação. Depois de terminado o algoritmo, é aberta uma figura do matlab com o resultado da expansão, sendo indicado na figura o método de interpolação seleccionado, bem como o factor de expansão (e ainda o operador, no caso de este ter sido usado). O utilizador poderá consultar todas as imagens resultantes da execução do algoritmo numa directoria criada para o efeito, “Resultados”, onde os ficheiros são gravados automáticamente, com a indicação do nome da imagem original, factor de expansão, método de interpolação, operador, e ainda o tempo de processamento para a geração da imagem expandida.

Apesar de não ser objectivo deste trabalho a redução de imagens, é também possível fazê-lo, bastando para tal introduzir um factor de expansão menor do que 1.

Testes, resultados esperados e obtidos: O objectivo dos nossos testes passou por expandir as imagens onde sabiamos que os

resultados teriam forçosamente comportamentos distintos, onde as diferenças entre os diversos métodos fossem mais díspares.

O método Nearest Neighbour tem o seu ponto forte em imagens cujo conteúdo seja formado por blocos que apresentem direcções predominantemente horizontais e verticais e onde não hajam muitos valores de brilhos, como por exemplo num gradiente. Neste tipo específico de imagens, os métodos de janela não devem apresentar melhores resultados. Foi criada uma imagem do tipo tabuleiro de xadrez para validar os resultados esperados:

Televisão Digital, 5º Ano – 1º semestre

Página 5 de 7

1 Para a visualização de um screenshot por favor consulte o Anexo 1.

Quando os objectos da imagem deixarem de ter uma orientação predominantemente horizontal ou vertical, o método Nearest deixa de ter vantagem:

Apesar de estas imagens terem sofrido um zoom para melhor visualização, dá para

reparar na “dureza” do método Nearest enquanto que os outros métodos apresentam transições bastante mais suaves.

O método Bilinear apresenta resultados bastante melhores que o método Nearest

Neighbour na maior parte das imagens (tirando o exemplo atrás referido), e apresenta vantagens relativamente ao Bicubic por apresentar resultados bastante semelhantes mas com um esfoço computacional inferior (o que para o operador “mediana” não foi por nós verificado). Os resultados deste métodos são melhores do que o “Bicubic” para imagens que apresentem bastantes contornos ténues porque, como utiliza uma janela de apenas 2x2, não os vai esbater tanto.

O método Bicubic é o método mais polivalente dos três apresentados, por ser o que

normalmente apresenta melhores resultados na maior parte das imagens do “dia-a-dia”, à custa de um bastante elevado tempo de processamento quando comparado com o Nearest (cerca de 10 vezes mais em média). As desvantagens deste método prendem-se com o facto de, em imagens com transições rápidas de brilhos bastante distintos, se perder um pouco essa informação (por causa da dimensão da janela) com o consequente “esborratamento” da imagem. Contudo, é o método que, para a generalidade dos casos, apresenta melhores resultados.

Todos os testes até agora realizados com o método Bicubic usavam o operador média.

Vejamos agora o que acontece se usarmos o operador mediana. Suponhamos que temos uma imagem com uma transição abrupta de brilhos, por exemplo, de preto para branco. Quando a janela estiver a operar com valores pertencentes a ambos os brilhos, o operador média irá resultar num brilho não existente na imagem, algo como um brilho com metade

Televisão Digital, 5º Ano – 1º semestre

Página 6 de 7

Televisão Digital, 5º Ano – 1º semestre

Página 7 de 7

da intensidade do preto (que é neste caso o que tem maior brilho), ou seja, um cinzento. Ao utilizar um operador de mediana, o resultado sobre essa janela irá resultar num valor que já pertence à imagem ou seja, os valores para os brilhos da imagem expandida terão obrigatóriamente de se encontar na gama de valores de brilho pertencentes à imagem original. Deste modo, poderemos ter uma aproximação bastante mais fidedigna à imagem original, já que não estão a ser introduzidos novos valores de brilho para os pixels.

A imagem acima torna flagrante as dife nças entre os vários métodos, de onde

pod

as imagens a cores, o algoritmo actua independentemente nas 3 matrizes de cor (a fun

pelo método Nearest notam-se bastantes transições, enquanto que na imagem interpolada pelo

reemos destacar a especial performance do operador mediana, pelas razões acima

apontadas. Os métodos que usam o operador mediana não são capazes de manter o aspecto original da imagem, e o Nearest esbate bastante os círculos. A imagem com o operador de mediana perde também alguma informação sobre os círculos mais pequenos (valores menos frequentes na janela), mas é a que consegue conservar melhor o aspecto original.

N

ção “imread” do Matlab® retorna uma matriz de dimensões N x M x 3) e os resultados são equivalentes aos dos testados nas matrizes “grayscale”, apesar do tempo de processamento ser bastante maior (em média 3 vezes mais).

Nesta imagem a melhor performance é a do método bilinear. Na imagem interpolada

método Bicubic houve um “esborratamento” demasiado elevado. Nestas condições, onde a imagem tem pequenos objectos com poucos pixels de altura/largura, o facto de ter uma janela de menores dimensões permite ao método Bilinear ser a melhor opção.

ANEXO 1 – Screenshot’s da interface implementada

ANEXO 2 – Código implementado function varargout = estica(varargin) if nargin == 0 % LAUNCH GUI %inicializacao clear all clc fig = openfig(mfilename,'new'); % Generate a structure of handles to pass to callbacks, and store it. handles = guihandles(fig); guidata(fig, handles); if nargout > 0 varargout{1} = fig; end %Abertura do Logotipo da FEUP logo_FEUP=imread('feup.jpg'); set(handles.logotipo_FEUP,'CDATA',logo_FEUP); %Abertura do Titulo do programa tit=imread('titulo.jpg'); set(handles.titulo,'CDATA',tit); %Logotipo Wolphin wolphin=imread('wolphin.jpg'); set(handles.wolphin_logo,'CDATA',wolphin); elseif ischar(varargin{1}) % INVOKE NAMED SUBFUNCTION OR CALLBACK try if (nargout) [varargout{1:nargout}] = feval(varargin{:}); % FEVAL switchyard else feval(varargin{:}); % FEVAL switchyard end catch disp(lasterr); end end %-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- % C A L L B A C K S %-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- % -------------------------------------------------------------------- function varargout = Ficheiro_Callback(h, eventdata, handles, varargin) % -------------------------------------------------------------------- % MENU - ABRIR function varargout = Abrir_Callback(h, eventdata, handles, varargin) global ioriginal global ioriginalinfo global img_path % Abertura de uma dialog box para escolha do ficheiro de imagem: [filename, pathname] = uigetfile('*.bmp;*.jpg;*.gif;*.tif', 'Seleccione um ficheiro de imagem'); if ~isequal(filename,0)|isequal(pathname,0) %path completa do ficheiro seleccionado img_path = sprintf('%s%s', pathname, filename); %leitura e recolha de dados do ficheiro original ioriginal = imread(img_path); ioriginalinfo = imfinfo(img_path); end

set(handles.popupmenu1,'Value',1); make_it_visible(h, eventdata, handles, varargin); set(handles.Status, 'String', ' '); set(handles.Show_Time, 'String', ' '); set(handles.novasdimensoes, 'String', ' '); set(handles.save_results,'Enable','off'); % -------------------------------------------------------------------- % MENU - SAIR function varargout = Sair_Callback(h, eventdata, handles, varargin) %fechar todas as janelas abertas e sair do programa... button = questdlg('Tem a certeza que quer sair?', ... 'Abandonar programa...','Sim','Nao','Nao'); switch button case 'Sim', close all; case 'Nao', quit cancel; end % -------------------------------------------------------------------- % Caixa de entrada do factor de expansao function varargout = answer_factor_Callback(h, eventdata, handles, varargin) % -------------------------------------------------------------------- % RADIO - Nearest function varargout = radio_nearest_Callback(h, eventdata, handles, varargin) % Para que os radio_buttons sejam mutuamente exclusivos: off = [handles.radio_bilinear, handles.radio_bicubic]; set(off, 'Value', 0) set(handles.tag_escolhaoperador,'Enable','off'); set(handles.radio_med,'Enable','off'); set(handles.radio_median,'Enable','off'); set(handles.radio_median,'Value',0); % -------------------------------------------------------------------- % RADIO - Bilinear function varargout = radio_Bilinear_Callback(h, eventdata, handles, varargin) % Para que os radio_buttons sejam mutuamente exclusivos: off = [handles.radio_nearest, handles.radio_bicubic]; set(off, 'Value', 0); set(handles.tag_escolhaoperador,'Enable','on'); set(handles.radio_med,'Enable','on'); set(handles.radio_median,'Enable','on'); set(handles.radio_med,'Value',1); set(handles.radio_median,'Value',0); % -------------------------------------------------------------------- % RADIO - Bicubic function varargout = radio_bicubic_Callback(h, eventdata, handles, varargin) % Para que os radio_buttons sejam mutuamente exclusivos: off = [handles.radio_bilinear, handles.radio_nearest]; set(off, 'Value', 0) set(handles.tag_escolhaoperador,'Enable','on'); set(handles.radio_med,'Enable','on'); set(handles.radio_median,'Enable','on'); set(handles.radio_med,'Value',1); set(handles.radio_median,'Value',0); % -------------------------------------------------------------------- % RADIO - Media function varargout = radio_med_Callback(h, eventdata, handles, varargin) % Para que os radio_buttons sejam mutuamente exclusivos: set(handles.radio_median, 'Value', 0) % -------------------------------------------------------------------- % RADIO - Mediana function varargout = radio_median_Callback(h, eventdata, handles, varargin)

% Para que os radio_buttons sejam mutuamente exclusivos: set(handles.radio_med, 'Value', 0) % -------------------------------------------------------------------- % B O T A O D E S I M U L A C A O - E X P A N D I R function varargout = expandir_Callback(h, eventdata, handles, varargin) global ioriginal global ioriginalinfo global scale_factor global method global op global image2write if exist('imodificada', 'var') clear image2write; end answer_factor=str2num(get(handles.insere_factor,'String')); scale_factor = get(handles.insere_factor,'String'); radio=[handles.radio_nearest, handles.radio_bilinear, handles.radio_bicubic]; answer_method=get(radio, 'Value'); method = ' '; % Verifica qual o metodo de interpolacao seleccionado: if answer_method{1} == 1 method = sprintf('nearest'); elseif answer_method{2} == 1 method = sprintf('bilinear'); elseif answer_method{3} == 1 method = sprintf('bicubic'); end % Verifica qual o operador de janela seleccionado: radio_op = [handles.radio_med, handles.radio_median]; answer_op = get(radio_op, 'Value'); op=' '; if answer_op{1} == 1 op = sprintf('mean'); elseif answer_op{2} == 1 op = sprintf('median'); end % Definir as dimensoes actuais e as da imagem expandida: altura_old = ioriginalinfo.Height; largura_old = ioriginalinfo.Width; altura = round(ioriginalinfo.Height*answer_factor); largura = round(ioriginalinfo.Width*answer_factor); novasdim=sprintf('%d x %d', largura, altura); set(handles.tag_novasdimensoes,'Enable','on'); set(handles.novasdimensoes,'Enable','on'); set(handles.novasdimensoes,'String',novasdim); % Colocar o inicio do temporizador para o calculo do tempo de processamento: tic; % Modificar a string de Status: set(handles.Status, 'String', 'A PROCESSAR ...'); set(handles.Show_Time, 'String', ' '); % Verificar se a variavel imodificada ja' existe. % Se existir apaga, para que as novas dimensoes prevalecam. if exist('imodificada', 'var') clear imodificada; end %--------------------------------------------------------- %N E A R E S T if isequal(method,'nearest') if isequal(ioriginalinfo.ColorType,'truecolor') % A imagem tem 3 dimensoes: for K = 1:3 % Criar os vectores para o mapeamento: column_map = round((1:largura)/answer_factor); row_map = round((1:altura)/answer_factor);

% Verifica se algum dos elementos dos vectores ´e zero, e se for passa a 1: column_map(find(~round((1:largura)/answer_factor))) = 1; row_map(find(~round((1:altura)/answer_factor))) = 1; % Preencher a nova matriz com os valores tirados da antiga for I = 1:altura for J = 1:largura imodificada(I,J,K)=ioriginal(row_map(I), column_map(J), K); end end end else % Criar os vectores para o mapeamento: column_map = round((1:largura)/answer_factor); row_map = round((1:altura)/answer_factor); % Verifica se algum dos elementos dos vectores ´e zero, e se for passa a 1: column_map(find(~round((1:largura)/answer_factor))) = 1; row_map(find(~round((1:altura)/answer_factor))) = 1; % Preencher a nova matriz com os valores tirados da antiga for I = 1:altura for J = 1:largura imodificada(I,J)=ioriginal(row_map(I),column_map(J)); end end end figure, imshow(uint8(imodificada)), title(sprintf('Imagem representada a %g %% (metodo ''%s'')', answer_factor*100, method)); end %--------------------------------------------------------- %B I L I N E A R if isequal(method,'bilinear') % Atribuir os valores 'a nova matriz: if isequal(ioriginalinfo.ColorType,'truecolor') % A imagem tem 3 MATRIZES: for K = 1:3 % Criar tambem uma matriz temporaria com mais 4 linhas e 4 colunas % (2 de cada lado) para o espelhamento da imagem original. img_mirrored(altura_old + 4, largura_old + 4, 3) = 0; img_mirrored(3 : altura_old + 2, 3 : largura_old + 2, 1) = ioriginal(:,:,1); img_mirrored(3 : altura_old + 2, 3 : largura_old + 2, 2) = ioriginal(:,:,2); img_mirrored(3 : altura_old + 2, 3 : largura_old + 2, 3) = ioriginal(:,:,3); img_mirrored(1,:,1) = img_mirrored(4,:,1); img_mirrored(2,:,1) = img_mirrored(3,:,1); img_mirrored(:,1,1) = img_mirrored(:,4,1); img_mirrored(:,2,1) = img_mirrored(:,3,1); img_mirrored(1,:,2) = img_mirrored(4,:,2); img_mirrored(2,:,2) = img_mirrored(3,:,2); img_mirrored(:,1,2) = img_mirrored(:,4,2); img_mirrored(:,2,2) = img_mirrored(:,3,2); img_mirrored(1,:,3) = img_mirrored(4,:,3); img_mirrored(2,:,3) = img_mirrored(3,:,3); img_mirrored(:,1,3) = img_mirrored(:,4,3); img_mirrored(:,2,3) = img_mirrored(:,3,3); img_mirrored(altura_old+4,:,1) = img_mirrored(altura_old+1,:,1); img_mirrored(altura_old+3,:,1) = img_mirrored(altura_old+2,:,1); img_mirrored(:,largura_old+4,1) = img_mirrored(:,largura_old+1,1); img_mirrored(:,largura_old+3,1) = img_mirrored(:,largura_old+2,1); img_mirrored(altura_old+4,:,2) = img_mirrored(altura_old+1,:,2); img_mirrored(altura_old+3,:,2) = img_mirrored(altura_old+2,:,2); img_mirrored(:,largura_old+4,2) = img_mirrored(:,largura_old+1,2); img_mirrored(:,largura_old+3,2) = img_mirrored(:,largura_old+2,2);

img_mirrored(altura_old+4,:,3) = img_mirrored(altura_old+1,:,3); img_mirrored(altura_old+3,:,3) = img_mirrored(altura_old+2,:,3); img_mirrored(:,largura_old+4,3) = img_mirrored(:,largura_old+1,3); img_mirrored(:,largura_old+3,3) = img_mirrored(:,largura_old+2,3); switch(op) case 'mean' for I = 1:altura for J = 1:largura canto_l = floor(I/answer_factor); canto_c = floor(J/answer_factor); janela = img_mirrored(... 2 + canto_l - 1 : 2 + canto_l,... 2 + canto_c - 1 : 2 + canto_c,... K); imodificada(round(I), round(J), K) = mean(mean(janela)); end end case 'median' for I = 1:altura for J = 1:largura canto_l = floor(I/answer_factor); canto_c = floor(J/answer_factor); janela = img_mirrored(... 2 + canto_l - 1 : 2 + canto_l,... 2 + canto_c - 1 : 2 + canto_c,... K); imodificada(round(I), round(J), K) = median(median(janela)); end end end end else %% A imagem tem apenas uma matriz: % Criar tambem uma matriz temporaria com mais 4 linhas e 4 colunas

% (2 de cada lado) para o espelhamento da imagem original. img_mirrored(altura_old + 4, largura_old + 4) = 0; img_mirrored(3 : altura_old + 2, 3 : largura_old + 2) = ioriginal; img_mirrored(1,:) = img_mirrored(4,:); img_mirrored(2,:) = img_mirrored(3,:); img_mirrored(:,1) = img_mirrored(:,4); img_mirrored(:,2) = img_mirrored(:,3); img_mirrored(altura_old+4,:) = img_mirrored(altura_old+1,:); img_mirrored(altura_old+3,:) = img_mirrored(altura_old+2,:); img_mirrored(:,largura_old+4) = img_mirrored(:,largura_old+1); img_mirrored(:,largura_old+3) = img_mirrored(:,largura_old+2); switch(op) case 'mean' for I = 1:altura for J = 1:largura canto_l = floor(I/answer_factor); canto_c = floor(J/answer_factor); janela = img_mirrored(2 + canto_l - 1 : 2 + canto_l,... 2 + canto_c - 1 : 2 + canto_c); imodificada(round(I), round(J)) = mean(mean(janela)); end end case 'median' for I = 1:altura for J = 1:largura canto_l = floor(I/answer_factor); canto_c = floor(J/answer_factor); janela = img_mirrored(2 + canto_l - 1 : 2 + canto_l,... 2 + canto_c - 1 : 2 + canto_c); imodificada(round(I), round(J)) = median(median(janela)); end end end end figure, imshow(uint8(imodificada)), title(sprintf('Imagem representada a %g %% (metodo ''%s'' e operador ''%s'')', answer_factor*100, method, op));

end %--------------------------------------------------------- %B I C U B I C if isequal(method,'bicubic') % Atribuir os valores 'a nova matriz: if isequal(ioriginalinfo.ColorType,'truecolor') % A imagem tem 3 MATRIZES: for K = 1:3 % E criar tambem uma matriz temporaria com mais 6 linhas e 6 colunas (3 de cada lado) % para o espelhamento da imagem original img_mirrored(altura_old + 6, largura_old + 6, 3) = 0; img_mirrored(4 : altura_old + 3, 4 : largura_old + 3, 1) = ioriginal(:,:,1); img_mirrored(4 : altura_old + 3, 4 : largura_old + 3, 2) = ioriginal(:,:,2); img_mirrored(4 : altura_old + 3, 4 : largura_old + 3, 3) = ioriginal(:,:,3); img_mirrored(1,:,1) = img_mirrored(6,:,1); img_mirrored(2,:,1) = img_mirrored(5,:,1); img_mirrored(3,:,1) = img_mirrored(4,:,1); img_mirrored(1,:,2) = img_mirrored(6,:,2); img_mirrored(2,:,2) = img_mirrored(5,:,2); img_mirrored(3,:,2) = img_mirrored(4,:,2); img_mirrored(1,:,3) = img_mirrored(6,:,3); img_mirrored(2,:,3) = img_mirrored(5,:,3); img_mirrored(3,:,3) = img_mirrored(4,:,3); img_mirrored(:,1,1) = img_mirrored(:,6,1); img_mirrored(:,2,1) = img_mirrored(:,5,1); img_mirrored(:,3,1) = img_mirrored(:,4,1); img_mirrored(:,1,2) = img_mirrored(:,6,2); img_mirrored(:,2,2) = img_mirrored(:,5,2); img_mirrored(:,3,2) = img_mirrored(:,4,2); img_mirrored(:,1,3) = img_mirrored(:,6,3); img_mirrored(:,2,3) = img_mirrored(:,5,3); img_mirrored(:,3,3) = img_mirrored(:,4,3); img_mirrored(altura_old+6,:,1) = img_mirrored(altura_old+1,:,1); img_mirrored(altura_old+5,:,1) = img_mirrored(altura_old+2,:,1); img_mirrored(altura_old+4,:,1) = img_mirrored(altura_old+3,:,1); img_mirrored(altura_old+6,:,2) = img_mirrored(altura_old+1,:,2); img_mirrored(altura_old+5,:,2) = img_mirrored(altura_old+2,:,2); img_mirrored(altura_old+4,:,2) = img_mirrored(altura_old+3,:,2); img_mirrored(altura_old+6,:,3) = img_mirrored(altura_old+1,:,3); img_mirrored(altura_old+5,:,3) = img_mirrored(altura_old+2,:,3); img_mirrored(altura_old+4,:,3) = img_mirrored(altura_old+3,:,3); img_mirrored(:,largura_old+6,1) = img_mirrored(:,largura_old+1,1); img_mirrored(:,largura_old+5,1) = img_mirrored(:,largura_old+2,1); img_mirrored(:,largura_old+4,1) = img_mirrored(:,largura_old+3,1); img_mirrored(:,largura_old+6,2) = img_mirrored(:,largura_old+1,2); img_mirrored(:,largura_old+5,2) = img_mirrored(:,largura_old+2,2); img_mirrored(:,largura_old+4,2) = img_mirrored(:,largura_old+3,2); img_mirrored(:,largura_old+6,3) = img_mirrored(:,largura_old+1,3); img_mirrored(:,largura_old+5,3) = img_mirrored(:,largura_old+2,3); img_mirrored(:,largura_old+4,3) = img_mirrored(:,largura_old+3,3); % Atribuir os valores 'a nova matriz: switch(op) case 'mean' for I = 1:altura for J = 1:largura canto_l = floor(I/answer_factor); canto_c = floor(J/answer_factor); janela = img_mirrored(... 3 + canto_l - 1 : 3 + canto_l + 3,... 3 + canto_c - 1 : 3 + canto_c + 3,... K);

imodificada(round(I), round(J), K) = mean(mean(janela)); end end case 'median' for I = 1:altura for J = 1:largura canto_l = floor(I/answer_factor); canto_c = floor(J/answer_factor); janela = img_mirrored(... 3 + canto_l - 1 : 3 + canto_l + 3,... 3 + canto_c - 1 : 3 + canto_c + 3,... K); imodificada(round(I), round(J), K) = median(median(janela)); end end end end else % Criar tambem uma matriz temporaria com mais 6 linhas e 6 colunas (3 de cada lado) % para o espelhamento da imagem original img_mirrored(altura_old+6, largura_old+6) = 0; img_mirrored(4:altura_old+3, 4:largura_old+3) = ioriginal; img_mirrored(1,:) = img_mirrored(6,:); img_mirrored(2,:) = img_mirrored(5,:); img_mirrored(3,:) = img_mirrored(4,:); img_mirrored(:,1) = img_mirrored(:,6); img_mirrored(:,2) = img_mirrored(:,5); img_mirrored(:,3) = img_mirrored(:,4); img_mirrored(altura_old+6,:) = img_mirrored(altura_old+1,:); img_mirrored(altura_old+5,:) = img_mirrored(altura_old+2,:); img_mirrored(altura_old+4,:) = img_mirrored(altura_old+3,:); img_mirrored(:,largura_old+6) = img_mirrored(:,largura_old+1); img_mirrored(:,largura_old+5) = img_mirrored(:,largura_old+2); img_mirrored(:,largura_old+4) = img_mirrored(:,largura_old+3); % Atribuir os valores 'a nova matriz: switch(op) case 'mean' for I = 1:altura for J = 1:largura canto_l = floor(I/answer_factor); canto_c = floor(J/answer_factor); janela = img_mirrored(... 3 + canto_l - 1 : 3 + canto_l + 3,... 3 + canto_c - 1 : 3 + canto_c + 3); imodificada(round(I), round(J)) = mean(mean(janela)); end end case 'median' for I = 1:altura for J = 1:largura canto_l = floor(I/answer_factor); canto_c = floor(J/answer_factor); janela = img_mirrored(... 3 + canto_l - 1 : 3 + canto_l + 3,... 3 + canto_c - 1 : 3 + canto_c + 3); imodificada(round(I), round(J)) = median(median(janela)); end end end end figure, imshow(uint8(imodificada)), title(sprintf('Imagem representada a %g %% (metodo ''%s'' e operador ''%s'')', answer_factor*100, method, op)); end image2write=imodificada; % Parar o temporizador: p_time = toc;

% Modificar a string de Status: set(handles.Status, 'String', 'CONCLUIDO! (em:)'); set(handles.Show_Time, 'String', sprintf('%g segundos',p_time)); set(handles.save_results,'Enable','on'); % -------------------------------------------------------------------- % Logotipo Wolphin function varargout = wolphin_logo_Callback(h, eventdata, handles, varargin) %nao faz nada de especial % -------------------------------------------------------------------- % Thumbnail - imagem original function varargout = thumb_ioriginal_Callback(h, eventdata, handles, varargin) global ioriginal fig1 = figure; imshow(ioriginal), title('Imagem original no tamanho original'); set(handles.thumb_ioriginal, 'Value', 0); % -------------------------------------------------------------------- % LINK para a FEUP function varargout = logotipo_FEUP_Callback(h, eventdata, handles, varargin) web http://www.fe.up.pt/ -browser set(handles.logotipo_FEUP, 'Value', 0); % -------------------------------------------------------------------- %Abertura pelo POPUP function varargout = popupmenu1_Callback(h, eventdata, handles, varargin) global ioriginal global ioriginalinfo global img_path % Abre o ficheiro escolhido pelo utilizador atraves do popup: % Lista do POPUP pop_list = {... ' ';... 'A.tif';... 'airfield512x512.tif';... 'B.tif';... 'boats512x512.tif';... 'bridge512x512.tif';... 'C.tif';... 'camel.bmp';... 'cameraman.tif';... 'einstein.tif';... 'elaine.tif';... 'frame1.tif';... 'frame2.tif';... 'karen.bmp';... 'kid-face.bmp';... 'kids-photo.bmp';... 'lena.tif';... 'man-on-camel.bmp';... 'mars.bmp';... 'men-camel.bmp';... 'movie14.bmp';... 'movie20.bmp';... 'movie27.bmp';... 'party.bmp';... 'piston.bmp';... 'ribs.bmp';... 'smandril.tif';... 'woman.bmp';... 'xray.bmp';... 'zoneplate.tif'}; if get(handles.popupmenu1,'Value') ~= 1 img_path = sprintf('imagens\\%s', char(pop_list(get(handles.popupmenu1,'Value')))); ioriginal = imread(img_path); ioriginalinfo = imfinfo(img_path); make_it_visible(h, eventdata, handles, varargin); set(handles.Status,'String',' '); set(handles.Show_Time,'String', ' '); set(handles.novasdimensoes, 'String', ' '); set(handles.save_results,'Enable','off');

end % -------------------------------------------------------------------- % MAKE IT VISIBLE... function make_it_visible(h, eventdata, handles, varargin) global ioriginal global ioriginalinfo global img_path %faz enable `as informacoes set(handles.tag_seleccionado,'String','[ Ficheiro Seleccionado! ]'); set(handles.tag_nomeficheiro,'Enable','on'); set(handles.tag_formato,'Enable','on'); set(handles.tag_tamanho,'Enable','on'); set(handles.tag_dimensoes,'Enable','on'); set(handles.tag_bitsporpixel,'Enable','on'); set(handles.tag_tipodecor,'Enable','on'); set(handles.tag_cliquethumboriginal,'Enable','on'); set(handles.tag_factor,'Enable','on'); set(handles.insere_factor,'Enable','on'); set(handles.tag_factor,'Enable','on'); set(handles.tag_escolhametodo,'Enable','on'); set(handles.radio_nearest,'Enable','on'); set(handles.radio_bicubic,'Enable','on'); set(handles.radio_bilinear,'Enable','on'); radio_nearest_Callback(h, eventdata, handles, varargin); set(handles.expandir,'Enable','on'); set(handles.radio_nearest, 'Value',1); %recolhe informacoes nome_info=sprintf('%s',img_path); formato_info=sprintf('%s',ioriginalinfo.Format); tamanho_info=sprintf('%d',ioriginalinfo.FileSize); dimensoes_info=sprintf('%d x %d',ioriginalinfo.Width,ioriginalinfo.Height); bitsporpixel_info=sprintf('%d',ioriginalinfo.BitDepth); tipocor_info=sprintf('%s',ioriginalinfo.ColorType); %faz display das informacoes set(handles.nomeficheiro,'String',nome_info); set(handles.formato,'String',formato_info); set(handles.tamanho,'String',tamanho_info); set(handles.dimensoes,'String',dimensoes_info); set(handles.bitsporpixel,'String',bitsporpixel_info); set(handles.tipodecor,'String',tipocor_info); %abrir thumbnail - Escalar imagem para caber no quadrado thumb_measure=get(handles.thumb_ioriginal,'Position'); thumb_width=thumb_measure(3); thumb_height=thumb_measure(4); thumb_factor_original1=1/(ioriginalinfo.Width/thumb_width); thumb_factor_original2=1/(ioriginalinfo.Height/thumb_height); thumb_factor_original=min(thumb_factor_original1,thumb_factor_original2); if isequal(tipocor_info,'truecolor') set(handles.thumb_ioriginal,'Enable','on'); ioriginal_escalado = imresize(ioriginal,thumb_factor_original); set(handles.thumb_ioriginal,'Enable','on'); set(handles.thumb_ioriginal,'CDATA',ioriginal_escalado); else load MAP; ioriginalconvertido=ind2rgb(ioriginal,map); ioriginalconvertido_escalado = imresize(ioriginalconvertido,thumb_factor_original); set(handles.thumb_ioriginal,'Enable','on'); set(handles.thumb_ioriginal,'CDATA',ioriginalconvertido_escalado); end % -------------------------------------------------------------------- % BOTAO DE GUARDAR RESULTADOS function varargout = save_results_Callback(h, eventdata, handles, varargin)

global image2write global scale_factor global method global op global ioriginalinfo path_file = ioriginalinfo.Filename; [zbr_path, name_file, zbr_ext, zbr_ver]=fileparts(path_file); format_file = ioriginalinfo.Format; if isequal(method,'nearest') save_file = sprintf('resultados\\%s_%s_%s.%s',name_file,scale_factor,method,format_file); else save_file = sprintf('resultados\\%s_%s_%s_%s.%s',name_file,scale_factor,method,op,format_file); end imwrite(image2write, save_file, format_file); set(handles.save_results,'Enable','off');