Image template matching using correlation - matlab

I am developing a template matching program in MATLAB. The code runs well, and finds the closest result. My first question, in this code, I am using the function corr2(). I would like to try a version using the formula (I tried to upload a picture of but I need 10 reputations).
I understand the formula itself, but I am not sure what variables should I use to use it. For example, what is exactly the m and n mean in my images where can I get them? In another words, what does the formula take as inputs?
Second question is, when I run the code I have now, it takes long, is there any thing I can change to speed it up?
Original = imread('Red.jpg'); % Read original image
Template = imread('temp.png'); % Read template image
OriDu = im2double(Original); % convert original image
TempDu = im2double(Template); % convert template
OriH = size(Original, 1); %height of the Original image
OriW = size(Original, 2); %width of the Original image
OriD = size(Original, 3); %colour depth
TempH = size(Template, 1); %height of the Template image
TempW = size(Template, 2); %width of the Template image
TempD = size(Template, 3); %colour depth
TempDu = reshape(TempDu, TempH*TempW, 3);
corr = 0; % to check the best correlation found
%% two for loops to go through the original image.
for i = 1:OriH-TempH
for j = 1:OriW-TempW
% take a segment of the original image( same size as the template size)
segment = OriDu(i: (i - 1) + TempH, j: (j - 1) + TempW, :);
segment = reshape(segment, TempH*TempW, 3);
output = corr2(TempDu, segment);
if output > corr
corr = output;
x = i;
y = j;
end
end
end
figure;
subplot(1,2,1), imshow(Template), title('Template');
subplot(1,2,2), imshow(OriDu(x:x+TempH, y:y+TempW, :)),title('Segment of the similar part');

Related

Updating histogram in a for-loop without growing y-data

I have had zero luck finding this elsewhere on the site, so here's my problem. I loop through about a thousand mat files, each with about 10,000 points of data. I'm trying to create an overall histogram of this data, but it's not very feasible to concatenate all this data to give to hist.
I was hoping to be able to create an N and Bin variable each loop using hist (y), then N and Bin would be recalculated on the next loop iteration by using hist(y_new). And so on and so on. That way the source data doesn't grow and when the loop finally ends, I can just use bar(). If this method wouldn't work, then I am very open-minded to other solutions.
Also, it is probably not safe to assume that the x data will remain constant throughout each iteration. I'm using 2012a.
Thanks for any help!!
I think the best solution here is to loop through your files twice: once to set the bins and once to do the histogram. But, if this is impossible in your case, here's a one shot solution that requires you to set the bin width beforehand.
clear; close all;
rng('default') % for reproducibility
% make example data
N = 10; % number of data files
M = 5; % length of data files
xs = cell(1,N);
for i = 1:N
xs{i} = trnd(1,1,M);
end
% parameters
width = 2;
% main
for i = 1:length(xs)
x = xs{i}; % "load data"
range = [min(x) max(x)];
binsPos = 0:width:range(2)+width;
binsNeg = fliplr( 0:-width:range(1)-width );
newBins = [binsNeg(1:end-1) binsPos];
newCounts = histc(x, newBins);
newCounts(end) = []; % last bin should always be zero, see help histc
if i == 1
counts = newCounts;
bins = newBins;
else
% combine new and old counts
allBins = min(bins(1), newBins(1)) : width : max(bins(end), newBins(end));
allCounts = zeros(1,length(allBins)-1);
allCounts(find(allBins==bins(1)) : find(allBins==bins(end-1))) = counts;
allCounts(find(allBins==newBins(1)) : find(allBins==newBins(end-1))) = ...
allCounts(find(allBins==newBins(1)) : find(allBins==newBins(end-1))) + newCounts;
bins = allBins;
counts = allCounts;
end
end
% check
figure
bar(bins(1:end-1) + width/2, counts)
xFull = [xs{:}];
[fullCounts] = histc(xFull, bins);
fullCounts(end) = [];
figure
bar(bins(1:end-1) + width/2, fullCounts)

Spheroids detction from Images

I need to find the blobs from the below image.
The major problem is background. background doesn't have uniform intensity. I tried couple of things like thresholding and edge detection in MATLAB but couldn't able to find a better ways to segment out all spheroids. I need to extract the blobs and I need to find the area of each blobs. Does anyone know how to work-around with this kind of background?
Edit (07/02/17):
As suggested by Spektre I tried Following things in MATLAB.
Method 1:
img_original = imread('~/my_image.jpg'); %Read image
img_ch = single(img_original(:,:,2)); %Pick one channel( here its green)
g = fspecial('gaussian',200,100); %Kernel matrix to make the img blurr
con_img = conv2(img_ch,g,'same'); %2D convolution, this wil make the img blurr
sub_img = (con_img - img_ch); %Simple matrix subtraction
sub_img(sub_img <= 10) = 0; %Thresholding
sub_img(sub_img ~= 0) = 1;
fil_sub = imfill(sub_img,'holes'); %Fill the regions
imgfilt = imfilter(fil_sub, ones(3)); %run filter using 3by3 matrx
imgfilt(imgfilt < 8) = 0; %Reduce noisy pixels by thresholding
mfilt_img = (medfilt2(imgfilt)); %reduce unwanted pixels
img = img_ch;
img(mfilt_img ~= 0) = 255;
img2 = img_ch;
img2(img2 < 70) = 0; %Threshold for darker pixels which are left out from above methode.
img(img2 ==0) = 255;
disp_img = img_original(:,:,1);
disp_img(img ==255) = 255;
img_original(:,:,1) = disp_img;
figure, imshow(img_original)
I got the segments but still not good enough I think. This method gave good segments in the high intensity background, Even if I reduce the threshold value segments are not clear in the darker background and brightest pixels in the blobs are excluded.
Method 2:
img_original = imread('~/cancer_cells/Snap-10234.jpg'); %Read image
img_ch = single(img_original(:,:,2)); %Pick one channel( here its green)
clear new_matcel cur_img matcel avg_matrx
s=3; % Set size of the square window
mat_img = img_ch; % Working image channel
% resize the working matrix so that the dimensions matches
resize_img = resizem(mat_img,round(size(mat_img)/s)*s);
% convert matrix into small s x s matrix and save each in cells
window_c = ones(1,size(resize_img,1)/s) * s;
window_r = ones(1,size(resize_img,2)/s) * s;
mat_cel = mat2cell(resize_img,window_c,window_r);
new_matcel = cell(size(mat_cel)); % initialize new variable
% get the average value for each window and replace the actual by avg value
for i = 1:size(mat_cel,1)
for j = 1:size(mat_cel,2)
cur_img = mat_cel{i,j};
avg_value = mean(mean(cur_img));
new_matcel{i,j} = ones(s) * avg_value;
end
end
avg_matrx = cell2mat(new_matcel); % convert cells to matrix
image_sub = (abs(resize_img - avg_matrx)); % take the absolute difference
image_sub(image_sub < 7) = 0; % thresholding
image_sub(image_sub~=0) = 1;
image_sub = bwmorph(image_sub,'bridge');% fill gaps
image_sub = imfill(image_sub,'holes'); % fill the bounded regioons
% image_sub(image_sub == 1) = 255;
image_sub = resizem(image_sub,size(img_ch)); % resize to original size
disp_img = img_original(:,:,1);
disp_img(image_sub == 1) = 255;
img_original(:,:,1) = disp_img;
figure, imshow(img_original)
Much better segmented image:
even brighter pixels are included in the segment. Thanks to Spektre.
Is there a way to improve the above code? or any other idea to get more precise segments?
Thanks.

Extracting feature points from flow lines and clustering them?

I'm trying to make a reliable passenger counting system using matlab, the camera will be fixed and above the door. I a able to get flow lines using Lucas Kanade optical flow, the lines represent the people's motion. I want to:
extract from these lines only the end points, if the line is long enough (the lines matrix contains all the points, even say a point on some random part of floor which will not have changed)
Cluster these 'good points' and get the centroids of the clustsers, representing people
Create bounding boxes of a fixed size on those cluster centers and send them to the multiple object KLT tracking program.
Would anyone happen to show me a good way to extract the points I want from the line matrix? My matlab syntax is atrocious and I'm running out of time to get this done, its for a uni project. Thanks in advance!
%example
videoReader = vision.VideoFileReader('5Converted.avi','ImageColorSpace','Intensity','VideoOutputDataType','uint8');
converter = vision.ImageDataTypeConverter;
opticalFlow = vision.OpticalFlow('ReferenceFrameDelay', 1);
opticalFlow.OutputValue = 'Horizontal and vertical components in complex form';
shapeInserter = vision.ShapeInserter('Shape','Lines','BorderColor','Custom', 'CustomBorderColor', 255);
videoPlayer = vision.VideoPlayer('Name','Motion Vector');
while ~isDone(videoReader)
frame = step(videoReader);
im = step(converter, frame);
of = step(opticalFlow, im);
[lines, trackedPoints] = getFlowLines(of, 20);
if ~isempty(lines)
out = step(shapeInserter, im, lines);
end
end
release(videoPlayer);
release(videoReader);
And this is the GetFLowLines Function (slightly modified version of an example):
> function [vel_Lines, allTrackedPoints] = getFlowLines(vel_Values,
> scaleFactor) %Modified function based on Matlab's
> 'videooptflowlines.m' helper function
>
> persistent first_time; persistent X; persistent Y; persistent RV;
> persistent CV; if isempty(first_time)
> first_time = 1;
> %% user may change the following three parameters
> borderOffset = 5;
> decimFactorRow = 5;
> decimFactorCol = 5;
> %%
> [R C] = size(vel_Values);
> RV = borderOffset:decimFactorRow:(R-borderOffset);
> CV = borderOffset:decimFactorCol:(C-borderOffset);
> [Y X] = meshgrid(CV,RV); end
>
> tmp = vel_Values(RV,CV); tmp = tmp.*scaleFactor; vel_Lines = [Y(:)
> X(:) Y(:)+real(tmp(:)) X(:)+imag(tmp(:))]; allTrackedPoints =
> [Y(:)+real(tmp(:)) X(:)+imag(tmp(:))];

Manual Mean Filtering

Before I begin, I would just like to clarify that I understand how to use kernels and the conv2() function in order to mean filter an image, but I have been tasked with doing this manually by calling up each pixel.
My goal here is to call up each pixel, find its neighbors, average them out, and replace previous values with the acquired mean, without using kernels or conv2(). I have so far attempted to find the neighbors of each pixel using
for
I = 1:512;
for
J = 1:683;
A = myimage;
neighbor_offsets = [-1, A, 1, -A, A + 1, -A + 1, -A-1, A - 1];
idx = [I J];
neighbors = bsxfun(#plus,idx,neighbor_offsets);
but it does not seem to work, and I am a bit lost in trying to fix it. I think I could finish the job if I were able to get the neighbors by using something like
sum(neighbors) / 9
then replace the previous values with that answer, but please correct me if I'm. I've developed somewhat of a tendency to ask poor questions, so if anything is unclear, please let me know so I can clarify for you. Thanks
Example below treats pixels at the edge in the manner that it only considers pixels that are inside the image. For example when program is computing average with kernel dy = (-1:1) and dx = (-1:1) on top-left corner, it only considers top-left corner and its immediate 3 neighbors (right, right-bottom, right), and does average of those 4 pixels.
I would strongly advise you to test every line separately in Matlab's command window to see it's behavior!
% find image size
imsz = size( myimage );
% initialize output image
imavg = zeros( imsz );
% iterate over pixels
for yy = 1 : imsz(1)
for xx = 1 : imsz(2)
% define rectangle-kernel width
dy = (-1:1); % 1 up, to 1 down and ...
dx = (-1:1); % 1 left, to 1 right from current pixel
% get indexes of image
indy = yy + dy;
indx = xx + dx;
% [!!!] keep indexes that are inside image
indy = indy( indy>0 & indy<=imsz(1) );
indx = indx( indx>0 & indx<=imsz(2) );
% create all the pairings of chosen indexes
[ IY, IX ] = meshgrid( indy, indx );
% take all values of chosen pixels
pixs = myimage( sub2ind(imsz,IY(:),IX(:)) );
% save mean of chosen pixels to the given location
imavg(yy,xx) = mean( pixs );
end
end
You can create function from the above code with creating mean_filter.m file with this contents:
function imagv = mean_filter( myimage )
% code from above ...
You can call function from command window by positioning yourself in the directory where it's at and executing filtered = mean_filter( myimage );.
You can repeatedly filter the same image with:
filtered_3_times = myimage;
for ii = 1 : 3
filtered_3_times = mean_filter( filtered_3_times );
end

Rolling window for averaging using MATLAB

I have the following code, pasted below. I would like to change it to only average the 10 most recently filtered images and not the entire group of filtered images. The line I think I need to change is: Yout(k,p,q) = (Yout(k,p,q) + (y.^2))/2;, but how do I do it?
j=1;
K = 1:3600;
window = zeros(1,10);
Yout = zeros(10,column,row);
figure;
y = 0; %# Preallocate memory for output
%Load one image
for i = 1:length(K)
disp(i)
str = int2str(i);
str1 = strcat(str,'.mat');
load(str1);
D{i}(:,:) = A(:,:);
%Go through the columns and rows
for p = 1:column
for q = 1:row
if(mean2(D{i}(p,q))==0)
x = 0;
else
if(i == 1)
meanvalue = mean2(D{i}(p,q));
end
%Calculate the temporal mean value based on previous ones.
meanvalue = (meanvalue+D{i}(p,q))/2;
x = double(D{i}(p,q)/meanvalue);
end
%Filtering for 10 bands, based on the previous state
for k = 1:10
[y, ZState{k}] = filter(bCoeff{k},aCoeff{k},x,ZState{k});
Yout(k,p,q) = (Yout(k,p,q) + (y.^2))/2;
end
end
end
% for k = 2:10
% subplot(5,2,k)
% subimage(Yout(k)*5000, [0 100]);
% colormap jet
% end
% pause(0.01);
end
disp('Done Loading...')
The best way to do this (in my opinion) would be to use a circular-buffer to store your images. In a circular-, or ring-buffer, the oldest data element in the array is overwritten by the newest element pushed in to the array. The basics of making such a structure are described in the short Mathworks video Implementing a simple circular buffer.
For each iteration of you main loop that deals with a single image, just load a new image into the circular-buffer and then use MATLAB's built in mean function to take the average efficiently.
If you need to apply a window function to the data, then make a temporary copy of the frames multiplied by the window function and take the average of the copy at each iteration of the loop.
The line
Yout(k,p,q) = (Yout(k,p,q) + (y.^2))/2;
calculates a kind of Moving Average for each of the 10 bands over all your images.
This line calculates a moving average of meanvalue over your images:
meanvalue=(meanvalue+D{i}(p,q))/2;
For both you will want to add a buffer structure that keeps only the last 10 images.
To simplify it, you can also just keep all in memory. Here is an example for Yout:
Change this line: (Add one dimension)
Yout = zeros(3600,10,column,row);
And change this:
for q = 1:row
[...]
%filtering for 10 bands, based on the previous state
for k = 1:10
[y, ZState{k}] = filter(bCoeff{k},aCoeff{k},x,ZState{k});
Yout(i,k,p,q) = y.^2;
end
YoutAvg = zeros(10,column,row);
start = max(0, i-10+1);
for avgImg = start:i
YoutAvg(k,p,q) = (YoutAvg(k,p,q) + Yout(avgImg,k,p,q))/2;
end
end
Then to display use
subimage(Yout(k)*5000, [0 100]);
You would do sth. similar for meanvalue