classdef app1_FINAL < matlab.apps.AppBase

    % Properties that correspond to app components
    properties (Access = public)
        UIFigure                        matlab.ui.Figure
        ObjectCountourPanel             matlab.ui.container.Panel
        GetObjectContoursButton         matlab.ui.control.Button
        ObjectContoursLabel             matlab.ui.control.Label
        UIAxesObjectContour             matlab.ui.control.UIAxes
        ExitButton                      matlab.ui.control.Button
        ObjectDetectionPanel            matlab.ui.container.Panel
        ClosestObjectLabel              matlab.ui.control.Label
        GetObjectCloudButton            matlab.ui.control.Button
        GetFullCloudPointButton         matlab.ui.control.Button
        DistancebehindobjectmEditField  matlab.ui.control.NumericEditField
        DistancebehindobjectmEditFieldLabel  matlab.ui.control.Label
        GetObjectSelectedPointsButton   matlab.ui.control.Button
        UIAxesClosestObject             matlab.ui.control.UIAxes
        VideoStreamsPanel               matlab.ui.container.Panel
        DepthVideoStreamLabel           matlab.ui.control.Label
        RGBVideoStreamLabel             matlab.ui.control.Label
        StartStreamsButton              matlab.ui.control.Button
        UIAxesDEPTHStream               matlab.ui.control.UIAxes
        UIAxesRGBStream                 matlab.ui.control.UIAxes
    end

    
    methods (Access = private)
        

    end
    

    % Callbacks that handle component events
    methods (Access = private)

        % Button pushed function: StartStreamsButton
        function StartStreamsButtonPushed(app, event)
            %% GLOBALS
            global DEPTHDisp
            global RGBDisp
%             global imgDEPTH
            global imgRGB

            %% RGB
            % LIGAR CAMARA RGB
            RGBDisp = videoinput('kinect',1,'RGB_640x480');

            frameRGB = flip(getsnapshot(RGBDisp),2);
            imgRGB = image(app.UIAxesRGBStream,zeros(size(frameRGB),'uint16'));

            % MOSTRAR RGB STREAM
            axis(app.UIAxesRGBStream,'image');
            preview(RGBDisp,imgRGB);

            % RGB VIDEO STREAM ASPECT RATIO
            app.UIAxesRGBStream.XLim = [0,640];
            app.UIAxesRGBStream.YLim = [0,480];
            pbaspect(app.UIAxesRGBStream,[640,480,1]);

            %% DEPTH
            % LIGAR CAMARA DEPTH
            DEPTHDisp = videoinput('kinect',2,'Depth_640x480');

            frameDEPTH = flip(getsnapshot(DEPTHDisp),2);
            imgDEPTH = image(app.UIAxesDEPTHStream,zeros(size(frameDEPTH),'uint16'));

            % MOSTRAR DEPTH STREAM
            axis(app.UIAxesDEPTHStream)
            preview(DEPTHDisp,imgDEPTH)

            % DEPTH VIDEO STREAM ASPECT RATIO
            app.UIAxesDEPTHStream.XLim = [0,640];
            app.UIAxesDEPTHStream.YLim = [0,480];
            pbaspect(app.UIAxesDEPTHStream,[640,480,2]);
            colormap(app.UIAxesDEPTHStream,'jet')


        end

        % Button pushed function: GetFullCloudPointButton
        function GetFullCloudPointButtonPushed(app, event)
            %% GLOBALS
            global DEPTHDisp
            global RGBDisp
            global ptCloudRot
            global RGBFrame1  

            %% FECHAR JANELA ABERTA
            close(figure(1))

            %% EXTRAIR A NUVEM DE PONTOS
            RGBFrame1 = getsnapshot(RGBDisp);
            DEPTHFrame1 = getsnapshot(DEPTHDisp);

            ptCloudOriginal = pcfromkinect(DEPTHDisp, DEPTHFrame1, RGBFrame1);

            %% RODAR A NUVEM DE PONTOS PARA FICAR PARALELA COM EIXO DOS XX
            %ANGULO DE ROTAÇAO
            theta = -0.04;

            % MATRIZ DE ROTAÇAO EM X
            Rx = [1 0 0; 0 cos(theta) -sin(theta); 0 sin(theta) cos(theta)];
            trans = [0, 0, 0];
            tform = rigid3d(Rx,trans);

            % NOVA NUVEM DE PONTOS RODADA
            ptCloudRot = pctransform(ptCloudOriginal,tform);

            % MOSTART NUVEM DE PONTOS
            figure
            pcshow(ptCloudRot,"VerticalAxis","Y",VerticalAxisDir="Down");
            title('Full Point Cloud')
            xlabel('X(m)')
            ylabel('Y(m)')
            zlabel('Z(m)')
            
        end

        % Button pushed function: GetObjectSelectedPointsButton
        function GetObjectSelectedPointsButtonPushed(app, event)
            %% GLOBALS
            global zRot
            global MRot
            global ptCloudRot
            global ptCloudObjeto
            global RGBFrame1
            global RGBCropped
            %%
            if app.GetObjectSelectedPointsButtonPushed~=1 && app.GetFullCloudPointButtonPushed~=0
                errordlg('Complete Point Cloud is required!')
            end
            %% FECHAR JANELA ABERTA
            close(figure(1))

            %% OBTER IMAGEM DO OBJETO MAIS PRÓXIMO
            % RETIRAR A MATRIZ DE PONTOS DE LOCALIZAÇAO DOS PONTOS
            zRot = ptCloudRot.Location(:,:,3);

            % MOSTART INDICE DOS PONTOS MINIMOS DA NUVEM DE PONTOS
            [MRot,~] = min(min(zRot));

            % LOCALIZAÇAO DO PONTO MAIS PROXIMO
            [xRot,yRot]=find(zRot==MRot);

            % RESOLUÇÃO DA IMAGEM 200x200
            xmin = xRot(1)-100;
            xmax = xRot(1)+100;
            ymin = yRot(1)-100;
            ymax = yRot(1)+100;

            % % IMPEDIR QUE IMAGEM XMIN SEJA NEGATIVO E XMAX NAO ULTRAPASSE OS 480
            if xmin < 0
                xmin = 1;
            elseif xmax > 480
                xmax = 480;
            end

            % IMPEDIR QUE IMAGEM YMIN SEJA NEGATIVO EYXMAX NAO ULTRAPASSE OS 640
            if ymin < 0
                ymin = 1;
            elseif ymax > 640
                ymax = 640;
            end

            % FRAME RGB RECORTADO EM 200x200 PARA ELIMINAR PERTURBAÇÕES NO FUNDO
            RGBCropped = RGBFrame1(xmin:xmax,ymin:ymax,:);

            image(RGBCropped,'Parent',app.UIAxesClosestObject)
            set(app.UIAxesClosestObject,'visible','off');

            %% ENCONTRAR VIZINHANÇA DO OBJETO MAIS PROXIMO
            % PONTO ORIGEM PARA PROCEDER À VIZINHANÇA -> (0,0,0) ERA O PONTO QUE MARCAVA "CENTRO" DO OBJETO
            point = [0 0 0];

            % INTRODUZIR A DISTANCIA DO PONTO MAIS PROXIMO ATÉ AO PONTO MAIS AFASTADO DO OBJETO
            Z = app.DistancebehindobjectmEditField.Value;
            
            % Nº DE PONTOS DA VIZINHANÇA
            K = numel(find(zRot<(MRot+Z)));

            % LOCALIZAÇÃO DOS PONTOS DE VIZINHANÇA
            [indices,~] = findNearestNeighbors(ptCloudRot,point,K);

            % NUVEM DE PONTOS DO OBJETO MAIS PROXIMO
            ptCloudObjeto = select(ptCloudRot,indices);

            % MOSTRAR A NUVEM DE PONTOS COM O OBJETO SELECIONADO
            figure
            pcshow(ptCloudRot,'VerticalAxis','Y',VerticalAxisDir='Down')
            hold on
            pcshow(ptCloudObjeto.Location,'ob','MarkerSize',5,'VerticalAxis','Y',VerticalAxisDir='Down')

            title('Selected Object Points')
            xlabel('X(m)')
            ylabel('Y(m)')
            zlabel('Z(m)')
         
        end

        % Button pushed function: GetObjectCloudButton
        function GetObjectCloudButtonPushed(app, event)
            %% GLOBALS
            global ptCloudObjeto

            %% FECHAR AS FIGURES ABERTAS
            close(figure(1));

            %% NUVEM DE PONTOS DO OBJETO SELECIONADO
            % MATRIZ POSIÇAO DO OBJETO
            PontosObjeto = ptCloudObjeto.Location;

            % MATRIZ CORES DO OBJETO
            CoresObjeto = ptCloudObjeto.Color;

            % NUVEM DE PONTOS DO OBJETO
            PtCloudObjeto = pointCloud(PontosObjeto,"Color",CoresObjeto);

            figure
            pcshow(PtCloudObjeto,'VerticalAxis','Y',VerticalAxisDir='Down')
            title('Object Point Cloud')
            xlabel('X(m)')
            ylabel('Y(m)')
            zlabel('Z(m)')
        end

        % Button pushed function: ExitButton
        function ExitButtonPushed(app, event)
            app.delete
        end

        % Button pushed function: GetObjectContoursButton
        function GetObjectContoursButtonPushed(app, event)
            %% GLOBALS
            global RGBCropped

            % BINARIZAÇÃO DA IMAGEM RECORTADA E PASSAGEM A BW
            imgBin = imbinarize(im2gray(RGBCropped));

            % PREENCHER ESPAÇOS DA IMAGEM
            op1=bwmorph(imgBin,'close',Inf);
            
            % REMOVER OBJETOS QUE TENHAM MAIS DE 800 PIXEIS (800 -> VALOR TENTATIVA ERRO)
            BW2 =bwareaopen(op1,800);
            
            % PREENCHER OS BURACOS DA IMAGEM QUE TENHAM PIXEIS BRANCOS À VOLTA
            imgBinHoles = imfill(BW2,'holes');

            % IDENTIFICAR E NUMERAR OS DIFERENTES OBJETOS NA IMAGEM BIN
            [L,N]=bwlabel(imgBinHoles);

            for i=1:N
                g=(L==i);
                tt(:,:,i)= imgBinHoles-g;
            end

            % FAZER A SEPARAÇÃO DOS DIFERENTES OBJETOS NA IMAGEM BIN
            aa=0;

            for i=1:size(tt,3)
                aa=[aa nnz(tt(:,:,i))];
            end

            % ENCONTRAR O MAIOR OBJETO BINARIZADO
            [~,okk]=find(aa(2:end)==max(aa));

            quero=tt(:,:,okk);

            % FAZER O PERIMETRO DO OBJETO PARA OBTER CONTORNO
            perim=bwperim(quero);            

            imshow(perim,'Parent',app.UIAxesObjectContour)
                     
        end
    end

    % Component initialization
    methods (Access = private)

        % Create UIFigure and components
        function createComponents(app)

            % Create UIFigure and hide until all components are created
            app.UIFigure = uifigure('Visible', 'off');
            app.UIFigure.AutoResizeChildren = 'off';
            app.UIFigure.Position = [100 100 996 638];
            app.UIFigure.Name = 'MATLAB App';
            app.UIFigure.Resize = 'off';

            % Create VideoStreamsPanel
            app.VideoStreamsPanel = uipanel(app.UIFigure);
            app.VideoStreamsPanel.AutoResizeChildren = 'off';
            app.VideoStreamsPanel.Title = 'Video Streams';
            app.VideoStreamsPanel.Position = [21 56 354 569];

            % Create UIAxesRGBStream
            app.UIAxesRGBStream = uiaxes(app.VideoStreamsPanel);
            app.UIAxesRGBStream.Box = 'on';
            app.UIAxesRGBStream.Position = [21 342 312 185];

            % Create UIAxesDEPTHStream
            app.UIAxesDEPTHStream = uiaxes(app.VideoStreamsPanel);
            app.UIAxesDEPTHStream.Box = 'on';
            app.UIAxesDEPTHStream.Position = [21 102 313 185];

            % Create StartStreamsButton
            app.StartStreamsButton = uibutton(app.VideoStreamsPanel, 'push');
            app.StartStreamsButton.ButtonPushedFcn = createCallbackFcn(app, @StartStreamsButtonPushed, true);
            app.StartStreamsButton.Position = [128 32 100 22];
            app.StartStreamsButton.Text = 'Start Streams';

            % Create RGBVideoStreamLabel
            app.RGBVideoStreamLabel = uilabel(app.VideoStreamsPanel);
            app.RGBVideoStreamLabel.Position = [124 518 107 22];
            app.RGBVideoStreamLabel.Text = 'RGB Video Stream';

            % Create DepthVideoStreamLabel
            app.DepthVideoStreamLabel = uilabel(app.VideoStreamsPanel);
            app.DepthVideoStreamLabel.Position = [121 278 113 22];
            app.DepthVideoStreamLabel.Text = 'Depth Video Stream';

            % Create ObjectDetectionPanel
            app.ObjectDetectionPanel = uipanel(app.UIFigure);
            app.ObjectDetectionPanel.AutoResizeChildren = 'off';
            app.ObjectDetectionPanel.Title = 'Object Detection';
            app.ObjectDetectionPanel.Position = [397 308 574 316];

            % Create UIAxesClosestObject
            app.UIAxesClosestObject = uiaxes(app.ObjectDetectionPanel);
            app.UIAxesClosestObject.DataAspectRatio = [0.596078431372549 1 1];
            app.UIAxesClosestObject.PlotBoxAspectRatio = [1.67763157894737 1 1];
            app.UIAxesClosestObject.Box = 'on';
            app.UIAxesClosestObject.Position = [20 -8 230 170];

            % Create GetObjectSelectedPointsButton
            app.GetObjectSelectedPointsButton = uibutton(app.ObjectDetectionPanel, 'push');
            app.GetObjectSelectedPointsButton.ButtonPushedFcn = createCallbackFcn(app, @GetObjectSelectedPointsButtonPushed, true);
            app.GetObjectSelectedPointsButton.IconAlignment = 'center';
            app.GetObjectSelectedPointsButton.Position = [348 234 165 41];
            app.GetObjectSelectedPointsButton.Text = 'Get Object Selected Points';

            % Create DistancebehindobjectmEditFieldLabel
            app.DistancebehindobjectmEditFieldLabel = uilabel(app.ObjectDetectionPanel);
            app.DistancebehindobjectmEditFieldLabel.HorizontalAlignment = 'center';
            app.DistancebehindobjectmEditFieldLabel.Position = [300 190 148 22];
            app.DistancebehindobjectmEditFieldLabel.Text = 'Distance behind object (m)';

            % Create DistancebehindobjectmEditField
            app.DistancebehindobjectmEditField = uieditfield(app.ObjectDetectionPanel, 'numeric');
            app.DistancebehindobjectmEditField.Limits = [0 Inf];
            app.DistancebehindobjectmEditField.Position = [452 190 100 22];
            app.DistancebehindobjectmEditField.Value = 0.2;

            % Create GetFullCloudPointButton
            app.GetFullCloudPointButton = uibutton(app.ObjectDetectionPanel, 'push');
            app.GetFullCloudPointButton.ButtonPushedFcn = createCallbackFcn(app, @GetFullCloudPointButtonPushed, true);
            app.GetFullCloudPointButton.IconAlignment = 'center';
            app.GetFullCloudPointButton.Position = [51 234 165 41];
            app.GetFullCloudPointButton.Text = 'Get Full Cloud Point';

            % Create GetObjectCloudButton
            app.GetObjectCloudButton = uibutton(app.ObjectDetectionPanel, 'push');
            app.GetObjectCloudButton.ButtonPushedFcn = createCallbackFcn(app, @GetObjectCloudButtonPushed, true);
            app.GetObjectCloudButton.IconAlignment = 'center';
            app.GetObjectCloudButton.Position = [349 76 165 41];
            app.GetObjectCloudButton.Text = 'Get Object Cloud';

            % Create ClosestObjectLabel
            app.ClosestObjectLabel = uilabel(app.ObjectDetectionPanel);
            app.ClosestObjectLabel.HorizontalAlignment = 'center';
            app.ClosestObjectLabel.Position = [93 153 84 22];
            app.ClosestObjectLabel.Text = 'Closest Object';

            % Create ExitButton
            app.ExitButton = uibutton(app.UIFigure, 'push');
            app.ExitButton.ButtonPushedFcn = createCallbackFcn(app, @ExitButtonPushed, true);
            app.ExitButton.Position = [871 17 100 22];
            app.ExitButton.Text = 'Exit';

            % Create ObjectCountourPanel
            app.ObjectCountourPanel = uipanel(app.UIFigure);
            app.ObjectCountourPanel.AutoResizeChildren = 'off';
            app.ObjectCountourPanel.Title = 'Object Countour';
            app.ObjectCountourPanel.Position = [398 56 574 227];

            % Create UIAxesObjectContour
            app.UIAxesObjectContour = uiaxes(app.ObjectCountourPanel);
            app.UIAxesObjectContour.Box = 'on';
            app.UIAxesObjectContour.Position = [19 9 313 185];

            % Create ObjectContoursLabel
            app.ObjectContoursLabel = uilabel(app.ObjectCountourPanel);
            app.ObjectContoursLabel.Position = [130 183 92 22];
            app.ObjectContoursLabel.Text = 'Object Contours';

            % Create GetObjectContoursButton
            app.GetObjectContoursButton = uibutton(app.ObjectCountourPanel, 'push');
            app.GetObjectContoursButton.ButtonPushedFcn = createCallbackFcn(app, @GetObjectContoursButtonPushed, true);
            app.GetObjectContoursButton.Position = [376 81 165 41];
            app.GetObjectContoursButton.Text = 'Get Object Contours';

            % Show the figure after all components are created
            app.UIFigure.Visible = 'on';
        end
    end

    % App creation and deletion
    methods (Access = public)

        % Construct app
        function app = app1_FINAL

            % Create UIFigure and components
            createComponents(app)

            % Register the app with App Designer
            registerApp(app, app.UIFigure)

            if nargout == 0
                clear app
            end
        end

        % Code that executes before app deletion
        function delete(app)

            % Delete UIFigure when app is deleted
            delete(app.UIFigure)
        end
    end
end