function scale_space = blob(imname, start_perc, end_perc, steps) %% imname - the filename to read %% start_perc - the starting percent of the kernel to the image size %% end_perc - the ending percent of the kernel to the image size %% steps - the number of steps between the start and end percent %% %% A sample call: %% >> blob('butterfly.jpg', 1.5,20,20); %% reads 'butterfly.jpg', samples with kernel size ranging from 1.5% %% to 20% of image size, in 20 steps (plus 2 extra samplings) img = imread(imname); % convert to gray. img_float = double(rgb2gray(img)); image_size = size(img_float); scale_space = zeros(image_size(1), image_size(2), steps); max_results = zeros(image_size(1), image_size(2), steps); % make the kernel sigma = 3; kern_size = max(1,fix(6*sigma)); % as harris set it. kern = fspecial( 'log', kern_size, sigma ); norm_kern = sigma.^2 * kern; % normalized it. %figure(1); %imagesc(norm_kern); % the uppermost and lowermost scales should not be tested for maximums % so add in 2 more sample steps steps = steps + 2; % apply the filter for each level for i=1 : steps %resize, filter, scale back new_image_size = kern_size / percent_at_level(i, start_perc, end_perc, steps); resized_img = imresize( img_float, new_image_size / image_size(2), 'bilinear'); filtered_img = imfilter( resized_img, norm_kern, 'replicate'); filtered_img = filtered_img .^2; filtered_img = imresize( filtered_img, [image_size(1) image_size(2)], 'bilinear'); %dump info percent = [num2str( percent_at_level(i, start_perc, end_perc, steps)*100 ) '%']; start_size = [ num2str(image_size(1)) 'x' num2str(image_size(2))]; end_size = [ num2str( fix(new_image_size / image_size(2) * image_size(1))) 'x' num2str( fix(new_image_size / image_size(2) * image_size(2)))]; [' ' percent ' = ' start_size ' -> ' end_size] scale_space(:,:, i) = filtered_img; end % 2d nonmax suppression, taken from harris code possible_max_list = []; for i=1 : steps % match the dilated image and are also greater than the threshold. current_image = scale_space(:,:,i); %threshold = median(current_image(:)) threshold = 1000; %mask_size = fix(image_size(2) * (start_perc + (i-1) * step_size) / 1000); mask_size = 5; mx = ordfilt2(scale_space(:,:,i), mask_size^2, ones(mask_size)); % Grey-scale dilate. max_results(:,:,i) = (scale_space(:,:,i)==mx)&(scale_space(:,:,i)>threshold); % Find maxima. [r,c] = find(max_results(:,:,i)); % Find row,col coords. possible_max_list = [possible_max_list, {[r,c]}]; end %find max in scale space - 3d nonmax suppression max_x = []; max_y = []; max_r = []; for level=2 : steps - 1 current_max_level = possible_max_list(level); current_max_cell = current_max_level{1}; num_found = size( current_max_cell ); current_radius = fix(image_size(2) * percent_at_level(level, start_perc, end_perc, steps) * 0.4); %filter_size = (5-1) / 2; % instead of a static filter, scale with relative size of kernel filter_size = fix(image_size(2) * percent_at_level(level, start_perc, end_perc, steps) * 0.5); ['level: ' num2str(level) ' radius: ' num2str(current_radius) ' filter: ' num2str(filter_size)] for i=1 : num_found(1) current_point = current_max_cell(i,:); x = current_point(1); y = current_point(2); % drop the max positions that are too close to the edge of the image if(x <= filter_size || x > image_size(1)-filter_size) continue; end if(y <= filter_size || y > image_size(2)-filter_size) continue; end local_max = scale_space(x,y,level); upper_vals = [ scale_space(x-filter_size:x+filter_size, y-filter_size:y+filter_size, level+1) ]; upper_max = max(upper_vals(:)); lower_vals = [ scale_space(x-filter_size:x+filter_size, y-filter_size:y+filter_size, level-1) ]; lower_max = max(lower_vals(:)); if( (local_max > upper_max) && (local_max > lower_max)) max_x = [max_x, [x]]; max_y = [max_y, [y]]; max_r = [max_r, [current_radius]]; end end end %{ % display the image for level=1 : steps figure(level); %imshow( scale_space(:,:, level) ); subplot(1,2,1); imagesc( scale_space(:,:, level) ); subplot(1,2,2); imagesc( max_results(:,:, level) ); end %} figure(steps+1); %show_all_circles(img, max_y', max_x', max_r');%, color, ln_wid); % show_circles(img, max_y', max_x', max_r', [0 0 1], 1.5, [num2str(start_perc) '% -> ' num2str(end_perc) '% , ' num2str(steps) ' steps']); end function perc = percent_at_level(i, start_perc, end_perc, steps) step_size = (end_perc - start_perc) / (steps-1); % linear steps don't work well % instead, sample more often when kernel is small relative to image size perc = (((i-1) * step_size) / (end_perc - start_perc))^2 * (end_perc - start_perc) + start_perc; %perc = (start_perc + (i-1) * step_size); perc = perc / 100; end function show_circles(I, cx, cy, rad, color, ln_wid, text) %% I: image on top of which you want to display the circles %% cx, cy: column vectors with x and y coordinates of circle centers %% rad: column vector with radii of circles. %% The sizes of cx, cy, and rad must all be the same %% color: optional parameter specifying the color of the circles %% to be displayed (red by default) %% ln_wid: line width of circles (optional, 1.5 by default if nargin < 5 color = 'r'; end if nargin < 6 ln_wid = 1.5; end imshow(I); hold on; theta = 0:0.1:(2*pi+0.1); cx1 = cx(:,ones(size(theta))); cy1 = cy(:,ones(size(theta))); rad1 = rad(:,ones(size(theta))); theta = theta(ones(size(cx1,1),1),:); X = cx1+cos(theta).*rad1; Y = cy1+sin(theta).*rad1; line(X', Y', 'Color', color, 'LineWidth', ln_wid); %title(sprintf('%d circles', size(cx,1))); title(text); end