Problems with initializing CamShift algorithm - matlab

I use matlab to implement a tracker using cam shift. I need to implement it myself hence I'm not using the built in method.
I let the user choose the object to track and after the first iteration the convergence makes it start tracking a different object. pictures speaks louder than words so:
I choose my face in the first frame:
It converges to my shoulder and starting tracking it:
Now the tracking is overall ok throughout the video so I think the issue is in the initialization phase.
SomeCode: Get position from user:
function [pos] = getObjectPosition(F)
f = figure;
imshow(F);
pos = getPosition(imrect(gca));
close(f);
end
Main Loop:
firstFrame = readFrame(input);
pos = getObjectPosition(firstFrame);
while hasFrame(input)
% init next frame
nextFrame = readFrame(input);
[currFrameHSV, ~, ~] = rgb2hsv(nextFrame);
frameHue = double(currFrameHSV(:,:,1));
% init while loop vars
prevX = -1;
prevY = -1;
i = 0;
while (i < numOfIterations) && ~(prevX == pos(1) && prevY == pos(2))
% updating the curr iteration number
i = i + 1;
% getting search window location and dimensions
envRect = round(getEnvRect(pos,pos(4)/yRatio,pos(3)/xRatio,height,width));
[X,Y] = meshgrid(envRect(1):envRect(1) + envRect(3),...
envRect(2):envRect(2) + envRect(4));
% getting the sub image
I = imcrop(frameHue,envRect);
M00 = sum(sum(I));
M10 = sum(sum(X.*I));
M01 = sum(sum(Y.*I));
% getting center mass location
Xc = round(M10/M00);
Yc = round(M01/M00);
% updating object position
prevX = pos(1);
prevY = pos(2);
pos(1) = floor(Xc - pos(3)/2);
pos(2) = floor(Yc - pos(4)/2);
end
% adding the object's bounding box to the frame to write
% show the image
end
getEnv method:
function [ envRect ] = getEnvRect( feature,hShift,wShift,rows,cols )
hEnvSize = feature(4) + 2*hShift;
wEnvSize = feature(3) + 2*wShift;
xPatch = feature(1);
xEnv = max(1, xPatch - wShift);
yPatch = feature(2);
yEnv = max(1, yPatch - hShift);
width = min(cols, xEnv + wEnvSize) - xEnv;
height = min(rows, yEnv + hEnvSize) - yEnv;
envRect = [xEnv, yEnv, width, height];
end

Related

Motion History Image in Matlab

I am working on a project about action recognition using motion history images in matlab. I am new to this field. I did background subtraction using frame differencing method to get images that have only the moving person. Now I want to compute MHI. I found the following code for MHI. I did not understand what is fg{1} and how to use it. Any help will be appreciated. Thank you.
vid= VideoReader('PS7A1P1T1.avi');
n = vid.NumberOfFrames;
fg = cell(1, n);
for i = 1:n
frame = read(vid,i);
frame = rgb2gray(frame);
fg{i} = frame;
end
%---------------------------------------------------------------
%background subtraction using frame differencing method
thresh = 25;
bg = fg{1}; % read in 1st frame as background frame
% ----------------------- set frame size variables -----------------------
fr_size = size(bg);
width = fr_size(2);
height = fr_size(1);
% --------------------- process frames -----------------------------------
for i = 2:n
fr = fg{i}; % read in frame
fr_diff = abs(double(fr) - double(bg)); % cast operands as double to avoid negative overflow
for j=1:width % if fr_diff > thresh pixel in foreground
for k=1:height
if ((fr_diff(k,j) > thresh))
fg {i}(k,j) = fr(k,j);
else
fg {i}(k,j) = 0;
end
end
end
bg = fr;
imshow(fg{i})
end
out = MHI(fg);
//----------------------------------------
function MHI = MHI(fg)
% Initialize the output, MHI a.k.a. H(x,y,t,T)
MHI = fg;
% Define MHI parameter T
T = 15; % # of frames being considered; maximal value of MHI.
% Load the first frame
frame1 = fg{1};
% Get dimensions of the frames
[y_max x_max] = size(frame1);
% Compute H(x,y,1,T) (the first MHI)
MHI{1} = fg{1} .* T;
% Start global loop for each frame
for frameIndex = 2:length(fg)
%Load current frame from image cell
frame = fg{frameIndex};
% Begin looping through each point
for y = 1:y_max
for x = 1:x_max
if (frame(y,x) == 255)
MHI{frameIndex}(y,x) = T;
else
if (MHI{frameIndex-1}(y,x) > 1)
MHI{frameIndex}(y,x) = MHI{frameIndex-1}(y,x) - 1;
else
MHI{frameIndex}(y,x) = 0;
end
end
end
end
end
fg{1} is most likely the first frame of a grayscale video. Given your comments, you are using the VideoReader class to read in frames. As such, read in each frame individually, convert to grayscale then place on a cell in a cell array. When you're done, call the script.
Here's the code modified from your comments to suit this task:
vid = VideoReader('PS7A1P2T1.avi');
n = vid.NumberOfFrames;
fg = cell(1, n);
for i = 1:n
frame = read(vid,i);
frame = rgb2gray(frame);
fg{i} = frame;
end
You can then call the MHI script:
out = MHI(fg);

how to determin the North west radiant score(270-360 degree) to decide score

I have a code in matlab as below. the code is very confusing. Now i need to decide the north west part of the disk (270-360) degree if the fuel type are f3 and f5, then it is a shia. i need to return yes or no for shia.
% base path
fireline_path = 'Documents/fireline/';
% EOSD landcover file
landcover_file = fullfile(fireline_path,'landcover/EOSD/083O_lc_1/083O_lc_1.TIF');
[landcover,cmap_landcover,R_landcover0] = geotiffread(landcover_file);
proj_landcover = geotiffinfo(landcover_file);
pixelsize = 25; % 25m UTM grid
% trim raster to area around town of Lake
i_trim = 3001:3500;
j_trim = 3001:3500;
landcover = landcover(i_trim,j_trim);
[x11,y11] = pix2map(R_landcover0,i_trim(1),j_trim(1));
R_landcover = makerefmat(x11,y11,pixelsize,-pixelsize);
% read in damaged propeties and get their locations in grid
damage_shapefile = fullfile(fireline_path,'work/slavelake/damaged_properties_SL.shp');
damage = shaperead(damage_shapefile);
x_damage = [damage(~strcmp({damage.Damage},'Undamaged')).X];
y_damage = [damage(~strcmp({damage.Damage},'Undamaged')).Y];
[i_damage, j_damage] = map2pix(R_landcover,x_damage,y_damage);
ind_damage = sub2ind(size(landcover),round(i_damage),round(j_damage));
% create landcover -> fuel mappings
fuelmappings = zeros(max(landcover(:)),1);
ind_vegclass = [52,81,82,83,100,211,221,231]; % indicies of classes present that are vegetation
veg_loadings = [...
3,...'Shrub Low'
3,...'Wetland-treed'
3,...'Wetland-shrub'
1,...'Wetland-herb'
1,...'Herbs'
5,...'Coniferous-dense'
5,...'Broadleaf-dense'
5]; %Mixedwood-dense'
fuelmappings(ind_vegclass) = veg_loadings;
landcover(landcover==0) = 1; % set nodata cells to 1, this will map to no fuel
fuelmap = fuelmappings(landcover);
% create binary fuel map (F3 or F5)
fuelmapbw = fuelmap>=3;
%%
% flag pixels within 1/2 mile of dense areas
shiasum = zeros(size(landcover)); % initialize summary
disp('Percent of damaged/destroyed properties in SHIA:')
densitythresholds = .25;%[.75, .67, .5, .33, .25];
for densitythreshold = densitythresholds
% create filter to calculate shia (create a disk and then zero out unwanted
% pixels)
shiadistmiles = .5; %miles
shiadistmeters = shiadistmiles*unitsratio('meters','miles');
shiadistpix = shiadistmeters/pixelsize;
hshia = fspecial('disk',shiadistpix);
hshia(1:floor(shiadistpix),:) = 0;
xy = -floor(shiadistpix):floor(shiadistpix);
[X,Y] = meshgrid(xy,fliplr(xy));
f70 = -tan(deg2rad(70))*X;
hshia(Y<f70) = 0;
f20 = -tan(deg2rad(20))*X;
hshia(Y>f20) = 0;
hshia(hshia>0) = 1;
hshia = hshia/sum(hshia(:));
close all
shiavals = filter2(hshia,fuelmapbw);
shia = filter2(hshia,fuelmapbw) > densitythreshold;
linkimage(fuelmapbw,shia)
hold on
plot(j_damage,i_damage,'x')
hold off
propsinshia = sum(shia(ind_damage))/numel(ind_damage);
disp(['With threshold of ' num2str(densitythreshold) ':'])
disp(propsinshia * 100)
outfile = [fireline_path 'shia/SlaveLake_'...
num2str(densitythreshold*100,'%02d') '.tif'];
geotiffwrite(outfile,shia,R_landcover,...
'CoordRefSysCode',proj_landcover.GeoTIFFCodes.PCS)
shiasum = shiasum+shia;
end
lookup = [0 fliplr(densitythresholds) * 100];
shia = lookup(shiasum+1);
outfile = [fireline_path 'shia/SlaveLake_v2.tif'];
geotiffwrite(outfile,uint8(shia),R_landcover,...
'CoordRefSysCode',proj_landcover.GeoTIFFCodes.PCS)

Change input video from saved video to streaming video for manipulation

I downloaded this code from MIT's video magnification lab: http://people.csail.mit.edu/mrub/evm/#code
Except it currently only runs on saved videos. We wanted to change it so that we can have a live video set up.
The matlab code is as follows:
dataDir = './data';
resultsDir = 'ResultsSIGGRAPH2012';
mkdir(resultsDir);
inFile = fullfile(dataDir,'face2.mp4');
fprintf('Processing %s\n', inFile);
% Motion
amplify_spatial_lpyr_temporal_butter(inFile,resultsDir,20,80, ...
0.5,10,30, 0);
The amplify_spatial_lpyr_temporal_butter matlab code is:
function amplify_spatial_lpyr_temporal_butter(vidFile, outDir ...
,alpha, lambda_c, fl, fh ...
,samplingRate, chromAttenuation)
[low_a, low_b] = butter(1, fl/samplingRate, 'low');
[high_a, high_b] = butter(1, fh/samplingRate, 'low');
[~,vidName] = fileparts(vidFile);
outName = fullfile(outDir,[vidName '-butter-from-' num2str(fl) '-to-' ...
num2str(fh) '-alpha-' num2str(alpha) '-lambda_c-' num2str(lambda_c) ...
'-chromAtn-' num2str(chromAttenuation) '.avi']);
% Read video
vid = VideoReader(vidFile);
% Extract video info
vidHeight = vid.Height;
vidWidth = vid.Width;
nChannels = 3;
fr = vid.FrameRate;
len = vid.NumberOfFrames;
temp = struct('cdata', ...
zeros(vidHeight, vidWidth, nChannels, 'uint8'), ...
'colormap', []);
startIndex = 1;
endIndex = len-10;
vidOut = VideoWriter(outName);
vidOut.FrameRate = fr;
open(vidOut)
% firstFrame
temp.cdata = read(vid, startIndex);
[rgbframe,~] = frame2im(temp);
rgbframe = im2double(rgbframe);
frame = rgb2ntsc(rgbframe);
[pyr,pind] = buildLpyr(frame(:,:,1),'auto');
pyr = repmat(pyr,[1 3]);
[pyr(:,2),~] = buildLpyr(frame(:,:,2),'auto');
[pyr(:,3),~] = buildLpyr(frame(:,:,3),'auto');
lowpass1 = pyr;
lowpass2 = pyr;
pyr_prev = pyr;
output = rgbframe;
writeVideo(vidOut,im2uint8(output));
nLevels = size(pind,1);
for i=startIndex+1:endIndex
progmeter(i-startIndex,endIndex - startIndex + 1);
temp.cdata = read(vid, i);
[rgbframe,~] = frame2im(temp);
rgbframe = im2double(rgbframe);
frame = rgb2ntsc(rgbframe);
[pyr(:,1),~] = buildLpyr(frame(:,:,1),'auto');
[pyr(:,2),~] = buildLpyr(frame(:,:,2),'auto');
[pyr(:,3),~] = buildLpyr(frame(:,:,3),'auto');
%% temporal filtering
lowpass1 = (-high_b(2) .* lowpass1 + high_a(1).*pyr + ...
high_a(2).*pyr_prev)./high_b(1);
lowpass2 = (-low_b(2) .* lowpass2 + low_a(1).*pyr + ...
low_a(2).*pyr_prev)./low_b(1);
filtered = (lowpass1 - lowpass2);
pyr_prev = pyr;
%% amplify each spatial frequency bands according to Figure 6 of our paper
ind = size(pyr,1);
delta = lambda_c/8/(1+alpha);
% the factor to boost alpha above the bound we have in the
% paper. (for better visualization)
exaggeration_factor = 2;
% compute the representative wavelength lambda for the lowest spatial
% freqency band of Laplacian pyramid
lambda = (vidHeight^2 + vidWidth^2).^0.5/3; % 3 is experimental constant
for l = nLevels:-1:1
indices = ind-prod(pind(l,:))+1:ind;
% compute modified alpha for this level
currAlpha = lambda/delta/8 - 1;
currAlpha = currAlpha*exaggeration_factor;
if (l == nLevels || l == 1) % ignore the highest and lowest frequency band
filtered(indices,:) = 0;
elseif (currAlpha > alpha) % representative lambda exceeds lambda_c
filtered(indices,:) = alpha*filtered(indices,:);
else
filtered(indices,:) = currAlpha*filtered(indices,:);
end
ind = ind - prod(pind(l,:));
% go one level down on pyramid,
% representative lambda will reduce by factor of 2
lambda = lambda/2;
end
%% Render on the input video
output = zeros(size(frame));
output(:,:,1) = reconLpyr(filtered(:,1),pind);
output(:,:,2) = reconLpyr(filtered(:,2),pind);
output(:,:,3) = reconLpyr(filtered(:,3),pind);
output(:,:,2) = output(:,:,2)*chromAttenuation;
output(:,:,3) = output(:,:,3)*chromAttenuation;
output = frame + output;
output = ntsc2rgb(output);
% filtered = rgbframe + filtered.*mask;
output(output > 1) = 1;
output(output < 0) = 0;
writeVideo(vidOut,im2uint8(output));
end
close(vidOut);
end
We are trying to get it to work with a streaming video input, but don't really know where to start. We are somewhat familiar with programming but not so familiar with Matlab and so don't really know where to look for such answers.
Any help would be greatly appreciated.

Matlab - Failures of function to detect collisions between line segments and circle

Many questions exist already covering how to detect collisions between a line segment and a circle.
In my code, I am using Matlab's linecirc function, then comparing the intersection points it returns with the ends of my line segments, to check that the points are within the line (linecirc assumes an infinite line, which I don't have/want).
Copying and adding some sprintf calls to the linecirc function shows that it is calculating points as intended. These seem to be being lost by my function.
My code is below:
function cutCount = getCutCountHex(R_g, centre)
clf;
cutCount = 0;
% Generate a hex grid
Dg = R_g*2;
L_b = 62;
range = L_b*8;
dx = Dg*cosd(30);
dy = 3*R_g;
xMax = ceil(range/dx); yMax = ceil(range/dy);
d1 = #(xc, yc) [dx*xc dy*yc];
d2 = #(xc, yc) [dx*(xc+0.5) dy*(yc+0.5)];
centres = zeros((xMax*yMax),2);
count = 1;
for yc = 0:yMax-1
for xc = 0:xMax-1
centres(count,:) = d1(xc, yc);
count = count + 1;
centres(count, :) = d2(xc, yc);
count = count + 1;
end
end
for i=1:size(centres,1)
centres(i,:) = centres(i,:) - [xMax/2 * dx, yMax/2 * dy];
end
hold on
axis equal
% Get counter for intersected lines
[VertexX, VertexY] = voronoi(centres(:,1), centres(:,2));
numLines = size(VertexX, 2);
for lc = 1:numLines
segStartPt = [VertexX(1,lc) VertexY(1,lc)];
segEndPt = [VertexX(2,lc) VertexY(2,lc)];
slope = (segEndPt(2) - segStartPt(2))/(segEndPt(1) - segStartPt(1));
intercept = segEndPt(2) - (slope*segEndPt(1));
testSlope = isinf(slope);
if (testSlope(1)==1)
% Pass the x-axis intercept instead
intercept = segStartPt(1);
end
[xInterceptionPoints, yInterceptionPoints] = ...
linecirc(slope, intercept, centre(1), centre(2), L_b);
testArr = isnan(xInterceptionPoints);
if (testArr(1) == 0) % Line intersects. Line segment may not.
interceptionPoint1 = [xInterceptionPoints(1), yInterceptionPoints(1)];
interceptionPoint2 = [xInterceptionPoints(2), yInterceptionPoints(2)];
% Test if first intersection is on the line segment
p1OnSeg = onSeg(segStartPt, segEndPt, interceptionPoint1);
p2OnSeg = onSeg(segStartPt, segEndPt, interceptionPoint2);
if (p1OnSeg == 1)
cutCount = cutCount + 1;
scatter(interceptionPoint1(1), interceptionPoint1(2), 60, 'MarkerFaceColor', 'r', 'MarkerEdgeColor', 'k');
end
% Test if second intersection point is on the line segment
if (interceptionPoint1(1) ~= interceptionPoint2(1) || interceptionPoint1(2) ~= interceptionPoint2(2)) % Don't double count touching points
if (p2OnSeg == 1)
cutCount = cutCount + 1;
scatter(interceptionPoint2(1), interceptionPoint2(2), 60, 'MarkerFaceColor', 'r', 'MarkerEdgeColor', 'k');
end
end
end
end
% Plot circle
viscircles(centre, L_b, 'EdgeColor', 'b');
H = voronoi(centres(:,1), centres(:,2));
for i = 1:size(H)
set(H(i), 'Color', 'g');
end
end
function boolVal = onSeg(segStart, segEnd, testPoint)
bvX = isBetweenOrEq(segStart(1), segEnd(1), testPoint(1));
bvY = isBetweenOrEq(segStart(2), segEnd(2), testPoint(2));
if (bvX == 1 && bvY == 1)
boolVal = 1;
else
boolVal = 0;
end
end
function boolVal = isBetweenOrEq(end1, end2, test)
if ((test <= end1 && test >= end2) || (test >= end1 && test <= end2))
boolVal = 1;
else
boolVal = 0;
end
end
It creates a hexagonal grid, then calculates the number of crossings between a circle drawn with a fixed radius (62 in this case) and a specified centre.
The scatter calls show the locations that the function counts.
Implementing sprintf calls within the if(p1OnSeg == 1) block indicates that my function has chosen fictitious intersection points (although it then deals with them correctly)
if (interceptionPoint1(1) > -26 && interceptionPoint1(1) < -25)
sprintf('p1 = [%f, %f]. Vx = [%f, %f], Vy = [%f, %f].\nxint = [%f, %f], yint = [%f, %f]',...
interceptionPoint1(1), interceptionPoint1(2), VertexX(1,lc), VertexX(2,lc), VertexY(1,lc), VertexY(2,lc),...
xInterceptionPoints(1), xInterceptionPoints(2), yInterceptionPoints(1), yInterceptionPoints(2))
end
Outputs
p1 = [-25.980762, 0.000000]. Vx = [-25.980762, -25.980762], Vy = [-15.000000, 15.000000].
xint = [-25.980762, -25.980762], yint = [0.000000, 0.000000]
A picture shows the strange points.
Sorry for the very long question but - why are these being detected. They don't lie on the circle (displaying values within a mylinecirc function detects the intersections at around (-25, 55) and (-25, -55) or so (as an infinite line would expect).
Moving the circle can remove these points, but sometimes this leads to other problems with detection. What's the deal?
Edit: Rotating my grid pattern created by [Vx, Vy] = voronoi(...) and then removing points with very large values (ie those going close to infinity etc) appears to have fixed this problem. The removal of 'large' value points seems to be necessary to avoid NaN values appearing in 'slope' and 'intercept'. My guess is this is related to a possible slight inclination due to rotation, coupled with then overflow of the expected intercept.
Example code added is below. I also edited in Jan de Gier's code, but that made no difference to the problem and so is not changed in the question code.
%Rotate slightly
RotAngle = 8;
RotMat = [cosd(RotAngle), -sind(RotAngle); sind(RotAngle), cosd(RotAngle)];
for i=1:size(centres,1)
centres(i,:) = centres(i,:) - [floor(xMax/2) * dx, floor(yMax/2) * dy]; %Translation
centres(i,:) = ( RotMat * centres(i,:)' ); %Rotation
end
% Get counter for intersected lines
[VertexX, VertexY] = voronoi(centres(:,1), centres(:,2));
% Filter vertices
numLines = size(VertexX, 2);
newVx = [];
newVy = [];
for lc = 1:numLines
testVec = [VertexX(:,lc) VertexY(:,lc)];
if ~any(abs(testVec) > range*1.5)
newVx = [newVx; VertexX(:,lc)'];
newVy = [newVy; VertexY(:,lc)'];
end
end
VertexX = newVx';
VertexY = newVy';
numLines = size(VertexX, 2);
Still appreciating answers or suggestions to clear up why this is/was occuring.
Example values that cause this are getCutCountHex(30, [0,0]) and ...(35, [0,0])
I cant reproduce your problem, but the thing I did notice is that your onSeg() function might be wrong: it returns true if the testpoint lies in the rectangle with two of the four corner points being segStart and segEnd.
A function that returns true iff a point is on (or more accurate: close enough to) the line segment (segStart,segEnd) could be:
function boolVal = onSeg(segStart, segEnd, testPoint)
tolerance = .5;
AB = sqrt((segEnd(1)-segStart(1))*(segEnd(1)-segStart(1))+(segEnd(2)-segStart(2))*(segEnd(2)-segStart(2)));
AP = sqrt((testPoint(1)-segEnd(1))*(testPoint(1)-segEnd(1))+(testPoint(2)-segEnd(2))*(testPoint(2)-segEnd(2)));
PB = sqrt((segStart(1)-testPoint(1))*(segStart(1)-testPoint(1))+(segStart(2)-testPoint(2))*(segStart(2)-testPoint(2)));
boolVal = abs(AB - (AP + PB)) < tolerance;
end
an approach that I found in one of the anwers here: Find if point lays on line segment. I hope that solves your problem.

Using Heat Equation to blur images using Matlab

I am trying to use the PDE heat equation and apply it to images using Matlab. The problem i am having is that the image isn't blurring , it is just going white. Also, I am getting different results from the rest of the class who is using Maple.
Here is the code:
% George Lees Jr.
% Heat equation
clear,clc;
dx = 1;
dy = 1;
dt = .025;
%dt/(dx*dx)
t = 0;
time = 3;
T_old = imread('tulipgray.jpg');
T_temp=T_old;
[m,n,k] = size(T_temp);
%colormap gray;
%imagesc(T_temp);
%imshow(T_old);
T_new = T_temp;
T_new=ind2gray(T_new,colormap);
%T_new(:,50)=0;
%T_old(1,70)
%imagesc(T_new);
%diff_x = dt/(dx*dx)
%diff_y = dt/ (dy*dy)
%time = 0;
while t < time
for i = 2:1:m-1
for j = 2:1:n-1
T_new(i,j) = T_temp(i,j) + dt*(T_temp(i+1,j) -2*T_temp(i,j) + T_temp(i-1,j)) + dt*(T_temp(i,j+1)-2*T_temp(i,j) + T_temp(i,j-1));
t = t+dt;
T_temp(i,j) = T_new(i,j);
end
end
end
figure
imshow(T_new)
Yeah the image just gets whiter
There's 2 issues with your code:
1) you're incrementing the time counter after each individual pixel instead of after doing the whole image
2) you need to do the calculations on floating points values, not integers. dt is small, so the values from the RHS of the equation are <1
Fixed code should look something like this
clear,clc;
dt = 0.025;
time = 3;
T_old = imread('rice.png');
T_temp=double(T_old);
[m,n,k] = size(T_temp);
T_new = double(T_temp);
T_new=ind2gray(T_new,colormap);
while t < time
for i = 2:1:m-1
for j = 2:1:n-1
T_new(i,j) = T_temp(i,j) + dt*(T_temp(i+1,j) -2*T_temp(i,j) + T_temp(i-1,j)) + dt*(T_temp(i,j+1)-2*T_temp(i,j) + T_temp(i,j-1));
end
end
T_temp = T_new;
t = t+dt;
imshow(uint8(T_new))
getframe;
end