martes, 9 de agosto de 2016

Rotar matrices en MATLAB


La rotación de matrices consiste en redefinir la posición de sus elementos mediante una modificación que no afecta el valor de sus elementos. Para comenzar, suponga que se tiene un vector v definido como sigue:

v = [v1, v2, v3, ⋯, vn − 1, vn]

Y sea vea v' el vector cuyas componentes son las mismas que v pero dispuestas en un orden inverso, es decir:

v′=[vn, vn − 1, ⋯, v3, v2, v1]

En MATLAB invertir el orden de los elementos de un vector resulta una tarea muy sencilla, esto puede lograrse indexando los elementos de la forma que a continuación se muestra:

>> v=[-2 5 8 7 3 0] % Vector original
v =
    -2     5     8     7     3     0
>> vp=v(end:-1:1) % Vector con elementos invertidos
vp =
     0     3     7     8     5    -2

La anterior es una forma muy simple de realizar dicha tarea, pero si usted prefiere el uso de funciones existe para tal fin la función fliplr cuya tarea es exactamente esa, extendiéndose su uso también a matrices, véase el ejemplo utilizando el mismo vector definido anteriormente:

>> vp=fliplr(v)
vp =
     0     3     7     8     5    -2

La función fliplr rota una matriz en un eje vertical, de tal modo que las columnas situadas a la izquierda queden en la parte derecha. Véase el ejemplo a continuación:

>> A=randi(10,3)
A =
     4     5     3
     2     2     4
     5     6     6
>> Ar=fliplr(A)
Ar =
     3     5     4
     4     2     2
     6     6     5

Está claro que fliplr ejecuta una rotación basada en las columnas, pero MATLAB dispone también de la función flipud que ejerce una rotación en un eje horizontal o basada en las filas, enseguida se muestra un ejemplo:

>> A=randi(10,4)
A =
     5     6     8     2
     9     4     5     3
     8     2     1     5
    10     7     3     6
>> Ar=flipud(A)
Ar =
    10     7     3     6
     8     2     1     5
     9     4     5     3
     5     6     8     2

Además de las anteriores MATLAB proporciona la función rot90 que permite girar la matriz en un ángulo múltiplo de 90° en el sentido contrario a las manecillas del reloj, de manera informal es como si la matriz rodase en dirección izquierda. Los argumentos de entrada de la función son primeramente la matriz a rotar y como segundo argumento un escalar entero que indica el múltiplo de 90° con el cual habrá de ejecutarse la rotación, si no se introduce un segundo argumento se asume que este será unitario. Véanse los ejemplos a continuación:

>> A=randi(20,3)
A =
    14     8    10
     1    19     9
    13     1    10
>> A90=rot90(A)  % Matriz rotada 90°
A90 =
    10     9    10
     8    19     1
    14     1    13
>> A180=rot90(A,2)  % Matriz  rotada en 180°
A180 =
    10     1    13
     9    19     1
    10     8    14
>> A270=rot90(A,3)   % Matriz rotada 270°

A270 =

    13     1    14
     1    19     8
    10     9    10

Resolver ecuaciones e inecuaciones algebraicas


Una ecuación es una igualdad matemática entre dos expresiones algebraicas en las que aparecen valores conocidos y una variable desconocida (incógnita), relacionados mediante operaciones matemáticas básicas, ejemplos de ecuaciones se muestran a continuación:

$$ 3x^2 + 2x - 2 = 0 $$

$$ x+\frac{3}{7}=2 $$

$$ \cos(x)+sin(\frac{\pi}{2})=0 $$

Las ecuaciones algebraicas sirven para modelar situaciones poco complejas pero que requieren el uso de la herramienta matemática para obtener una solución satisfactoria. Existen diversos métodos para resolver ecuaciones, los cuales se aplican dependiendo del tipo de ecuación, incluso hay fórmulas establecidas para algunos tipos de ecuaciones que minimizan el esfuerzo de cálculo.

MATLAB dispone de la función solve perteneciente al Symbolic Math Toolbox, la cual permite resolver ecuaciones, inecuaciones y sistemas de ecuaciones; la sintaxis general de la función solve es:

solve(ec, var);

Donde ec es una ecuación algebraica definida usando variables simbólicas y var es la incógnita respecto a la cual se resuelve la ecuación dada.

A manera de ejemplo se resolverá la siguiente ecuación lineal

$$ x+3=2 $$


>> x=sym('x');
>> solve(x+3==2,x)
ans =
-1

Es importante hacer mención que para especificar una igualdad se utilizan dos signos, dado que un sólo signo hace referencia a una asignación.

Si no se especifica el segundo miembro de la igualdad, MATLAB asumirá que la expresión estará igualada a cero, es decir, para resolver la ecuación:

$$ x^2 - 2x - 1 = 0 $$

Puede hacerlo de las diversas formas que enseguida se muestran:

>> solve(x^2-2*x-1==0,x)
ans =
 2^(1/2) + 1
 1 - 2^(1/2)
>> solve(x^2-2*x-1,x)
ans =
 2^(1/2) + 1
 1 - 2^(1/2)
>> solve(x^2-2*x-1)
ans =
 2^(1/2) + 1
 1 - 2^(1/2)

Para resolver desigualdades o inecuaciones la sintaxis es prácticamente la misma, claro, sólo hay que utilizar los operadores relacionales mayor que o menor que en lugar del signo de igualdad. Por ejemplo, resolviendo la siguiente desigualdad

$$  x+2>10 $$

>> solve(x+2>10,x)
ans =
Dom::Interval(8, Inf)

MATLAB devuelve el intervalo solución para la inecuación, en este caso $ (8,\infty) $. Para el caso de un intervalo cerrado MATLAB devuelve entre corchetes el valor del límite correspondiente, por ejemplo:

>> solve(x+2>=10,x)
ans =
Dom::Interval([8], Inf)

Un sistema de ecuaciones se compone de dos o más ecuaciones y un número equivalente de valores desconocidos, es posible resolver sistemas de ecuaciones utilizando también la función solve con la sintaxis siguiente:

solve(ec1,ec2,ec3,…)

Un ejemplo, resolver el siguiente sistema de ecuaciones:

x + y = 4

x − y = 3

>> syms x y
>> sol=solve(x+y==4,x-y==3)
sol = 
    x: [1x1 sym]
    y: [1x1 sym]

Para visualizar los resultados puede acceder a los campos de cada variable como se muestra enseguida:

>> sol.x 
ans =
7/2
>> sol.y
ans =
1/2

jueves, 4 de agosto de 2016

Convertir una imagen a escala de grises


La manera rápida


Si cuenta con el Image Processing Toolbox MATLAB dispone de una función llamada rgb2gray que permite convertir una imagen RGB a una en escala de grises, ej:

X = imread('lenna.png');
XG = rgb2gray(X);
imshow(XG);

Imagen original

Imagen en escala de grises

Como puede notar es muy simple, sólo necesita pasar como argumento la matriz que contiene la información de la imagen RGB.

La otra, un poco de algoritmos...


Si no dispone del toolbox de procesamiento de imagen, entonces puede implementar su propio algoritmo para realizar dicha tarea.

El algoritmo más simple es el del promedio (average method), que consiste en calcular el promedio de los canales RGB y asignarlos al pixel correspondiente en la imagen de grises. Por ejemplo dada una matriz de MxNx3 correspondiente a una imagen, el pixel de la matriz de grises en la posición (i, j) se calcula como sigue:

$$ XG_{i,j} = \frac{X_{i,j,1} + X_{i,j,2} + X_{i,j,3}}{3} $$

Donde XG es la matriz de grises, de dimensiones MxN. Y Xi, j, 1Xi, j, 2 y Xi, j, 3 las componentes correspondientes a los canales R, G y B, respectivamente.

Implementando esto en MATLAB:

X = imread('lenna.png');
XG = uint8(mean(X,3));
imshow(XG);

¿Bastante simple verdad?, lo que hacemos es hacer el promedio en la dimensión 3, es decir, para cada pixel. La conversión a entero de 8-bits (uint8) es necesaria para que se muestre correctamente cuando utilizamos imshow, dado que la función mean devuelve una matriz de tipo double.

Otro método para convertir a escala de grises es el de la luminosidad (luminosity method) que consiste en asignar una proporción específica (ponderada) a cada uno de los canales, dependiendo la aportación de estos. De hecho MATLAB utiliza este tipo de transformación en la función rgb2gray. Con este método, la expresión para calcular el valor de un pixel de grises viene dado por:

XGi, j = 0.2889 Xi, j, 1 + 0.5870 Xi, j, 2 + 0.1140 Xi, j, 3

LLevando esto a un código MATLAB:

X = imread('img/lenna.png');
k = [0.2989 0.5870 0.1140];
XG = X(:,:,1)*k(1) + X(:,:,2)*k(2) + X(:,:,3)*k(3);
imshow(XG)

martes, 10 de mayo de 2016

Detección de bordes en imágenes con MATLAB


La detección de bordes en MATLAB es una de las operaciones de procesamiento de imágenes más común y básica, cuyo objetivo es determinar las regiones en una imagen que presentan cambios significativos de intensidad en los pixeles que la conforman.

Recuerde que una imagen en escala de grises puede expresarse como una función bivariable f(x, y), donde x e y son las coordenadas de ubicación (fila, columna). Así una forma sencilla de detectar los bordes en una imagen es utilizar el gradiente, mismo que determina la tasa de variación en ambas direcciones de una función bivariable, dado por:

$$ \nabla f = \begin{bmatrix} \frac{\partial f}{\partial x} \\ \frac{\partial f}{\partial y} \end{bmatrix} $$

Aunque claro, para nuestros propósitos lo que usaremos es la magnitud del gradiente:

$$ |\nabla f| = \sqrt{ \left(\frac{\partial f}{\partial x}\right)^2 + \left(\frac{\partial f}{\partial y}\right)^2} $$

Así, para determinar los bordes en una imagen, o lo que sería lo mismo: localizar las regiones en donde la magnitud del gradiente es mayor, podemos utilizar la función gradient, vea el siguiente ejemplo:

X = imread('Lenna.png');
XG = rgb2gray(X);
[dx,dy] = gradient(double(XG));
M = uint8(sqrt(dx.^2+dy.^2));
imshow(M);



MATLAB cuenta con una función especial para detectar bordes en una imagen: edge, la cual utiliza operadores matriciales especiales que transforman una imagen en escala de grises en una imagen binarizada con bordes resaltados.

X = imread('Lenna.png');
XG = rgb2gray(X);
XB = edge(XG,'sobel');
imshow(XB);


lunes, 4 de enero de 2016

Ordenar matrices en MATLAB


El ordenamiento de datos es una tarea muy común dentro del mundo de la informática y en la programación científica. Se ordenan datos para realizar análisis cualitativos, para la visualización gráfica o cualquier otro procedimiento que requiera datos organizados. Los datos se pueden organizar por criterios diversos, pero en esta sección veremos simplemente como ordenarlos de acuerdo a su valor numérico, en orden ascendente o descendente.

Generalmente los algoritmos de ordenamiento forman parte de los cursos básicos de programación y algorítmica, dada su importancia mencionada con anterioridad. Se estudian por lo general métodos tradicionales como: el método de ordenamiento por selección, ordenamiento por inserción y ordenamiento por combinación.

Ahora, enseguida sólo veremos cómo implementar el método de ordenamiento por selección, puesto que resulta muy didáctico y fácil de programar, y como no estamos en disposición de reinventar la rueda,  entonces, para el ordenamiento de las matrices y/o vectores utilizaremos la función sort incluida en el núcleo de MATLAB, y el resto de métodos de ordenamiento tradicionales se propondrán como ejercicios al final de este capítulo.

Así pues, puede revisar el siguiente código:

X=input('Inserte un vector: ');
for i=1:length(X)
   [menor,k]=min(X(i:end));
   X((i-1)+k)=X(i);
   X(i)=menor;
end
disp(X); % Vector ordenado

El programa anterior tiene como punto de entrada un vector introducido por el usuario de forma interactiva y que puede contener valores numéricos cualesquiera. Una vez se ha introducido el vector, se utiliza un bucle for cuyo recorrido está determinado por la longitud del vector, y en cada iteración se busca el elemento de menor valor ubicado en el sub-arreglo $X(i,i+1,...,n-1,n)$ donde i es el i-ésimo elemento dado por el número de iteración actual, y n el último elemento del arreglo, la función min de MATLAB devuelve dos resultados: el valor y la posición del mínimo encontrado, con ello se procede a intercambiar el valor mínimo encontrado con aquel ubicado en la i-ésima posición del arreglo. Y así, cuando se hayan ejecutado tantas iteraciones como elementos tenga el vector, se habrán ordenado en forma ascendente dichos valores. Si por el contrario necesita ordenar un vector en forma descendente, simplemente habrá de sustituir la función min por max, es decir, buscar un valor máximo en lugar del mínimo en cada iteración, o bien, reutilizar el mismo algoritmo y audazmente rotar el vector resultante mediante la función fliplr.

Como se mencionó, en MATLAB todo lo anterior puede reemplazarse utilizando la función sort.
cuya sintaxis más general es:

>> sort(X, dim, mod);

Donde X es la matriz o vector a ordenar, dim es un escalar que puede ser 1 (columnas) o 2 (filas) y que representa la dimensión de referencia sobre la cual se ordenará, y mod es el modo de ordenamiento, que puede ser 'ascend' (menor a mayor) o 'descend' (mayor a menor), por defecto las matrices o vectores se ordenan en forma ascendente. 

Véanse los ejemplos siguientes:

>> X=[10 2 8 17 20 1 4 8 9];
>> sort(X)
ans =
    1     2     4     8     8     9    10    17    20
>> M=randi(10,5)
M =
    3    10     3     2     8
    8     7     2    10     6
    9     4     9     5     5
    1    10     8     3    10
    4     8     4     5     6
>> sort(M,1) % Ordenada por columnas
ans =
    1     4     2     2     5
    3     7     3     3     6
    4     8     4     5     6
    8    10     8     5     8
    9    10     9    10    10
>> sort(M,2) % Ordenada por filas
ans =
    2     3     3     8    10
    2     6     7     8    10
    4     5     5     9     9
    1     3     8    10    10
    4     4     5     6     8

sábado, 19 de diciembre de 2015

Exportar datos de una uitable MATLAB a una tabla en archivo HTML: table2html.


La función table2html que se anexa a continuación permite exportar los datos contenidos en una uitable MATLAB a una tabla contenida en un archivo HTML. La utilidad puede ser en aquellos casos donde se requiera elaborar reportes con datos de salida contenidos en una uitable, evidentemente la opción "Publish" de MATLAB permite elaborar un reporte de cualquier script, pero incluye solamente capturas de los objetos gráficos. Esta función se puede adaptar para que en lugar de devolver un archivo HTML completo, solamente devuelva el código HTML de la tabla e incrustar esto posteriormente en un reporte HTML creado de manera independiente.

function table2html(hTab,filename,opts)
% TABLE2HTML(hTab,filename)
%
%   hTab       - Handle de la uitable a "exportar"
%   filename   - Nombre del archivo de salida (*.html)
%   opts       - Estructura de opciones adicionales (Veáse Opciones)
%
% Exporta una uitable como tabla en un archivo en formato HTML
%
% EJEMPLO:
%
%       f = figure();
%       hTab = uitable(f,'Data',rand(10));
%       table2html(hTab,'miejemplo.html');
%
%
% OPCIONES (OPTS)
%    
%      PageTitle   -  Título de la página web
%      TableTitle  -  Título de la tabla
%      BgColor     -  Color de fondo de la tabla
%      FontName    -  Tipo de fuente utilizada
%      BorderWidth -  Ancho del borde de la tabla
%     
% EJEMPLO CON OPCIONES:
%
%       f = figure();
%       opts.PageTitle = 'Ejemplo';
%       opts.TableTitle = 'Mi tabla';
%       opts.BgColor = '#00FF00';
%       opts.FontName = 'Arial';
%       opts.BorderWidth = '3';
%       hTab = uitable(f,'Data',rand(10));
%       table2html(hTab,'miejemplo.html',opts);
%             
%
%    -------------------------------
%       Ver. 0.0.1  ||  25/10/2014
%           Jorge De Los Santos
%        delossantosmfq@gmail.com
%        http://labdls.blogspot.mx
%              MIT License
%    -------------------------------

if nargin < 1
    % En caso de no especificarse argumentos se "busca" un elemento del
    % tipo uitable y se asigna como archivo de salida a html/utitled.html
    hTab = findobj('type','uitable');
    if ~isempty(hTab)
        filename = 'html/untitled.html';
    else
        error('No existe elemento uitable disponible');
    end
end

if ~strcmp(get(hTab,'type'),'uitable')
    % Verificando que la referencia sea tipo "uitable"
    error('La referencia debe ser de tipo uitable');
end

% ========================== OPCIONES ===================================
fields_opts = {'PageTitle',   'Sin título',;
               'TableTitle',  '<b>Tabla 1</b>';
               'BgColor',     '#F0F0F0';
               'FontName',    'DejaVu Sans Mono';
               'BorderWidth', '2';
               'FontColor',   '#0000F0'};
if nargin == 3 && isstruct(opts)
    for k = 1:size(fields_opts,1)
        if ~isfield(opts,fields_opts{k,1})
            opts = setfield(opts,fields_opts{k,1},fields_opts{k,2});
        end
    end
else
    opts = cell2struct(fields_opts(:,2),fields_opts(:,1),1);
end

% ======================= PROPIEDADES DE LA TABLA ======================

X = get(hTab,'Data');
colnames = get(hTab,'ColumnName');
[nrows, ncols] = size(X);

% ========================= PLANTILLAS ================================

COL_TEMP = '<TD>_col_</TD>';
ROW_TEMP = '<TR>_row_</TR>';
HEADER_TEMP = '<TH bgcolor=#DCDCFF>_header_</TH>';

HTML_TEMP = ['<html><head><title>_pagetitle_</title></head><body><font face="_fontname_">',...
    '<table border=_borderwidth_ bordercolor=#000000 cellspacing=5 cellpadding=5 bgcolor=_bgcolor_>',...
    ' <caption>_tabletitle_</caption> _table_ </table></font> _footnote_ </body></html>'];

FOOT_TEMP = ['<br><br><br><font face="Arial Narrow" color=#C0C0C0 size=2>',...
    'Published by: <cite>table2html</cite></font>'];

% ========================== ENCABEZADOS  =============================
if strcmp(colnames,'numbered')
    colnames = repmat('untitled|',1,ncols);
    remain = colnames;
    colnames = {};
    while 1
        [str,remain]=strtok(remain,'|');
        if isempty(str),break,end;
        colnames=[colnames str];
    end
end
rstr = WriteHeaders(colnames);
WriteTable(rstr);
web(filename,'-browser');

% =====================================================
    function rstr = WriteHeaders(headers)
        rstr = '';
        for k = 1:ncols
            rstr=[rstr,strrep(HEADER_TEMP,'_header_',headers{k})];
        end
    end

    function WriteTable(rstr)
        [path_,~,~] = fileparts(filename);
        if ~isempty(path_)
            if ~isdir(path_)
                mkdir(path_);
            end
        end
       
        fid=fopen(filename,'w');
        for i=1:nrows
            cstr='';
            for j=1:ncols
                if isa(X,'cell')
                    cstr = [cstr,strrep(COL_TEMP,'_col_',num2str(X{i,j})),' '];
                else
                    cstr = [cstr,strrep(COL_TEMP,'_col_',num2str(X(i,j))),' '];
                end
            end
            rstr = [rstr,strrep(ROW_TEMP,'_row_',cstr)];
        end
        WEB_PAGE = strrep(HTML_TEMP,'_table_',rstr);
        WEB_PAGE = regexprep(WEB_PAGE,{'_footnote_','_bgcolor_',...
            '_fontname_','_borderwidth_','_tabletitle_','_pagetitle_','_fontcolor_'},...
            {FOOT_TEMP,opts.BgColor,opts.FontName,opts.BorderWidth,...
            opts.TableTitle,opts.PageTitle,opts.FontColor});
        fprintf(fid,'%s',WEB_PAGE);
        fclose(fid);
    end

end

Para una referencia más completa con algunos ejemplos/test de la función table2html puede revisar el siguiente enlace:

table2html (GitHub)

miércoles, 3 de diciembre de 2014

Intercambiar filas y columnas de una matriz en MATLAB


El hecho de intercambiar filas y columnas de una matriz suele ser un tema muy importante en álgebra lineal. Aquí vamos a explicar con ejemplos cómo lograr esto mediante la indexación de matrices utilizando el operador dos puntos.

Para ejemplificar vamos a utilizar la matriz A, definida por:

$$A=\begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6  \\ 7 & 8 & 9 \end{bmatrix}$$

Creando la matriz en MATLAB:

>> A=[1,2,3;4,5,6;7,8,9]
A =
     1     2     3
     4     5     6
     7     8     9

Intercambiar filas

Suponga que se pide intercambiar las filas 1 y 2, entonces se procedería como sigue:

>> A([1 2],:)=A([2 1],:)
A =
     4     5     6
     1     2     3
     7     8     9

Básicamente le estamos "diciendo" a MATLAB que de la matriz A sustituya todas las columnas de las filas 1 y 2 por las filas 2 y 1, es decir, "invirtiendo" el orden.


Intercambiar columnas

La lógica usada es prácticamente la misma que en el caso anterior, con la única diferencia que el operador dos puntos lo utilizaremos en el índice de las filas. Por ejemplo, de la matriz A original vamos a intercambiar las filas 2 y 3:

>> A(:,[2 3])=A(:,[3 2])
A =
     1     3     2
     4     6     5
     7     9     8


Definiendo funciones propias

Finalmente, si lo anterior le parece un poco confuso, puede utilizar las siguientes funciones: swaprows y swapcols, que intercambian filas y columnas respectivamente:

function X = swaprows(A,m1,m2)
X = A;
X(m1,:) = A(m2,:);
X(m2,:) = A(m1,:);
end

function X = swapcols(A,n1,n2)
X = A;
X(:,n1) = A(:,n2);
X(:,n2) = A(:,n1);
end

La sintaxis para ambas es similar, simplemente necesita pasar como argumento la matriz y las filas y/o columnas a intercambiar de posición. Desde luego las funciones anteriores no están incluidas en MATLAB por defecto, por lo que habrá de colocarlas a su directorio de trabajo o bien añadirlas al PATH de MATLAB.