% the script prepares the input and parses various parameters

% Written by Yi-Qing Wang, 2016

image.original = imread(image.realImagePath);
if ~isa(image.original, 'uint8')
	image.original = im2uint8(image.original);
end
if length(size(image.original)) == 3
	image.original = rgb2gray(image.original);
end

[~,name_str,~] = fileparts(image.realImagePath); 

imwrite(uint8(image.original), sprintf('%s.png', name_str));

rng('default');
rng(5);

clear palette;
linewidth = 3;
palette.wo = floor(linewidth/2); % width offset
if regexp(mode, 'all_red')
	% leave a field undefined = no display
	palette.track = [255, 0, 0];
	palette.detect = [255, 0, 0];
	% palette.strip = [0, 0, 255];
elseif regexp(mode, 'classic')
	% leave a field undefined = no display
	palette.track = [255, 0, 0];
	palette.detect = [0, 255, 0];
	palette.strip = [0, 0, 255];
elseif regexp(mode, 'detection_only')
	% leave a field undefined = no display
	% palette.track = [255, 0, 0];
	palette.detect = [0, 255, 0];
	palette.strip = [0, 0, 255];
end

% potentially two sweeps if only_horizontal = false

for run = 0:1

if ~only_horizontal
	% transpose the input image here
	image.original = image.original';
end

% parameters for CurveDetector
detector.image_size = min(size(image.original));
detector.h_bound = 10;
detector.skipScaleZero = true;
detector.variance_test = true;		% beneficial
detector.margin_size = 1;
detector.display_every = -1;
detector.extend_all = false;
detector.chi_test = true;		% critical
detector.scale_offset = 2;		% inflated by 1 width ratio between a tracking strip and a detection strip
detector.max_num_lps = 2^(detector.max_scale-detector.interp_scale+detector.scale_offset);

% only add noise to the toy example
if regexp(image.realImagePath, '.*toy.*')
	snr = 1.5;
	image.toyNoise = 50/snr;  % edge contrast set to 50 for proper image displaying
	detector.suggested_sigma = image.toyNoise;
	if run == 0
	image.noise = randn(size(image.original))*detector.suggested_sigma;
	image.noisy = double(image.original) + image.noise;
	else
	image.noisy = image.noisy';
	end
else
	image.noisy = double(image.original);
end

imwrite(uint8(image.noisy), sprintf('%s_noisy.png', name_str));

if run == 0
image.background = repmat(image.noisy, [1, 1, 3]);
else
image.background = cat(3, image.background(:,:,1)', image.background(:,:,2)', image.background(:,:,3)');
end

% manually tested parameters for different images

if regexp(image.realImagePath, '.*powerlines.*')
	detector.suggested_sigma = -1;
elseif regexp(image.realImagePath, '.*foggy_road.*')
	detector.suggested_sigma = 3;
	detector.b_bounds = [10, 2];  % increase the bound is only ok for an edge in the middle
	detector.mask_width = 3;
elseif regexp(image.realImagePath, '.*bridge.*')
	detector.suggested_sigma = 3;
	detector.mask_width = 4;
elseif regexp(image.realImagePath, '.*fields.*')
	detector.suggested_sigma = 20;
	detector.mask_width = 5;
elseif regexp(image.realImagePath, '.*silouette.*')
	detector.suggested_sigma = 4;
	detector.mask_width = 6;
elseif regexp(image.realImagePath, '.*road_sky.*')
	detector.suggested_sigma = 20;
	detector.mask_width = 3;
elseif regexp(image.realImagePath, '.*corner_soccer.*')
	detector.b_bounds = [10, 2];
	detector.mask_width = 8;
	detector.suggested_sigma = 30;
else
	detector.suggested_sigma = -1;
	detector.num_strips = 1;
	detector.mask_width = 7;
	detector.max_scale = 6;  % for toyco, set it to 7
	detector.scale_offset = 1;
	detector.max_num_lps = 2^(detector.max_scale-detector.interp_scale+detector.scale_offset);
end

% set the detection strips

center_cols = floor(linspace(1, size(image.noisy, 2), detector.num_strips+2));
num_track_cols = min(diff(center_cols));

% num_track_cols denotes the extent to which the tracking from a strip will pursue
% if assert fails, you should reduce detector.num_strips
assert(num_track_cols > 2^(detector.max_scale+1));

% assign memory for recording detected edges

if run == 0
	image.sketch = zeros(size(image.background, 1), size(image.background, 2));
else
	image.sketch = image.sketch';
end
image.curve_coordinates.detected = cell(detector.num_strips, detector.max_scale);
image.curve_coordinates.left = cell(detector.num_strips, detector.max_scale);
image.curve_coordinates.right = cell(detector.num_strips, detector.max_scale);
image.pixel_responses = conv2(image.noisy, [ones(detector.mask_width, 1); -ones(detector.mask_width, 1)]/sqrt(2*detector.mask_width), 'valid');

tic();

% the main algorithm
% detection plus leftward and rightward tracking
directions = 1:2;
for lc = 2:numel(center_cols)-1
	% direction in which tracking procedure will go
	center_col = center_cols(lc) + 2^(detector.max_scale-1);

	% mark the detection strip / cosmetic operation which increases detect_track's runtime
	% though it looks messy here, sorry
	half_size = 2^(detector.max_scale-1);
	if isfield(palette, 'wo')
		wo = palette.wo;
	else
		wo = 0;
	end
	marked_columns = [-half_size-wo:-half_size+wo, half_size-wo:half_size+wo] + center_col;
	marked_columns = marked_columns(marked_columns <= size(image.background, 2));
	marked_columns = marked_columns(marked_columns >= 1);
	if isfield(palette, 'strip')
	image.background(:, marked_columns, 1) = palette.strip(1);
	image.background(:, marked_columns, 2) = palette.strip(2);
	image.background(:, marked_columns, 3) = palette.strip(3);
	end

	image = detect_track(image, detector, center_col, num_track_cols, directions, lc-1);
end

image = postprocessing(image, detector.num_strips, detector.mask_width, palette);

runtime = toc();
disp(['Sublinear Curved Edge Detector Runtime: ', num2str(runtime),' sec']);

% output the detected edges in different formats

if run == 1 || only_horizontal
figure(); imshow(uint8(image.background));
figure(); imshow(uint8(image.sketch));

imwrite(uint8(image.background), sprintf('%s_%s', name_str, 'tracked.png'));
% black on white with a bounding box
sketch = 255-image.sketch;
sketch(1, :) = 0;
sketch(end, :) = 0;
sketch(:, 1) = 0;
sketch(:, end) = 0;
imwrite(uint8(sketch), sprintf('%s_%s', name_str, 'sketch.png'));
end

% release persistent memory in csweep
csweep();

if only_horizontal
	break;
end

end
