function varargout = TuberculosisGUI(varargin)
% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @TuberculosisGUI_OpeningFcn, ...
                   'gui_OutputFcn',  @TuberculosisGUI_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
% The above code is automatically written when using GUIDE to create a GUI
% with MATLAB, which essentially sets up the program for use.

%% Section 1: Initialize Waitbar
h = waitbar(0,'Thank you for using TuberCo Diagnosis Interface. Please wait...'); % Create a wait bar to notify user to wait
steps = 1000; % Uses waitbar to wait about a second for GUI to load 
for step = 1:steps % Run for loop till it increments to 1000
    waitbar(step / steps) % Increases the loading bar at a rate of 1/1000
end
close(h) % Closes waitbar
function TuberculosisGUI_OpeningFcn(hObject, eventdata, handles, varargin)% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   command line arguments to TuberculosisGUI (see VARARGIN)

% Choose default command line output for TuberculosisGUI
handles.output = hObject;

% Update handles structure
guidata(hObject, handles);

% --- Outputs from this function are returned to the command line.
function varargout = TuberculosisGUI_OutputFcn(hObject, eventdata, handles) %Varargout is varying arguments which is basically a GUI variable. 
% Get default command line output from handles structure
varargout{1} = handles.output;
g = msgbox('Select Upload Image to Locate Tuberculosis'); % Tells user to press the Upload button to start program
%% Section 2: Pushbutton 1- Select Image
% Executes on Upload Image press
function pushbutton1_Callback(hObject, eventdata, handles) % This function is created when placing the first pushbutton which is "Upload Image"

waitfor(msgbox({'Please select the x-ray file.'})); % Have user understand to select a x-ray file before continuing
[file, folder] = uigetfile({'*.jpg';'*.png'}); % Allows users to select a file that is either a jpg or png
if isequal(file,0) % If the user cancels out the command window will display canceled
   disp('Canceled');
   return;
end
Dir = [folder file]; % Creates an array of the folder location and the file name
grayImage = imread(Dir); % Reads the selected file from the folder with Dir
axes(handles.axes1);% Displays on the first plot which is the left plot
imshow(Dir) % Shows the image selected on the left plot

%% Section 3: Have User Set Threshold and Extract Lungs
% The code below allows the user to adjust the values for lung extraction to ensure best results
prompt = {'Enter Threshold Value For Lung Extraction (Recommended: 100):'}; % Tells the user what the meaning behind the value is
title = 'Lungs'; % Creates title for the message box
dims = [1 35]; % Dimensions for the message
definput = {'100'}; % Defaults to a value of 100
input = inputdlg(prompt,title,dims,definput); % Uses a function of inputdlg to allow the message box to appear and give the user access to edit the value
if isempty(input) % If the user cancels then stop the code
    disp('Canceled');
    return; 
end
threshold = str2double(input{1}); % Convert the string value to a number to use as a variable later in the code
clearvars -except threshold grayImage % Clears all variables but threshold and grayImage

Lungs = LungSegment(grayImage, threshold); % Uses the function LungSegment to pull out the lungs from the image

%% Section 4: Segmenting the Image and Detecting Regions of Tuberculosis
GrayscaleImage = imresize(Lungs,[720 720]); % Resizes the image to 720x720 to ensure all images can be segmented
[rows, columns, numberOfColorBands] = size(GrayscaleImage); % Takes the size of the GrayScaleImage
blockSizeR = 180; % Rows in block
blockSizeC = 180; % Columns in block

% Figure out the size of each block in rows
% Most will be blockSizeR but there may be a remainder amount of less than that
wholeBlockRows = floor(rows / blockSizeR);
blockVectorR = [blockSizeR * ones(1, wholeBlockRows), rem(rows, blockSizeR)];
% Figure out the size of each block in columns.
wholeBlockCols = floor(columns / blockSizeC);
blockVectorC = [blockSizeC * ones(1, wholeBlockCols), rem(columns, blockSizeC)];
if numberOfColorBands > 1 % Checks if the image is still in color
    % If a color image also use numberOfColorBands
    ca = mat2cell(GrayscaleImage, blockVectorR, blockVectorC, numberOfColorBands);
else % Grayscaled (all of our images)
    ca = mat2cell(GrayscaleImage, blockVectorR, blockVectorC);
end
plotIndex = 1; % Sets the index for the plots
numPlotsR = size(ca, 1); % Takes the number of the rows
numPlotsC = size(ca, 2); % Takes the number of the columns

figure(1);
for r = 1:numPlotsR % Run for the amount of rows there are
    for c = 1:numPlotsC % Run for the amount of columns there are
        % Specify the location for display of the image
        subplot(numPlotsR, numPlotsC, plotIndex);
        % Extract the numerical array out of the cell
        grayBlock = ca{r,c};
        imshow(grayBlock); % Display the subplotted region
        [rowsB, columnsB, numberOfColorBandsB] = size(grayBlock); % Takes size of grayBlock this time
        
        drawnow; % Immediately update the figure
        plotIndex = plotIndex + 1; % Increment the subplot to the next location.
    end
end

% Creates variables for regions of subplotting
count1 = [1 2 3 4; 5 6 7 8; 9 10 11 12; 13 14 15 16];
count2 = 0;
count3 = [ 1 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4];
count4 = [1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4];

tuberc_regions = []; % Creates an empty array for later use in the for loop to determine area
Number_Cavities = 0; % Sets the variable to 0 to count the amount of cavities 
for indices = [1 2 3 4 6 7 8 9 11 12 13 14 16 17 18 19] % Run subplotting for given sections 
    count2 = count2+1;
    count5 = count1(count2);
    count6 = count3(count2);
    count7 = count4(count2);
    
% Filter and Find Edges
GrayscaleImage = medfilt2(ca{indices}, [5,5]); % Applies a median filter to our sectioned lungs for anything smaller than 5x5
ThreshImage =  GrayscaleImage <= threshold; % Sets our threshold value to the user selected value
SE = strel('square', 3); % Creates a square structuring element with 3 pixels
SE.Neighborhood; % Indicates pixels in the surrounding region 
ThreshImage = imopen(not(ThreshImage),SE); % If not within the threshold the pixel is closed and removed
EdgeImage = edge(uint8(ThreshImage), 'sobel'); % Uses sobel method to detect edges in the figure
LabeledImage = bwlabel(ThreshImage); % Gives a binary label

% Display the Labeled Edges and Plot Graphs
props = regionprops(LabeledImage,'BoundingBox', 'Area'); % Gives us our properties for all the defined regions in the figure
areas = [props.Area]; % Specify you want the areas of the region properties
sortedAreas = sort(areas, 'descend'); % Sort the areas in descending order
LB = 30;  % Uses a lowerbound of 30 to remove any false positives (this was determined as the best value for eliminating small areas)
UB = 30000; % Remove any of the large objects not tuberculosis (this area was determined as the area of each plot is 32,400 pixels and we needed less than such)
edges = find(EdgeImage ~= 0); % Uses the find function to give us the edge values not equal to 0
GrayscaleImage(edges) = 255; % Makes our edges highest intensity so we can see the regions

figure(2); % Opens new figure
numRecsAcross = 5.3385; % These value was used to close the gaps between subplots
numRecsDown = 4;
subplot('Position',[(count6-1)*1/numRecsAcross (numRecsDown-count7)*1/numRecsDown 1/numRecsAcross 1/numRecsDown])
imshow(GrayscaleImage); % Shows the image and subplots the region

hold on % Allows for overlaying of plot
for i = 1:length(props) % Runs for loop for how long the detected amount of regions were
    if LB < areas(i) && areas(i) < UB % If the regions are within the bounds then continue
    plot(props(i).BoundingBox(1), props(i).BoundingBox(2), 'ro',...
    'MarkerSize', 10) % Polt a red circle in region that fits the requirements
    tuberc_region = props(i).BoundingBox; 
    tuberc_regions = [tuberc_regions; {tuberc_region}]; % Creates a cell that continuosly adds the details of the locations and areas of the regions
    Number_Cavities = Number_Cavities + 1; % Counts the amount of cavities there are
    end
end
hold off % Stops overlaying of plot

figure(3); % Opens a third figure
subplot(4,4,count5) % Adds a plot to the second column
imshow(LabeledImage) 

hold on % Allows overlay over the LabeledImage
for i =1:length(props) % Once again runs for the amount of elements props has
    if LB < areas(i) && areas(i) < UB % Continues if fits bounds
    plot(props(i).BoundingBox(1), props(i).BoundingBox(2), 'ro',...
    'MarkerSize', 10) % Plots our centroids again
    end
end
hold off % Stops overlay

end

%% Section 5: Find Max Area and Assign Variables
for i = 1:length(tuberc_regions) % Run until the amount of cells in our variable
    if i == 1 % For the first cell set area = to the product of the last two values
       area = prod(tuberc_regions{i,1}([3,4])); 
    else 
        if prod(tuberc_regions{i,1}([3,4])) > area % If any of the values are greater then replace the variable with the new value
           area = prod(tuberc_regions{i,1}([3,4])); 
        end
    end
end

saveas(figure(2),'final.jpg'); % Save the combined subplots as an image
final = imread('final.jpg'); % Read the image into the workspace
assignin('base','final',final) % Assign the variable final to the main workspace
assignin('base','area',area) % Assign the variable area to the main workspace
assignin('base','Number_Cavities',Number_Cavities) % Assign the variable Number_Cavities to the main workspace
delete('final.jpg'); % Delete the image that was saved a moment ago
close 1 2 3 % Close all figures that were created
i= msgbox('Press Detected Image to Diagnose Tuberculosis'); % Calls on messagebox which tells user a message for next step


%% Section 6: Pushbutton 2: Display Detected Image
% Executes on Display Detected Image press
function pushbutton2_Callback(hObject, eventdata, handles) % This function is created when placing the second pushbutton which is "Display Detected Image"
final = evalin('base', 'final'); % Pulls the variable final from the main workspace
area = evalin('base', 'area'); % Pulls the variable area from the main workspace
Number_Cavities = evalin('base', 'Number_Cavities'); % Pulls the variable Number_Cavities from the main workspace

axes(handles.axes2); % Selects the second plot a.k.a the right plot
imshow(final); % Shows the final image onto the right plot
answer = questdlg('Would you like to save the information and image?', ...
	'TuberCo menu', ... 
	'Yes','No','No'); % Asks the user to save the image
if answer == "Yes"
    [file,path] = uiputfile('TuberculosisDetectedImage.jpg'); % Name of File
    if isequal(file,0) || isequal(path,0)
        disp('Canceled.') % If canceled display canceled
        return;
    else % If saved also save the data gathered from the regions into a text file
        fullFileName = fullfile(path, file); % Builds the file name with the folder location
        imwrite(final, fullFileName); % Writes the image to the location
        Dir = [path 'Tuberculosis_Data.txt']; % Creates an array of the title of the text file and folder save to
        fid = fopen(Dir, 'w'); % Creates a writeable text file
        fprintf(fid,'The largest tuberculosis area is about %i pixels. \n', area'); % Prints the data from area
        fprintf(fid,'The amount of cavities detected is %i.', Number_Cavities'); % Prints the data of number of cavities
        fclose(fid); % Closes the text file
    end
else
    return;
end

%% Section 7: Pushbutton 3: Clear Axes
% Executes on button press on Clear
function pushbutton3_Callback(hObject, eventdata, handles) % This function is created when placing the third pushbutton which is "Clear"

axes(handles.axes1) % Selectes the left axis
hold off; % Wait to clear
cla reset; % Clears the plot

axes(handles.axes2); % Selects the right axis
hold off; % Wait to clear
cla reset; % Clears the plot
