function decode2(bar)

format short

% decode2(img): Decode barcode in image img

% Barcode 128c: four different run lengths, the relative widths are 1 2 3 4

[barh, barw] = size(bar);
slice = double(bar(round(barh/2),:));
sliceh = interp(slice,16);
thres = mean(sliceh);
sliceb = sliceh > thres;
runs = [];
m = 1;
for k=2:length(sliceb)
	if (sliceb(k)~=sliceb(m))
		runs = [runs k-m];
		m = k;
	end
end
color = sliceb(1);	% 0=black, 1=white
%figure(1),stem(runs);

codetab = [ ...
2 1 2 2 2 2;	% 00
2 2 2 1 2 2;
2 2 2 2 2 1;
1 2 1 2 2 3;
1 2 1 3 2 2;
1 3 1 2 2 2;
1 2 2 2 1 3;
1 2 2 3 1 2;
1 3 2 2 1 2;
2 2 1 2 1 3;
2 2 1 3 1 2;
2 3 1 2 1 2;
1 1 2 2 3 2;
1 2 2 1 3 2;
1 2 2 2 3 1;
1 1 3 2 2 2;
1 2 3 1 2 2;
1 2 3 2 2 1;
2 2 3 2 1 1;
2 2 1 1 3 2;
2 2 1 2 3 1;
2 1 3 2 1 2;
2 2 3 1 1 2;
3 1 2 1 3 1;
3 1 1 2 2 2;
3 2 1 1 2 2;
3 2 1 2 2 1;
3 1 2 2 1 2;
3 2 2 1 1 2;
3 2 2 2 1 1;
2 1 2 1 2 3;
2 1 2 3 2 1;
2 3 2 1 2 1;
1 1 1 3 2 3;
1 3 1 1 2 3;
1 3 1 3 2 1;
1 1 2 3 1 3;
1 3 2 1 1 3;
1 3 2 3 1 1;
2 1 1 3 1 3;
2 3 1 1 1 3;
2 3 1 3 1 1;
1 1 2 1 3 3;
1 1 2 3 3 1;
1 3 2 1 3 1;
1 1 3 1 2 3;
1 1 3 3 2 1;
1 3 3 1 2 1;
3 1 3 1 2 1;
2 1 1 3 3 1;
2 3 1 1 3 1;
2 1 3 1 1 3;
2 1 3 3 1 1;
2 1 3 1 3 1;
3 1 1 1 2 3;
3 1 1 3 2 1;
3 3 1 1 2 1;
3 1 2 1 1 3;
3 1 2 3 1 1;
3 3 2 1 1 1;
3 1 4 1 1 1;
2 2 1 4 1 1;
4 3 1 1 1 1;
1 1 1 2 2 4;
1 1 1 4 2 2;
1 2 1 1 2 4;
1 2 1 4 2 1;
1 4 1 1 2 2;
1 4 1 2 2 1;
1 1 2 2 1 4;
1 1 2 4 1 2;
1 2 2 1 1 4;
1 2 2 4 1 1;
1 4 2 1 1 2;
1 4 2 2 1 1;
2 4 1 2 1 1;
2 2 1 1 1 4;
4 1 3 1 1 1;
2 4 1 1 1 2;
1 3 4 1 1 1;
1 1 1 2 4 2;
1 2 1 1 4 2;
1 2 1 2 4 1;
1 1 4 2 1 2;
1 2 4 1 1 2;
1 2 4 2 1 1;
4 1 1 2 1 2;
4 2 1 1 1 2;
4 2 1 2 1 1;
2 1 2 1 4 1;
2 1 4 1 2 1;
4 1 2 1 2 1;
1 1 1 1 4 3;
1 1 1 3 4 1;
1 3 1 1 4 1;
1 1 4 1 1 3;
1 1 4 3 1 1;
4 1 1 1 1 3;
4 1 1 3 1 1;
1 1 3 1 4 1;		% 99
1 1 4 1 3 1;		% 100: code B
3 1 1 1 4 1;		% 101: code A
4 1 1 1 3 1;		% 102: FNC 1
2 1 1 4 1 2;		% 103: START code A
2 1 1 2 1 4;		% 104: START code B
2 1 1 2 3 2;		% 105: START code C
2 3 3 1 1 1 ];		% 106: STOP + 2
starta = 103;
startb = 104;
startc = 105;
stop = 106;

%color
detect = zeros(0,4);
for k=1:length(runs)-6
	if color==0
		[mse,est] = match2(runs(k:k+5),codetab(starta+1,:));
		detect = [detect; k mse est starta];
		[mse,est] = match2(runs(k:k+5),codetab(startb+1,:));
		detect = [detect; k mse est startb];
		[mse,est] = match2(runs(k:k+5),codetab(startc+1,:));
		detect = [detect; k mse est startc];
		[mse,est] = match2(runs(k:k+6),fliplr([codetab(stop+1,:) 2]));
		detect = [detect; k mse est stop];
	end
	color = 1-color;
end
detect = sortrows(detect, [2 1]);	% sort by smallest MSE first
%figure(2),stem(1./detect(:,2));

detect(1,:)
est = detect(1,3);	% Estimated width of the narrowest bar (module width?)
charset = detect(1,4);	% Charset code
estsum = est;
estnum = 1;

format short g
widths = zeros(0,5);
for k=detect(1,1):length(runs)
	l = runs(k) ./ [1 2 3 4];
	l = l - est;			% Find difference
	l = l / est;			% Normalize difference
	l = l .^ 2;			% Squared error
	[tmp,w] = min(l);		% Index of the smallest MSE
	s = 1./sort(l);
	widths = [widths; w s(1)/s(2) runs(k)/w est runs(k)/w-est];
	estsum = estsum + runs(k)/w;
	estnum = estnum + 1;
%	est = estsum/estnum;		% Update estimate of module width
end

[lenwidth,tmp] = size(widths);

%figure(3),plot(widths(:,3)-widths(:,4));
disp('                    Estimated  Confidence  Module width  Estimated module  Pixel');
disp('                    bar label              (pixels*16)   width (pixels*16) error*16');
tmp = [(1:lenwidth)' widths];
%sortrows(tmp,3)
tmp
min(widths(:,2))

resultn = [];
results = [];
k = 1;
while k<=lenwidth-5
	m = 1;
	while max(abs(widths(k:k+5,1)'-codetab(m,:)))~=0
		m = m+1;
		if m>length(codetab)
			break
		end
	end
	if m>length(codetab)
		k
		break
	end
	code = m-1;
	resultn = [resultn code];
	if code>=100
		results = [results sprintf('*', code)];
	else
		results = [results sprintf('%02i', code)];
	end
	if code==stop
		break
	end
	k = k + 6;
end

resultn

checksum = charset;
for k=2:length(resultn)-2
	checksum = mod((k-1)*resultn(k)+checksum,103);
end

if checksum ~= resultn(length(resultn)-1)
	warning('CHECKSUM ERROR')
else
	disp('Checksum OK');
end

results

if length(results)<55
	return
end
disp(sprintf('Versionumero     : %s', results(2)));
disp(sprintf('Saajan tilinumero: %s', results(3:16)));
disp(sprintf('Markat/eurot     : %s', results(17:22)));
disp(sprintf('Pennit/sentit    : %s', results(23:24)));
disp(sprintf('Viitenumero      : %s', results(25:44)));
disp(sprintf('Eräpäivä         : %s', results(45:50)));
disp(sprintf('Varalla          : %s', results(51:54)));
disp(sprintf('Tarkiste 1       : %s', results(55)));
