0001 classdef (Abstract) FDPDEInpainter
0002
0003
0004
0005
0006 properties
0007 relChangeTolerance = 1e-8;
0008 maxIters = 100000;
0009 dt = 1e-2;
0010 relax = 1;
0011 hx = 1;
0012 hy = 1;
0013
0014 debugShowStep = false;
0015 debugCreateVideo = false;
0016 debugVideoFile = '';
0017 debugItersPerFrame = 1000;
0018 end
0019
0020 methods
0021 function obj = FDPDEInpainter(varargin)
0022
0023
0024 p = inputParser;
0025 p.KeepUnmatched=true;
0026 validGTZero = @(x) isscalar(x) && x >= 0;
0027 validGTZeroInt = @(x) isscalar(x) && x >= 0 && floor(x) == x;
0028 validScalarLogical = @(x) isscalar(x) && islogical(x);
0029 validRelaxation = @(x) isscalar(x) && x >= 1 && x <= 2;
0030 addParameter(p, 'UpdateStepSize', 1e-2, validGTZero);
0031 addParameter(p, 'RelChangeTolerance', 1e-8, validGTZero);
0032 addParameter(p, 'MaxIters', 1e8, validGTZeroInt);
0033 addParameter(p, 'Relaxation', 1, validRelaxation);
0034 addParameter(p, 'DebugShowStep', false, validScalarLogical);
0035 addParameter(p, 'DebugVideoFile', '', @ischar);
0036 addParameter(p, 'DebugItersPerFrame', 1000, validGTZeroInt);
0037 addParameter(p, 'GridStepX', 1, @isscalar);
0038 addParameter(p, 'GridStepY', 1, @isscalar);
0039 parse(p, varargin{:});
0040
0041 obj.relChangeTolerance = p.Results.RelChangeTolerance;
0042 obj.maxIters = p.Results.MaxIters;
0043 obj.dt = p.Results.UpdateStepSize;
0044 obj.hx = p.Results.GridStepX;
0045 obj.hy = p.Results.GridStepY;
0046
0047 obj.debugShowStep = p.Results.DebugShowStep;
0048 obj.debugItersPerFrame = p.Results.DebugItersPerFrame;
0049 if ~isempty(p.Results.DebugVideoFile)
0050 obj.debugVideoFile = p.Results.DebugVideoFile;
0051 obj.debugCreateVideo = true;
0052 end
0053 end
0054
0055 function inpaitedImage = inpaint(obj, image, mask)
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067 [sy, sx, channels] = size(image);
0068 if size(mask, 1) ~= sy || size(mask, 2) ~= sx
0069 error('The mask must have the first two dimensions equal to those of the image');
0070 end
0071
0072 inpaitedImage = zeros(size(image));
0073
0074
0075 if obj.debugCreateVideo
0076
0077 video = VideoWriter(obj.debugOutputVideoFile, 'Motion JPEG AVI');
0078 video.Quality = 100;
0079 open(video);
0080 end
0081
0082
0083 for c = 1:channels
0084
0085 f = image(:, :, c);
0086 Pi = @(f)f.*(1-mask) + image(:, :, c).*mask;
0087
0088
0089
0090
0091
0092 for i=1:obj.maxIters
0093
0094 fnew = Pi(f - obj.dt*obj.stepFun(f));
0095
0096
0097 if obj.relax > 1
0098 fnew = Pi(f*(1-obj.relax) + fnew*obj.relax);
0099 end
0100
0101
0102 diff = norm(fnew(:)-f(:))/norm(fnew(:));
0103
0104
0105 f = fnew;
0106
0107
0108 if (obj.debugShowStep || obj.debugCreateVideo) && mod(i-1, obj.debugItersPerFrame) == 0
0109 imagesc(f'); axis xy; colorbar;
0110 if obj.createDemoVideo
0111 frame = getframe(gcf);
0112 writeVideo(video, frame);
0113 end
0114 end
0115
0116
0117 if diff < obj.relChangeTolerance
0118 break;
0119 end
0120 end
0121
0122
0123
0124
0125 if i == obj.maxIters
0126 warning('Maximum number of iterations reached');
0127 end
0128
0129 inpaitedImage(:, :, c) = f;
0130 end
0131
0132
0133 if obj.debugCreateVideo, close(video); end
0134 end
0135
0136 function varargin = removeParentParametersFromVarargin(obj, varargin)
0137 paramsToDelete = {'UpdateStepSize', 'RelChangeTolerance', 'MaxIters', 'Relaxation', 'DebugShowStep', 'DebugVideoFile', 'DebugItersPerFrame', 'GridStepX', 'GridStepY'};
0138 varargin = deleteParamsFromVarargin(paramsToDelete, varargin);
0139 end
0140 end
0141
0142
0143 methods (Abstract)
0144 f = stepFun(obj, f, mask);
0145 end
0146
0147
0148 methods (Access = protected)
0149 function preProcess(obj, img, mask)
0150
0151 end
0152 function stepRegularization(obj, img, mask)
0153
0154 end
0155 function postProcessing(obj, img, mask)
0156
0157 end
0158 end
0159 end
0160