function varargout = Image_Inpainting_GUI(varargin)
% IMAGE_INPAINTING_GUI M-file for Image_Inpainting_GUI.fig
%      IMAGE_INPAINTING_GUI, by itself, creates a new IMAGE_INPAINTING_GUI or raises the existing
%      singleton*.
%
%      H = IMAGE_INPAINTING_GUI returns the handle to a new IMAGE_INPAINTING_GUI or the handle to
%      the existing singleton*.
%
%      IMAGE_INPAINTING_GUI('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in IMAGE_INPAINTING_GUI.M with the given input arguments.
%
%      IMAGE_INPAINTING_GUI('Property','Value',...) creates a new IMAGE_INPAINTING_GUI or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before Image_Inpainting_GUI_OpeningFcn gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to Image_Inpainting_GUI_OpeningFcn via varargin.
%
%      *See GUI Options on GUIDE's Tools menu.  Choose "GUI allows only one
%      instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES

% Edit the above text to modify the response to help Image_Inpainting_GUI

% Last Modified by GUIDE v2.5 16-Jul-2010 16:52:12

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @Image_Inpainting_GUI_OpeningFcn, ...
                   'gui_OutputFcn',  @Image_Inpainting_GUI_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


% --- Executes just before Image_Inpainting_GUI is made visible.
function Image_Inpainting_GUI_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% 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 Image_Inpainting_GUI (see VARARGIN)

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

UserData.Im = varargin{1};
UserData.ScratchesList = []; % Each line is one scratch: [p1Y p1X p2Y p2X width]
UserData.NumScratchesOnPixel = zeros(size(UserData.Im));
set(handles.figure1 , 'UserData' , UserData);
Update_Image(handles);

% Update handles structure
guidata(hObject, handles);

% UIWAIT makes Image_Inpainting_GUI wait for user response (see UIRESUME)
% uiwait(handles.figure1);


% --- Outputs from this function are returned to the command line.
function varargout = Image_Inpainting_GUI_OutputFcn(hObject, eventdata, handles) 
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get default command line output from handles structure
varargout{1} = handles.output;


% --- Executes on button press in SelectScratchButton.
function SelectScratchButton_Callback(hObject, eventdata, handles)
% hObject    handle to SelectScratchButton (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get the data
UserData = get(handles.figure1 , 'UserData');

% Get the points
[scratchX , scratchY] = ginput(2);
if length(scratchX) < 2, return; end; % Do nothing if 2 points aren't selected
p1 = [scratchY(1) scratchX(1)];
p2 = [scratchY(2) scratchX(2)];

% Get the scratch width
scratchWidth = str2double(get(handles.ScratchWidthText , 'String'));
if (scratchWidth > 3)
	errordlg('Scratch is too thick - max is 3 pixels' , 'Adding Scratches');
	return;
end

% Compute the mask image for this scratch
currScratchIm = Get_Scratch_Im(size(UserData.Im) , p1 , p2 , scratchWidth);

% Update the total mask
UserData.NumScratchesOnPixel = UserData.NumScratchesOnPixel + currScratchIm;

% Store the scratch
UserData.ScratchesList = [UserData.ScratchesList ; p1 p2 scratchWidth];

% Save the data
set(handles.figure1 , 'UserData' , UserData);

% Update the image
Update_Image(handles)



% --- Executes on button press in RemoveScratchButton.
function RemoveScratchButton_Callback(hObject, eventdata, handles)
% hObject    handle to RemoveScratchButton (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get the data
UserData = get(handles.figure1 , 'UserData');
p1 = UserData.ScratchesList(end , 1:2);
p2 = UserData.ScratchesList(end , 3:4);
scratchWidth = UserData.ScratchesList(end , 5);

% Compute the mask image for this scratch
currScratchIm = Get_Scratch_Im(size(UserData.Im) , p1 , p2 , scratchWidth);

% Update the total mask
UserData.NumScratchesOnPixel = max(UserData.NumScratchesOnPixel - currScratchIm , 0);

% Remove the scratch from the list
UserData.ScratchesList(end,:) = [];

% Save the data
set(handles.figure1 , 'UserData' , UserData);

% Update the image
Update_Image(handles)


function currScratchIm = Get_Scratch_Im(imSz , p1 , p2 , scratchWidth)

% Get the points on the line itself
d = ceil( sqrt(sum( (p2-p1).^2)));
pointsOnLineX = round(linspace(p1(2) , p2(2) , 10*d));
pointsOnLineY = round(linspace(p1(1) , p2(1) , 10*d));
pointsOnLineInd = sub2ind(imSz , pointsOnLineY , pointsOnLineX);
currScratchIm = zeros(imSz);
currScratchIm(unique(pointsOnLineInd)) = 1;

% Take care of the width

% Create a mask to make the line the desired width
halfScratchWidth = ceil(scratchWidth / 2);
[deltC, deltR] = meshgrid([-halfScratchWidth:halfScratchWidth] , [-halfScratchWidth:halfScratchWidth]);
deltTot = sqrt(deltC.^2 + deltR.^2);
resFilter = double(deltTot<=halfScratchWidth);
currScratchIm = imfilter(currScratchIm , resFilter , 'same' , 0);
currScratchIm = currScratchIm > 0;

return;


% --- Executes on button press in Done.
function Done_Callback(hObject, eventdata, handles)
% hObject    handle to Done (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

UserData = get(handles.figure1 , 'UserData');
Mask = UserData.NumScratchesOnPixel == 0;
[ResIm , ResIm_OMPonly] = Image_Inpainting(double(UserData.Im) , Mask , 2);
figure; imshow(UserData.Im , [0 255]); title('Original Image'); ax = gca;
figure; imshow(double(UserData.Im) .* Mask , [0 255]); title('Masked Image'); ax = [ax gca];

figure; imshow(ResIm_OMPonly , [0 255]); P = Compute_Error_Stats(ResIm_OMPonly , UserData.Im); title(sprintf('Result , %02.2f dB' , P)); ax = [ax gca];
figure; imshow(ResIm , [0 255]); P = Compute_Error_Stats(ResIm , UserData.Im); title(sprintf('Result, replacing only missing pixels , %02.2f dB' , P)); ax = [ax gca];
linkaxes(ax , 'xy');


function Update_Image(handles)

UserData = get(handles.figure1 , 'UserData');
Mask = UserData.NumScratchesOnPixel == 0;
rgbIm = repmat(UserData.Im , [1 1 3]);
R = UserData.Im; R(~Mask) = 255;
G = UserData.Im; G(~Mask) = 255;
B = UserData.Im; B(~Mask) = 0;
rgbIm(:,:,1) = R; rgbIm(:,:,2) = G; rgbIm(:,:,3) = B;
axes(handles.imAxes);
imshow(rgbIm);
hold on;


% --- Executes on button press in ZoomOnButton.
function ZoomOnButton_Callback(hObject, eventdata, handles)
% hObject    handle to ZoomOnButton (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

axes(handles.imAxes);
zoom on;



function ScratchWidthText_Callback(hObject, eventdata, handles)
% hObject    handle to ScratchWidthText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of ScratchWidthText as text
%        str2double(get(hObject,'String')) returns contents of ScratchWidthText as a double


% --- Executes during object creation, after setting all properties.
function ScratchWidthText_CreateFcn(hObject, eventdata, handles)
% hObject    handle to ScratchWidthText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end
