%
% A MATLAB program for analysis of thresholded (=binary) canopy images
%
% Authors: Jaakko Heikkinen & Lauri Korhonen 2006-2009
% Citation: Korhonen, L. & Heikkinen, J. 2009. Automated analysis of in situ canopy images for the estimation of forest canopy cover.
% Forest Science 55(4): 323-334.
% Here size reduction is done based on circular filter.
%Constants
filetype='bmp'; %Which type of files are read
elem_size=10 %Diameter of the circular structuring element used in painting
true_focal=6.5; %Focal length of the camera, mm
ccd_hor=6.16; %Horizontal size of the ccd sensor
ccd_ver=4.62; %Vertical size of the ccd sensor
set_angle=40 %Angle of view that should be used, degrees. Larger than cameras diagonal AOV -> whole image is analyzed.
files=dir(['*.', filetype]); %Read all files of the specified type
results=cell(length(files),3); %Create array for the results
results{1,1}='Image';
results{1,2}='C_Closure';
results{1,3}='C_Cover';
%%%%%%%%%%%%%%% START LOOP %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
for h=1:length(files) %Loop goes through all images h
%%%%%%%%%%%%%%%%%% READ IMAGE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
fileid=files(h).name(1:length(files(h).name)-(length(filetype)+1));
binim=imread(files(h).name); %Read RGB image
[rows,cols,channels]=size(binim); %Read image dimensions
%%%%%% FIRST IMAGE: CIRCULAR MASK DETERMINATION %%%%%%%%%%
if h==1
centerx=round(cols/2);
centery=round(rows/2);
%Calculate AOVs in degrees
hor_angle=2*atan(ccd_hor/(2*true_focal))*180/pi;
ver_angle=2*atan(ccd_ver/(2*true_focal))*180/pi;
%Pixel dimensions in degrees
rowpix=ver_angle/rows;
colpix=hor_angle/cols;
mask=zeros(rows,cols);
maskpixels=0;
for r=1:rows
for c=1:cols
deltax=abs(centerx-c)*colpix; %Horizontal angle for pixel (r,c)
deltay=abs(centery-r)*rowpix; %Vertical angle for pixel (r,c)
d=sqrt(deltax^2+deltay^2);
if d<=set_angle/2
mask(r,c)=1;
maskpixels=maskpixels+1;
end
end
end
disp('Analyzing image:');
end %if
disp(fileid);
%%%%%%%%%%%%%%%%% PAINTING %%%%%%%%%%%%%%%%%%%%%%%%%%%
%Paint the crowns black using morphological opening and closing
elem=strel('disk',elem_size);
opeclo=imopen(binim,elem); %Because objects are black, do the closing with opening operation
opeclo=imclose(opeclo,elem);
%%%%%%%%%%%%%%% CANOPY CLOSURE %%%%%%%%%%%%%%%%%%%%%%%%%%%%
all=0;clos_black=0;cover_black=0;
clos_black=sum(sum(binim & mask));
cover_black=sum(sum(opeclo & mask));
cclosure=100-clos_black/maskpixels*100;
ccover=100-cover_black/maskpixels*100;
%%%%%%%%%%%%%% SAVE PAINTED IMAGE AND SPREADSHEET %%%%%%%%%%%%%%%%%%%%%
%Save painted images as bmp
opeclo=opeclo>0; %2-bit conversion
imwrite(opeclo, ['painted_',fileid,'_',num2str(set_angle),'_circ.bmp'],'bmp')
close all
%Save results to array
results{h+1,1}=files(h).name;
results{h+1,2}=cclosure;
results{h+1,3}=ccover;
end
results
xlswrite(['Circ_Bin_',num2str(set_angle),'.xls'],results);
clear all