% Notes and Recommendations:
% - File Organization: It is recommended to place all videos obtained from an experiment inside the same folder. This code is designed to apply normalization to all videos within the selected folder.
% - File Filter (ref): The variable "ref" is used as a reference so that the program only processes videos whose names start with that specific value.
% - Storing Results: Normalized videos are saved using the naming convention ["namVid", "Original_Name"] inside a new folder named "VideoNorRes", which will be automatically created inside the selected folder.
% - Normalization Parameters:
%   * "DivI": Indicates the maximum value to which you want to normalize your videos (scale from 0 to 1, where 1 represents 255, the maximum pixel value).
%   * "minP": Indicates the minimum value that the normalization will accept; any value below this threshold will be eliminated.
%   * Note: The values for "minP" and "DivI" should be chosen by analyzing the pixel histogram, ensuring that the object of interest does not become saturated or lose essential parts.
% - Region of Interest (ROI): The variable "a1" defines whether a manual ROI is used to eliminate the selected section. If "a1" = 0, no ROI is generated; if "a1" > 0, the manual ROI is applied.
% - Using the FucMaskIm Function: This function is used to generate a complete mask of the object, ensuring that the area in which it moves remains fixed throughout the entire video.
%   * Requirement: For the program to detect the function, the "FucMaskIm.m" file (or its corresponding extension) must be located in the same folder as this script.
%   * Syntax: FucMaskIm(readerobj, FreVi, minP, maxP, area, aref, a1)
%   * Parameters: (Video, FPS, Minimum value, Maximum value, Minimum area, Edge removal, Enable ROI)

clear
close all
clc

path = uigetdir;
d2=dir([path,filesep,'**/*.avi']); % Address of the videos to be normalized in format .avi.
d=dir([path,filesep,'VideoNorRes']); % Save address for normalization videos.
h3=size(d);
h2=size(d2);
Dfolder=[path,filesep,'VideoNorRes']; %See if the save location exists
if h3(1)==0
    mkdir(Dfolder);
end
DivI=0.8; % Maximum value to which values ​​between 0-1 will be normalized
minP=20; % Minimun value to which values ​​between 0-255 will be normalized
maxP=round(DivI*255);
namVid='ResNor'; %Start of the normalized video name
%% Validation of videos in the folder
ref='Supple'; % I only selected the videos that start with the name of the ref variable
h=length(ref);
cref=1;
for i3=1:h2(1)
    nom=d2(i3).name;
    if strcmp(nom(1:h),ref)
        d3(cref)=d2(i3);
        cref=cref+1;
    end
end
h4=size(d3);
%% Main cycle
a1=1; % Select if you want to use manual ROI, a1=0 is not used, a1>0 is used
for j2=1:h4(2)
    file2=d3(j2).name;
    file2(end-3:end)=[];
    readerobj = VideoReader([path,filesep,d3(j2).name]);  
    imF=read(readerobj, 1);
    h=size(imF);
    N=readerobj.NumFrames;
    VideoObj=VideoWriter([Dfolder,filesep,namVid,file2,'.avi'],'Motion JPEG AVI'); % Normalized video name and address
    VideoObj.Quality=100;
    FreVi=round(readerobj.FrameRate); 
    VideoObj.FrameRate=FreVi;
    ImFTotal=zeros(h(1),h(2),N);
    ImFTotal2=zeros(h(1),h(2),N);
    ImFTotal3=zeros(h(1),h(2),N);
    if j2==1 && a1>0
        figure
        imF=read(readerobj,FreVi+1);
        imF=im2gray(imF);
        imshow(imF)
        hroi = drawassisted; % Manual ROI to delimit the perimeter of the heart
        mask2 = createMask(hroi);
        we3=find(mask2==1); 
        for i2=1:N % Saving the video in the ImFTotal matrix
            imF=read(readerobj, i2);
            imF=im2gray(imF);
            imF=double(imF);
            imF(we3)=0;
            ImFTotal3(:,:,i2)=imF;
        end
        mask=FucMaskIm(ImFTotal3,FreVi,minP,maxP,100,1,a1); %% Function that segments all images to create a mask and eliminates objects with an area less than a value of 100. This parameter can be changed
    elseif a1>0 && j2>1
        for i2=1:N % Saving the video in the ImFTotal matrix
            imF=read(readerobj, i2);
            imF=im2gray(imF);
            imF=double(imF);
            imF(we3)=0;
            ImFTotal3(:,:,i2)=imF;
        end
        mask=FucMaskIm(ImFTotal3,FreVi,minP,maxP,100,1,a1); 
    else
        mask=FucMaskIm(readerobj,FreVi,minP,maxP,100,1,a1); 
    end
    imref = imfill(mask,'holes'); % Gap filling function
    we=find(imref==0);
    
    for i2=1:N 
        if a1==1
            imF=ImFTotal3(:,:,i2);
        else
            imF=read(readerobj, i2);
        end
        imF=im2gray(imF);
        imF=double(imF);
        imF(we)=0;
        we2=find(imF<=minP);
        imF(we2)=0;
        ImFTotal(:,:,i2)=imF;
    end
    minTol=min(ImFTotal,[],'all');
    maxTol=255*DivI;
    for i2=1:N % Normalization of the original video with respect to the maximum and minimum value of the entire video
        for i=1:h(1)
            for j=1:h(2)
                if maxTol<=0
                    ImFTotal2(i,j,i2)=0;
                else
                    ImFTotal2(i,j,i2)=(ImFTotal(i,j,i2)-minTol)/(maxTol-minTol);
                end
            end
        end
    end
    open(VideoObj);
    for i2=1:N
        imCen=ImFTotal2(:,:,i2);
        imCen=imCen*255;
        writeVideo(VideoObj,uint8(imCen));
    end
    close(VideoObj);
    disp(['Finished  ',file2,' Video'])
    disp(['Video ',num2str(j2),' of ',num2str(h4(2))])
    pause(1)
end
