Danilo R. Vieira | Oceanógrafo

Aqui estão algumas das coisas que eu aprendi, descobri ou fiz (por obrigação ou por diversão). Espero que encontre algo que seja útil para você.

MATLAB → Manipulação e análise de imagens

Criando uma interface gráfica para obter distâncias entre pontos em uma figura

Este exemplo mostra como criar uma interface gráfica para obter a distância entre pontos em uma figura. O principal neste exemplo é a interface e como trabalhar com os componentes, pois a distância entre os pontos pode ser obtida por diversas outras formas, podendo até mesmo ser automatizada.

Download dos arquivos (8.9 KB).

Conteúdo

Criando a interface

Para criar uma interface no MATLAB, basta chamar a função guide no prompt do MATLAB. Esta função trará a seguinte janela:

[GUIDE Quick Start]

Neste exemplo, podemos ficar com a opção padrão (Blank GUI) e você também pode salvar a figura (interface) com a opção Save new figure as. Quando você salvar, o MATLAB criará automaticamente um arquivo *.m correspondente à sua interface e já adiciona a este arquivo um monte coisa necessária ao bom funcionamento da interface. Este arquivo conterá o código para as ações dos botões, controles de texto, menus e demais componentes existentes na interface. Clicando em OK, temos a nova interface:

[GUIDE]

Agora você já pode colocar os componentes na interface. Basta selecionar um componente na lista à esquerda e colocá-lo na interface com um clique. Todos os componentes suportam o recurso de arrastar e soltar e também têm alças de redimensionamento, que você já deve ter visto em algum outro programa. Para alterar cores, fonte e texto dos componentes, basta clicar duas vezes sobre ele, irá aparecer o editor de propriedades, onde você pode modificar facilmente as característica dos controles e da própria interface. Para o exemplo, eu usei uma interface assim (clique para ver maior):

[Interface usada no exemplo]

Esta interface funcionará da seguinte forma: o usuário clica em “Abrir imgem” e escolhe uma figura, que será aberta no componente axes1; em seguida, ele especifica uma distância conhecida usando a caixa de texto abaixo do botão “Referência” e escolhe a unidade em que está a distância com o menu logo abaixo. Então ele clica no botão “Referência” e marca na figura onde está a distância conhecida. Depois basta escolher com quantos pontos ele quer trabalhar (na minha interface eu chamei de “Estações”), clica em “Marcar pontos” e marca os pontos na figura. Conforme ele marca os pontos as distâncias são calculadas e mostradas sobre a figura. Veja em funcionamento (note que no editor de propriedades eu coloquei a propriedade ToolBar da figura como figure para ter acesso às ferramentas de imagem durante a execução do programa) (clique para ver maior):

[Interface em funcionamento]

Para ver funcionando você pode clicar no triângulo verde do GUIDE ou apertar F5 no editor de códigos. Para chamar a interface futuramente, basta usar o nome que você deu a ela como se fosse uma função (e é isso que ela é), você pode chamá-la dentro de outros programas ou direto do promtp (ela deve estar acessível no path).

Codificando o exemplo

Para associar ações aos componententes, o MATLAB utiliza os chamados callbacks, que são apenas funções chamadas quando alguma coisa acontece. Veremos como funciona na prática: clicando com o botão direito sobre um componente, aparece um menu, neste menu há a opção View Callbacks que mostra todos os callbacks disponíveis para um componente e você ó precisa clicar em qual você quer editar e o MATLAB mostra onde digitar e, para alguns componentes, já trás algumas dicas. Veja o código que eu coloquei no callback do botão “Abrir imagem” (os comentários em inglês foram colocados automaticamente pelo MATLAB):

% --- Executes on button press in pushbutton1.
function pushbutton1_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% mostra uma tela para que o usuário escolha um arquivo de imagem:
[filename, canceled] = imgetfile;
   
% se o usuário não tiver cancelado
if ˜canceled
    % guarda o nome do arquivo
    handles.arquivo = filename;
    % abre a imagem
    handles.imagem = imread(filename);
    % seleciona o componente axes1
    axes(handles.axes1);
    % exibe a figura
    imshow(handles.imagem);
end

% reseta a referência
handles.px2min = NaN;
% salva a variável handles
guidata(hObject, handles);

Handles são números que identificam os componentes, eles ficam armazenados na variável handles. Essa variável é do tipo struct e é muito importante: é a única que está disponível para todos os callbacks, pois é salva com a função guidata. Veja que eu aproveitei ela para guardar o nome do arquivo e também a imagem.

Agora o callback do botão “Referência”:

% --- Executes on button press in pushbutton3.
function pushbutton3_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton3 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% ativa o axes1
axes(handles.axes1);
% mostra a imagem (isso reseta a imagem quando marcamos uma nova referência)
imshow(handles.imagem);

% pegamos qual a distância que o usuário que marcou
% ("edtRef" é a propriedade "Tag" da caixa de texto)
numRef = str2double(get(handles.edtRef, 'String'));

% Vê se o usuário digitou um número válido, caso contrário
% mostra uma mensagem e sai desse callback
if isnan(numRef) || (numRef <= 0)
    % mostra a mensagem
    errordlg('Por favor, digite um número válido.', 'Erro');
    % sai da função
    return;
end

% pede para o usuário marcar dois pontos
ptos = ginput(2);

% calcula a distância em pixels que o usuário marcou.
% se você estudou vetores, sabe que distância entre pontos
% pode ser obtida pela norma do vetor que tem
% início num ponto e fim no outro, então basta chamar
% a função norm com a diferença entre os pontos como
% parâmetro.
c = norm(ptos(1,:)-ptos(2,:)) / numRef;

% converte a distância em pixels para milhas náuticas, levando
% em consideração que o usuário pode ter marcado em qualquer
% unidade disponível.
% get(handles.popupmenu1, 'Value') retorna qual item o usuário escolheu
switch get(handles.popupmenu1, 'Value')
    case 1 % minuto
        fator = c;
    case 2 % segundo
        fator = c / (1/60);
    case 3 % grau
        fator = c / 60;
    case 4 % quilometro
        fator = c / (1/(1852 * 1000));
    case 5 % metro
        fator = c / (1/1852);
end

% guarda a referência
handles.px2min = fator;
guidata(hObject, handles);

Veja que continuamos usando os handles, agora para obter propriedades dos componentes usando a função get (para mudar propriedades via código, usa-se set).

Finalmente, o callback do botão “Marcar pontos”. Nesse eu vou usar a mesma técnica que autores famosos de livros técnicos usam quando têm preguiça: não vou comentar para estimular o raciocínio do leitor.

% --- Executes on button press in pushbutton2.
function pushbutton2_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton2 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

if isnan(handles.px2min)
    errordlg('Marque a referência primeiro', 'Erro');
    return;
end

numEst = str2double(get(handles.edtNumEst, 'String'));
if ~isnan(numEst) && numEst > 1
    axes(handles.axes1);
    pto = ginput(1);
    hold on;
    plot(pto(1), pto(2), 'xr');
else
    errordlg('Por favor, digite um número válido de estações.', 'Erro');
    return;
end

for j=2:numEst
   last = pto;
   pto = ginput(1);
   plot(pto(1), pto(2), 'xr');
   line([last(1) pto(1)], [last(2) pto(2)]);
   d = ( norm(last-pto) / handles.px2min ) * 1852;
   text(pto(1)+(last(1)-pto(1))/2, pto(2)+(last(2)-pto(2))/2, ...
      sprintf('%.2fm', d), 'backgroundcolor', 'y');
end
hold off;

Transformando num executável

Se você quiser transformar uma interface gráfica em um programa de verdade (que pode ser executado em outros computadores, mesmo sem o MATLAB) você pode usar o MATLAB Compiler, digitando o seguinte no prompt do MATLAB (interface.m é o nome do arquivo M, não é necessário especificar o arquivo FIG correspondente):

mcc -m interface.m

A opção -m diz que queremos um programa standalone, ou seja, que funcione sozinho, independente do MATLAB. Na verdade, ele não será totalmente independente, ele requerirá a instalação do MCR (MATLAB Compiler Runtime), mas você poderá distribuir seu programa e o MCR livremente e dentro da lei, pois o pessoal da MathWorks deixa você distribuir o MCR para qualquer um (apenas o MCR). Consulte a documentação para saber mais.

Em Windows, será criado o arquivo interface.exe na mesma pasta na qual está o arquivo M, em Linux será criado o arquivo binário interface, também na mesma pasta do arquivo M.