function varargout = GUIDE_SC(varargin)
% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
    'gui_Singleton',  gui_Singleton, ...
    'gui_OpeningFcn', @GUIDE_SC_OpeningFcn, ...
    'gui_OutputFcn',  @GUIDE_SC_OutputFcn, ...
    'gui_LayoutFcn',  [] , ...
    'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT
% ______________________________________________________________________
% --- CONDICIONES INICIALES DEL PROGRAMA
function GUIDE_SC_OpeningFcn(hObject, eventdata, handles, varargin)
% Mover la GU al centro
movegui(hObject,'center');
% String vacío para la ruta del video. Una vez que se elije el video a leer
% este manejado (handles) se sobreescribe con la ruta del video (Ej: C:\VIDEO\test.avi)
handles.ruta=' ';
% Deshabilitar los botones de "Trazar ruta" y "Guardar" hasta que haya
% información disponible.
set(handles.trazar_ruta,'Enable','off');
set(handles.guardar,'Enable','off');
% ______________________________________________________________________
% Choose default command line output for GUIDE_SC
handles.output = hObject;
% Update handles structure
guidata(hObject, handles);
% --- Outputs from this function are returned to the command line.
function varargout = GUIDE_SC_OutputFcn(hObject, eventdata, handles)
varargout{1} = handles.output;
% ______________________________________________________________________
% ______________________________________________________________________
% BOTÓN QUE SELECCIONA LA IMAGEN DONDE DE ESCOGERÁ EL COLOR A BUSCAR
function selec_fondo_Callback(hObject, eventdata, handles)
% Deshabilitar el botón durante el proceso
set(hObject,'Enable','off');
% Verificar la fuente de la imagen, si es la webcam o el video avi
sel_fuente=get(handles.video_f,'Value');
switch sel_fuente
    % -----------------------------------------------------------------
    case 1 %WEB CAM
        % Iniciar entrada de video
        vid = videoinput('winvideo', 1);        
        % Intervalo de captuta de trama de la cadena de video
        vid.FrameGrabInterval = 1;
        set(vid,'TriggerRepeat',Inf);        
        % Iniciar captura
        % _______Obtener el fondo_________
        disp('Obteniendo imagen de fondo')
        % Capturar 50 imágenes
        vid.FramesPerTrigger=50;
        % Iniciar la captura
        start(vid);
        % Obtener las 50 imágenes
        data = getdata(vid,50);
        % Obtener la imagen número 50
        fondo=double(data(:,:,:,50));
        % Presentar la imagen
        imshow(uint8(fondo))
        % Detener el objeto de video
        stop(vid);
        % Borrar el objeto de video
        clear vid        
    case 2%VIDEO AVI
        [nombre ruta]=uigetfile('*.avi','Seleccionar video');
        % Si se presiona CANCELAR, retorna.
        if nombre == 0, return, end        
        % Leer la secuencia de video AVI
        avi=aviread(fullfile(ruta,nombre));
        % Obtener las imágenes del video
        video = {avi.cdata};
        % Tomar la imagen número 10 (Este valor es empírico)
        fondo=video{10};
        % Almacenar la ruta y el nombre del archivo
        handles.ruta_s=fullfile(ruta,nombre);
        % Mostrar la imagen
        imshow(fondo)
end
% Usar IMPIXEL para tomar el valor RGB de la imagen con click derecho.
colors=impixel(uint8(fondo));
% Retorna si no hay color selccionado
if isempty(colors)
    return
end
% Establecer la matriz RGB en los edit text.
set(handles.rojos,'String',colors(1));
set(handles.verdes,'String',colors(2));
set(handles.azules,'String',colors(3));
% Actualizar los valores de la GUI.
guidata(hObject,handles)
% Habilitar nuevamente el botón
set(hObject,'Enable','on');
% ______________________________________________________________________
% ______________________________________________________________________
% --- FUNCIÓN DEL BOTÓN "INICIAR"
function inicio_Callback(hObject, eventdata, handles)
% Habilitar los botones de "Trazar ruta" y "Guardar"
set(handles.trazar_ruta,'Enable','off');
set(handles.guardar,'Enable','off');
% Establecer el dato de usuario del botón PARAR en 0. Este botón PARAR
% detiene la búsqueda de color 
set(handles.parar_b,'UserData',0);
% Obtener el umbral de comparción de color
umbral=str2double(get(handles.umbral,'String'));
% Verificar que el valor del umbral es correcto, caso contrario mostrar un
% mensaje de error y detener el programa
if umbral<0 || isempty(umbral) || isnan(umbral)
    errordlg('El umbral debe ser positivo y entero','Error de umbral')
    return
end
% Obtener la matriz RGB de los edit-text
R=str2double(get(handles.rojos,'String'));
G=str2double(get(handles.verdes,'String'));
B=str2double(get(handles.azules,'String'));
% Verificar cual es la entrada de video (Webcam o Video AVI)
sel_fuente=get(handles.video_f,'Value'); 
% Matriz vacía que va a almacenar las coordenadas del objeto en movimiento.
centros=[ ];
% El código que viene ejecuta la búsqueda en la imágenes que provienes o
% bien de la webcam o bien del video AVI.
switch sel_fuente
    % -----------------------------------------------------------------
    case 1 %WEB CAM seleccionada como fuente de video
        % Iniciar entrada de video
        vid = videoinput('winvideo', 1);
        % Repeticiones de captura infinita
        set(vid,'TriggerRepeat',Inf);
        % Intervalo de captuta de trama de la cadena de video
        vid.FrameGrabInterval = 1;
        % Iniciar captura        
        start(vid);
        % Indicar el axes en donde se graficará la imagen con la ruta
        axes(handles.axes1)
        try
            while 1 % Ciclo inf hasta presionar botón PARAR
                if get(handles.parar_b,'UserData')==1
                    break % Sentencia que termina con el ciclo WHILE
                end
                % Extraer datos de la web cam "getdata(vid,muestra)"
                I = getdata(vid,1);
                % Transformar imagen a formato de doble precisión númerica
                I=double(I);                
                % Cálculo de la referenica
                diferencia=(abs(I(:,:,1)-R)<umbral)&(abs(I(:,:,2)-G)<umbral)&(abs(I(:,:,3)-B)<umbral);
                % Remover ruido (eliminar pequeños hoyos y rellena aberturas)
                % 4 SIGNIFICA 4 objetos conectados
                a = bwlabel(diferencia,4);
                % Realiza cierre morfológico (dilación seguida por la erosión)
                b = bwmorph(a,'close');
                % bwmorph: realiza operaciones morfológicas en imágenes binarias
                % open->Realiza apertura morfológica (erosión seguida por la dilación)
                diferencia = bwmorph(b,'open');
                % Transformar la imagen a UINT8 para mostrarla con la
                % función IMSHOW
                imagen=uint8(I);                
                image(imagen)
                % Etiquetar cada objeto encontrado
                etiqueta = bwlabel(diferencia,4);
                % Determinar propiedades de los objetos encontrados como:
                % 'Area', 'Centroid', y 'caja'
                objeto = regionprops(etiqueta);
                % Contar el número de objetos encontrados
                N = size(objeto,1);
                if N < 1 || isempty(objeto) % Retorna si no hay ningún objeto en la imagen
                    continue % Inicia el siguiente ciclo while.
                end
                % Eliminar los objetos con área menos a 200 (eliminar ruido)
                s=find([objeto.Area]<200);
                if ~isempty(s)
                    objeto(s)=[ ];
                end
                % Contar nuevamente el número de objetos encontrados
                N=size(objeto,1);
                if N < 1 || isempty(objeto) % Retorna si no hay ningún objeto en la imagen
                    continue
                end
                % Seleccionar solo el objeto más grande
                [area_maxi pam]=max([objeto.Area]);
                %for n=1:N
                    hold on %Mantener la imagen y el rectángulo de seguimiento
                    % Obtener el centro
                    centroid = objeto(pam).Centroid;                    
                    C_X = round(centroid(1)); % Coordenada X
                    C_Y = round(centroid(2)); % Coordenada Y
                    % Escribir la posición en el static-text de título del axes                  
                    set(handles.coordenadas,'String',['X= ',num2str(C_X),' ','Y= ',num2str(C_Y)])
                    % Almacenar la coordenada ("centros" es la ruta del objeto)
                    centros=[centros; C_X C_Y];
                    % Dibujar el rectángulo de seguimiento
                    rectangle('Position',objeto(pam).BoundingBox,'EdgeColor','g','LineWidth',2)
                    % Dibujar la ruta de seguimiento
                    plot(C_X,C_Y,'Color','g','Marker','+','LineWidth',2)
                    plot(centros(1:5:end,1),centros(1:5:end,2));
                    hold off
                %end
                drawnow % Actualización de la imagen a presentar
            end
            %Parar adquisicón de video al terminar el ciclo While
            stop(vid);
        catch %Funciones que se ejecutan en caso de suceder un error en la adquisición
            stop(vid);   %Parar la adquisición de imágenes
            delete vid  % Borrar el objeto de video  (ver imaqtool)
            clear vid    % Borrar el objeto de video del workspace
            errordlg('Sucedió un ERROR','Aviso') % Mostrar aviso de error
        end
        % -----------------------------------------------------------------   
    case 2 %VIDEO AVI seleccionado como fuente de video
        % Leer la ruta del video
        ruta=handles.ruta_s; 
        % Si la "ruta" es un string vacío, muestra un mensaje y retorna
        if strcmp(ruta,' ')
            msgbox('Seleccione un color a buscar del video AVI','MENSAJE')
            return
        end
        % Matriz vacía que almacena las coordenadas de recorrido del objeto
        centros=[ ];
        % Leer el video AVI
        avi=aviread(ruta);
        % Tomar las imágenes del video
        video = {avi.cdata};
        % El ciclo FOR procesará la totalidad de la imágenes del video
        for cnt = 1:length(video)
            % Si se presiona el botón PARAR, rompe el lazo FOR
            if get(handles.parar_b,'UserData')==1
                break
            end
            % Presentar la imagen adquirida del video
            imagesc(video{cnt});
            % Desactivar la etiquetación de los ejes
            axis image off
            % Actualización de la imagen a presentar
            drawnow; 
            % Convertir la imagen a double para operar.
            I=double(video{cnt});
            % Cálculo de la referenica
            diferencia=(abs(I(:,:,1)-R)<umbral)&(abs(I(:,:,2)-G)<umbral)&(abs(I(:,:,3)-B)<umbral);
            % Remover ruido (eliminar pequeños hoyos y rellena aberturas)
            % 4 SIGNIFICA 4 objetos conectados
            a = bwlabel(diferencia,4);
            % Realiza cierre morfológico (dilación seguida por la erosión)
            b = bwmorph(a,'close');
            % bwmorph REALIZA OPERACIONES MORFOLÓGICAS EN IMÁGENES BINARIAS
            % open->Realiza apertura morfológica (erosión seguida por la dilación)
            diferencia = bwmorph(b,'open');            
            % Etiquetar objetos encontrados
            etiqueta = bwlabel(diferencia,4);
            % Determinar propiedades de los objetos encontrados como:
            % 'Area', 'Centroid', y 'caja'
            objeto = regionprops(etiqueta);%'Area', 'Centroid', y 'caja'
            % Contar el número de objetos encontrados
            N = size(objeto,1);            
            if N < 1 || isempty(objeto) % Retorna si no hay ningún objeto en la imagen
                continue
            end
            % Eliminar los objetos con área menos a 200 (eliminar ruido)
            s=find([objeto.Area]<200);
            if ~isempty(s)
                objeto(s)=[ ];
            end
            % Contar el número de objetos encontrados
            N=size(objeto,1);
            if N < 1 || isempty(objeto) % Retorna si no hay ningún objeto en la imagen
                continue
            end
            % Seleccionar solo el objeto más grande
            [area_maxi pam]=max([objeto.Area]);
%             for n=1:N
                hold on %Mantener la imagen y el rectángulo de seguimiento
                % Obtener el centro
                centroid = objeto(pam).Centroid;
                C_X = round(centroid(1)); % Coordenada X
                C_Y = round(centroid(2)); % Coordenada Y
                % Escribir la posición en el static-text de título del axes                
                set(handles.coordenadas,'String',['X= ',num2str(C_X),' ','Y= ',num2str(C_Y)])
                % Almacenar la coordenada ("centros" es la ruta del objeto)
                centros=[centros; C_X C_Y];
                % Dibujar el rectángulo de seguimiento
                rectangle('Position',objeto(pam).BoundingBox,'EdgeColor','g','LineWidth',2)
                % Dibujar la ruta de seguimiento
                plot(C_X,C_Y,'Color','g','Marker','+','LineWidth',2)
                plot(centros(1:5:end,1),centros(1:5:end,2));
                hold off
%             end
            % Actualización de la imagen a presentar
            drawnow
        end
        disp('SALIO')
end
% Almacenar la ruta del objeto
handles.ruta=centros;
guidata(hObject, handles) %Actualizar datos de la GUI
% Habilitar botones "Trazar ruta" y "Guardar"
set(handles.trazar_ruta,'Enable','on');
set(handles.guardar,'Enable','on');
% ______________________________________________________________________
% ______________________________________________________________________
% --- TRAZAR LA RUTA
function trazar_ruta_Callback(hObject, eventdata, handles)
% Mostrar una nueva figura
figure(1)
% Llamar los datos de la ruta
ruta=handles.ruta;
% Plotear la ruta
plot(ruta(1:5:end,1),ruta(1:5:end,2))
title('Ruta del objeto')
axis ij
% ______________________________________________________________________
% ______________________________________________________________________
% --- FUNCIÓN PARA GUARDAR LA RUTA EN UN ARCHIVO .MAT.
function guardar_Callback(hObject, eventdata, handles)
% GUI de usuario para colocar el nombre del archivo
[nombre ruta]=uiputfile('*.mat','Guardar ruta del objeto');
%Retorna si se presiona cancelar
if nombre==0, return, end
% Guardar la ruta con la función SAVE
ruta=handles.ruta;
save(nombre,'ruta')
% ______________________________________________________________________
% ______________________________________________________________________
% --- FUNCIÓN DEL BOTÓN PARAR (DETIENE LA ADQ DE IMÁGENES)
function parar_b_Callback(hObject, eventdata, handles)
set(handles.parar_b,'UserData',1);
guidata(hObject, handles);
% ______________________________________________________________________
% ______________________________________________________________________

function video_f_Callback(hObject, eventdata, handles)
% --- Executes during object creation, after setting all properties.
function video_f_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function umbral_Callback(hObject, eventdata, handles)
% --- Executes during object creation, after setting all properties.
function umbral_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function rojos_Callback(hObject, eventdata, handles)
% --- Executes during object creation, after setting all properties.
function rojos_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function verdes_Callback(hObject, eventdata, handles)
% --- Executes during object creation, after setting all properties.
function verdes_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function azules_Callback(hObject, eventdata, handles)
% --- Executes during object creation, after setting all properties.
function azules_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end