moving shadow elimination in video - matlab

I wish to remove moving shadow in video. I followed the steps as mentioned in this article, but getting the same result before and after applying threshold operation on the swt output. didn't get the expected output...Can anyone suggest me what I am doing wrong?
Steps to do for shadow removal:
(i) Read the video.
(ii) After the color conversion split the h s v components
(iii) applying the stationary wavelet transform on on s and v components of frame
(iv) calculate skew value for respective swt output of s and v component
(v) Assign the value 1 and 0 to 's and v' pixel if swt of v is greater than skewness value of v likewise for s too.
(vi) Do inverse swt over the s and v
(vii)Combine the h s and v
clc; % Clear the command window.
close all; % Close all figures (except those of imtool.)
imtool close all; % Close all imtool figures.
clear; % Erase all existing variables.
workspace; % Make sure the workspace panel is showing.
fontSize = 22;
movieFullFileName = fullfile('cam4v.mp4');
% Check to see that it exists.
if ~exist(movieFullFileName, 'file')
strErrorMessage = sprintf('File not found:\n%s\nYou can choose a new one,
or cancel', movieFullFileName);
response = questdlg(strErrorMessage, 'File not found', 'OK - choose a new
movie.', 'Cancel', 'OK - choose a new movie.');
if strcmpi(response, 'OK - choose a new movie.')
[baseFileName, folderName, FilterIndex] = uigetfile('*.avi');
if ~isequal(baseFileName, 0)
movieFullFileName = fullfile(folderName, baseFileName);
else
return;
end
else
return;
end
end
try
videoObject = VideoReader(movieFullFileName);
% Determine how many frames there are.
numberOfFrames = videoObject.NumberOfFrames;
vidHeight = videoObject.Height;
vidWidth = videoObject.Width;
numberOfFramesWritten = 0;
% Prepare a figure to show the images in the upper half of the screen.
figure;
% screenSize = get(0, 'ScreenSize');
% Enlarge figure to full screen.
set(gcf, 'units','normalized','outerposition',[0 0 1 1]);
% Ask user if they want to write the individual frames out to disk.
promptMessage = sprintf('Do you want to save the individual frames out to
individual disk files?');
button = questdlg(promptMessage, 'Save individual frames?', 'Yes', 'No',
'Yes');
if strcmp(button, 'Yes')
writeToDisk = true;
% Extract out the various parts of the filename.
[folder, baseFileName, extentions] = fileparts(movieFullFileName);
% Make up a special new output subfolder for all the separate
% movie frames that we're going to extract and save to disk.
% (Don't worry - windows can handle forward slashes in the folder
name.)
folder = pwd; % Make it a subfolder of the folder where this m-file
lives.
outputFolder = sprintf('%s/Movie Frames from %s', folder,
baseFileName);
% Create the folder if it doesn't exist already.
if ~exist(outputFolder, 'dir')
mkdir(outputFolder);
end
else
writeToDisk = false;
end
% Loop through the movie, writing all frames out.
% Each frame will be in a separate file with unique name.
for frame = 1 : numberOfFrames
% Extract the frame from the movie structure.
thisFrame = read(videoObject, frame);
% Display it
hImage = subplot(2, 2, 1);
image(thisFrame);
caption = sprintf('Frame %4d of %d.', frame, numberOfFrames);
title(caption, 'FontSize', fontSize);
drawnow; % Force it to refresh the window.
% Write the image array to the output file, if requested.
if writeToDisk
% Construct an output image file name.
outputBaseFileName = sprintf('Frame %4.4d.png', frame);
outputFullFileName = fullfile(outputFolder, outputBaseFileName);
% Stamp the name and frame number onto the image.
% At this point it's just going into the overlay,not actually
getting written into the pixel values.
text(5, 15, outputBaseFileName, 'FontSize', 20);
% Extract the image with the text "burned into" it.
frameWithText = getframe(gca);
% frameWithText.cdata is the image with the text
% actually written into the pixel values.
% Write it out to disk.
imwrite(frameWithText.cdata, outputFullFileName, 'png');
end
if frame == 1
xlabel('Frame Number');
ylabel('Gray Level');
% Get size data later for preallocation if we read
% the movie back in from disk.
[rows, columns, numberOfColorChannels] = size(thisFrame);
end
% Update user with the progress. Display in the command window.
if writeToDisk
progressIndication = sprintf('Wrote frame %4d of %d.', frame,
numberOfFrames);
else
progressIndication = sprintf('Processed frame %4d of %d.', frame,
numberOfFrames);
end
disp(progressIndication);
% Increment frame count (should eventually = numberOfFrames
% unless an error happens).
numberOfFramesWritten = numberOfFramesWritten + 1;
% Now let's do the differencing
alpha = 0.5;
if frame == 1
Background = thisFrame;
else
% Change background slightly at each frame
% Background(t+1)=(1-alpha)*I+alpha*Background
Background = (1-alpha)* thisFrame + alpha * Background;
end
% Display the changing/adapting background.
subplot(2, 2, 3);
imshow(Background);
title('Adaptive Background', 'FontSize', fontSize);
% Do color conversion from rgb to hsv
x=rgb2hsv(thisFrame);
y=rgb2hsv(Background);
% Split the hsv component to h,s,v value
Hx = x(:,:,1); Hy = y(:,:,1);
Sx = x(:,:,2); Sy = y(:,:,2);
Vx = x(:,:,3); Vy = y(:,:,3);
%Find the absolute diffrence between h s v value of current and
previous frame
dh=(abs(double(Hx) - double(Hy)));
ds1=(abs(double(Sx) - double(Sy)));
dv1=(abs(double(Vx) - double(Vy)));
%Perform the swt2 transformation on difference of s and v value
[as,hs,vs,ds] = swt2(ds1,1,'haar');
[av,hv,vv,dv] = swt2(dv1,1,'haar');
%Compute the skewness value of 'swt of v'
sav=skewness(av(:));
shv=skewness(hv(:));
svv=skewness(vv(:));
sdv=skewness(dv(:));
%Compute the skewness value of 'swt of s'
sas=skewness(as(:));
shs=skewness(hs(:));
svs=skewness(vs(:));
sds=skewness(ds(:));
% Do the shadow detection based on the output of swt and skew of 'v'
value
% Compare swt v output with its skew value if the av >=sav then av is
assigned to one else it becomes zero.This operation continues till variable i
b=(av>=sav); f= (as>=sas);
c=(hv>=shv); g=(hs>=shs);
d=(vv>=svv); h=(vs>=svs);
e=(dv>=sdv); i=(ds>=sds);
% Remove the shadows based on 'and operation
j=(b&f); l=(d&h);
k=(c&g); m=(e&i);
% Do inverse swt operation
recv = iswt2(b,c,d,e,'haar');
recs= iswt2(j,k,l,m,'haar');
%Combine the value of h,s and v
de_shadow=cat(3,dh,recs,recv);
rgb=hsv2rgb(de_shadow);
% Plot the image.
subplot(2, 2, 4);
imshow(rgb);
title('output Image', 'FontSize', fontSize);
end
% Alert user that we're done.
if writeToDisk
finishedMessage = sprintf('Done! It wrote %d frames to
folder\n"%s"', numberOfFramesWritten, outputFolder);
else
finishedMessage = sprintf('Done! It processed %d frames of\n"%s"',
numberOfFramesWritten, movieFullFileName);
end
disp(finishedMessage); % Write to command window.
uiwait(msgbox(finishedMessage)); % Also pop up a message box.
% Exit if they didn't write any individual frames out to disk.
if ~writeToDisk
return;
end
% Ask user if they want to read the individual frames from the disk,
% that they just wrote out, back into a movie and display it.
promptMessage = sprintf('Do you want to recall the individualframes\nback
from disk into a movie?\n(This will take several seconds.)');
button = questdlg(promptMessage, 'Recall Movie?', 'Yes', 'No', 'Yes');
if strcmp(button, 'No')
return;
end
% Create a VideoWriter object to write the video out to a new, different
file.
writerObj = VideoWriter('Newcam4v.mp4');
open(writerObj);
% Read the frames back in from disk, and convert them to a movie.
% Preallocate recalledMovie, which will be an array of structures.
% First get a cell array with all the frames.
allTheFrames = cell(numberOfFrames,1);
allTheFrames(:) = {zeros(vidHeight, vidWidth, 3, 'uint8')};
% Next get a cell array with all the colormaps.
allTheColorMaps = cell(numberOfFrames,1);
allTheColorMaps(:) = {zeros(256, 3)};
% Now combine these to make the array of structures.
recalledMovie = struct('cdata', allTheFrames, 'colormap',allTheColorMaps)
for frame = 1 : numberOfFrames
% Construct an output image file name.
outputBaseFileName = sprintf('Frame %4.4d.png', frame);
outputFullFileName = fullfile(outputFolder, outputBaseFileName);
% Read the image in from disk.
thisFrame = imread(outputFullFileName);
% Convert the image into a "movie frame" structure.
thisFrame=imresize(thisFrame,[452, 231]);
recalledMovie(frame) = im2frame(thisFrame);
% Write this frame out to a new video file.
writeVideo(writerObj, thisFrame);
end
close(writerObj);
% Get rid of old image and plot.
delete(hImage);
% Create new axes for our movie.
subplot(1, 3, 2);
axis off; % Turn off axes numbers.
title('Movie recalled from disk', 'FontSize', fontSize);
% Play the movie in the axes.
movie(recalledMovie);
% Note: if you want to display graphics or text in the overlay
% as the movie plays back then you need to do it like I did at first
% (at the top of this file where you extract and imshow a frame at a
time.)
msgbox('Done this experiment!');
catch ME
% Some error happened if you get here.
strErrorMessage = sprintf('Error extracting movie frames
from:\n\n%s\n\nError: %s\n\n)', movieFullFileName, ME.message);
uiwait(msgbox(strErrorMessage));
end

Related

bubble size distribution in bubble column using image processing technique

I have a video from which I have extracted several frames. I need to analyse them to get the total number and the sizes of the bubbles. The program I have so far can identify a single bubble in the image but has trouble to determine multiple bubbles.
code:
clc;
clear all;
close all;
% ----------------- Select the image -------------------------------
% Double click the image fle to be selected
[FileName,PathName] = uigetfile('*.png','Select the image');
file = fullfile(PathName,FileName);
img=imread(file); % Reads the image
rgb = imcrop(img);
figure,imshow(rgb)
d = imdistline; %to find the appropriate radius range
delete(d);
gray_image = rgb2gray(rgb);
figure, imshow(gray_image);
impixelinfo
[centers, radii] = imfindcircles(rgb,[3 10],'ObjectPolarity','dark')
hold on
[centers, radii] = imfindcircles(rgb,[3 10],'ObjectPolarity','dark', ...
'Sensitivity',0.96)
hold off
figure, imshow(rgb);
h = viscircles(centers,radii);
[centers, radii] = imfindcircles(rgb,[3 10],'ObjectPolarity','dark', ...
'Sensitivity',0.96);
length(centers)
delete(h); % Delete previously drawn circles
h = viscircles(centers,radii);
%second method(2 stage )
[centers, radii] = imfindcircles(rgb,[3 10], 'ObjectPolarity','dark', ...
'Sensitivity',0.96,'Method','twostage');
delete(h);
h = viscircles(centers,radii);
The Frame Given As Input To Code
Output i am getting
I need help to get the correct number of bubbles in the image.
since in output screenshot there is some cluster where algo fails to get the correct number of bubbles.

Can anyone suggest how do I obtain all the values of the variable bc?

The variable bc is getting overwritten and I am Unable to plot all the values of the variable from the start.
I tried exporting the variable to a csv file but that didn't work.
I'm trying to detect a red, green, blue object and plot its coordinates versus time in matlab.
a = imaqhwinfo;
[camera_name, camera_id, format] = getCameraInfo(a);
% Capture the video frames using the videoinput function
% You have to replace the resolution & your installed adaptor name.
vid = videoinput(camera_name, camera_id, format);
% Set the properties of the video object
set(vid, 'FramesPerTrigger', Inf);
set(vid, 'ReturnedColorspace', 'rgb')
vid.FrameGrabInterval = 5;
%start the video aquisition here
start(vid)
% Set a loop that stop after 100 frames of aquisition
while(vid.FramesAcquired<=100)
% Get the snapshot of the current frame
data = getsnapshot(vid);
% Now to track red objects in real time
% we have to subtract the red component
% from the grayscale image to extract the red components in the image.
diff_im = imsubtract(data(:,:,1), rgb2gray(data));
%Use a median filter to filter out noise
diff_im = medfilt2(diff_im, [3 3]);
% Convert the resulting grayscale image into a binary image.
diff_im = im2bw(diff_im,0.18);
% Remove all those pixels less than 300px
diff_im = bwareaopen(diff_im,300);
% Label all the connected components in the image.
bw = bwlabel(diff_im, 8);
% Here we do the image blob analysis.
% We get a set of properties for each labeled region.
stats = regionprops(bw, 'BoundingBox', 'Centroid');
% Display the image
imshow(data)
hold on
%
% %This is a loop to bound the red objects in a rectangular box.
for object = 1:length(stats)
bb = stats(object).BoundingBox;
bc = stats(object).Centroid;
rectangle('Position',bb,'EdgeColor','r','LineWidth',2)
plot(bc(1),bc(2), '-m+')
x = bc(1);
y = bc(2);
csvwrite('bcx.dat', bc(1));
csvwrite('bcy.dat', bc(2));
a=text(bc(1)+15,bc(2), strcat('X: ', num2str(round(bc(1))), ' Y: ', num2str(round(bc(2)))));
set(a, 'FontName', 'Arial', 'FontWeight', 'bold', 'FontSize', 12, 'Color', 'yellow');
end
hold off
end
% Both the loops end here.
% Stop the video aquisition.
stop(vid);
% Flush all the image data stored in the memory buffer.
flushdata(vid);
% Clear all variables
clear all
%sprintf('%s','That was all about Image tracking, Guess that was pretty easy :) ')

Segmenting cursive character (Arabic OCR)

I want to segment an Arabic word into single characters. Based on the histogram/profile, I assume that I can do the segmentation process by cut/segment the characters based on it's baseline (it have similar pixel values).
But, unfortunately, I still stuck to build the appropriate code, to make it works.
% Original Code by Soumyadeep Sinha
% Saving each single segmented character as one file
function [segm] = trysegment (a)
myFolder = 'D:\1. Thesis FINISH!!!\Data set\trial';
level = graythresh (a);
bw = im2bw (a, level);
b = imcomplement (bw);
i= padarray(b,[0 10]);
verticalProjection = sum(i, 1);
set(gcf, 'Name', 'Trying Segmentation for Cursive', 'NumberTitle', 'Off')
subplot(2, 2, 1);imshow(i);
subplot(2,2,3);
plot(verticalProjection, 'b-'); %histogram show by this code
% hist(reshape(input,[],3),1:max(input(:)));
grid on;
% % t = verticalProjection;
% % t(t==0) = inf;
% % mayukh = min(t)
% 0 where there is background, 1 where there are letters
letterLocations = verticalProjection > 0;
% Find Rising and falling edges
d = diff(letterLocations);
startingColumns = find(d>0);
endingColumns = find(d<0);
% Extract each region
y=1;
for k = 1 : length(startingColumns)
% Get sub image of just one character...
subImage = i(:, startingColumns(k):endingColumns(k));
% se = strel('rectangle',[2 4]);
% dil = imdilate(subImage, se);
th = bwmorph(subImage,'thin',Inf);
n = imresize (th, [64 NaN], 'bilinear');
figure, imshow (n);
[L,num] = bwlabeln(n);
for z= 1 : num
bw= ismember(L, z);
% Construct filename for this particular image.
baseFileName = sprintf('char %d.png', y);
y=y+1;
% Prepend the folder to make the full file name.
fullFileName = fullfile(myFolder, baseFileName);
% Do the write to disk.
imwrite(bw, fullFileName);
% subplot(2,2,4);
% pause(2);
% imshow(bw);
end
% y=y+1;
end;
segm = (n);
Word image is as follow:
Why the code isn't work?
do you have any recommendation of another codes?
or suggested algorithm to make it works, to do a good segmentation on cursive character?
Thanks before.
Replace this code part from the posted code
% 0 where there is background, 1 where there are letters
letterLocations = verticalProjection > 0;
% Find Rising and falling edges
d = diff(letterLocations);
startingColumns = find(d>0);
endingColumns = find(d<0);
with the new code part
threshold=max(verticalProjection)/3;
thresholdedProjection=verticalProjection > threshold;
count=0;
startingColumnsIndex=0;
for i=1:length(thresholdedProjection)
if thresholdedProjection(i)
if(count>0)
startingColumnsIndex=startingColumnsIndex+1;
startingColumns(startingColumnsIndex)= i-floor(count/2);
count=0;
end
else
count=count+1;
end
end
endingColumns=[startingColumns(2:end)-1 i-floor(count/2)];
No changes needed for the rest of the code.

To refresh imshow in Matlab?

I want to convert this answer's code to imshow.
It creates a movie in MOVIE2AVI by
%# preallocate
nFrames = 20;
mov(1:nFrames) = struct('cdata',[], 'colormap',[]);
%# create movie
for k=1:nFrames
surf(sin(2*pi*k/20)*Z, Z)
mov(k) = getframe(gca);
end
close(gcf)
movie2avi(mov, 'myPeaks1.avi', 'compression','None', 'fps',10);
My pseudocode
%# preallocate
nFrames = 20;
mov(1:nFrames) = struct('cdata',[], 'colormap',[]);
%# create movie
for k=1:nFrames
imshow(signal(:,k,:),[1 1 1]) % or simply imshow(signal(:,k,:))
drawnow
mov(k) = getframe(gca);
end
close(gcf)
movie2avi(mov, 'myPeaks1.avi', 'compression','None', 'fps',10);
However, this creates the animation in the screen, but it saves only a AVI -file which size is 0 kB. The file myPeaks1.avi is stored properly after running the surf command but not from imshow.
I am not sure about the command drawnow.
Actual case code
%% HSV 3rd version
% https://stackoverflow.com/a/29801499/54964
rgbImage = imread('http://i.stack.imgur.com/cFOSp.png');
% Extract blue using HSV
hsvImage=rgb2hsv(rgbImage);
I=rgbImage;
R=I(:,:,1);
G=I(:,:,2);
B=I(:,:,3);
R((hsvImage(:,:,1)>(280/360))|(hsvImage(:,:,1)<(200/360)))=255;
G((hsvImage(:,:,1)>(280/360))|(hsvImage(:,:,1)<(200/360)))=255;
B((hsvImage(:,:,1)>(280/360))|(hsvImage(:,:,1)<(200/360)))=255;
I2= cat(3, R, G, B);
% Binarize image, getting all the pixels that are "blue"
bw=im2bw(rgb2gray(I2),0.9999);
% The label most repeated will be the signal.
% So we find it and separate the background from the signal using label.
% Label each "blob"
lbl=bwlabel(~bw);
% Find the blob with the highes amount of data. That will be your signal.
r=histc(lbl(:),1:max(lbl(:)));
[~,idxmax]=max(r);
% Profit!
signal=rgbImage;
signal(repmat((lbl~=idxmax),[1 1 3]))=255;
background=rgbImage;
background(repmat((lbl==idxmax),[1 1 3]))=255;
%% Error Testing
comp_image = rgb2gray(abs(double(rgbImage) - double(signal)));
if ( sum(sum(comp_image(32:438, 96:517))) > 0 )
break;
end
%% Video
% 5001 units so 13.90 (= 4.45 + 9.45) seconds.
% In RGB, original size 480x592.
% Resize to 480x491
signal = signal(:, 42:532, :);
% Show 7 seconds (298 units) at a time.
% imshow(signal(:, 1:298, :));
%% Video VideoWriter
% movie2avi deprecated in Matlab
% https://stackoverflow.com/a/11054155/54964
% https://stackoverflow.com/a/29952648/54964
%# figure
hFig = figure('Menubar','none', 'Color','white');
Z = peaks;
h = imshow(Z, [], 'InitialMagnification',1000, 'Border','tight');
colormap parula; axis tight manual off;
set(gca, 'nextplot','replacechildren', 'Visible','off');
% set(gcf,'Renderer','zbuffer'); % on some Windows
%# preallocate
N = 40; % 491;
vidObj = VideoWriter('myPeaks3.avi');
vidObj.Quality = 100;
vidObj.FrameRate = 10;
open(vidObj);
%# create movie
for k=1:N
set(h, 'CData', signal(:,k:k+40,:))
% drawnow
writeVideo(vidObj, getframe(gca));
end
%# save as AVI file
close(vidObj);
How can you substitute the drawing function by imshow or corresponding?
How can you store the animation correctly?
Here is some code to try:
%// plot
hFig = figure('Menubar','none', 'Color','white');
Z = peaks;
%h = surf(Z);
h = imshow(Z, [], 'InitialMagnification',1000, 'Border','tight');
colormap jet
axis tight manual off
%// preallocate movie structure
N = 40;
mov = struct('cdata',cell(1,N), 'colormap',cell(1,N));
%// aninmation
for k=1:N
%set(h, 'ZData',sin(2*pi*k/N)*Z)
set(h, 'CData',sin(2*pi*k/N)*Z)
drawnow
mov(k) = getframe(hFig);
end
close(hFig)
%// save AVI movie, and open video file
movie2avi(mov, 'file.avi', 'Compression','none', 'Fps',10);
winopen('file.avi')
Result (not really the video, just a GIF animation):
Depending on the codecs installed on your machine, you can apply video compression, e.g:
movie2avi(mov, 'file.avi', 'Compression','XVID', 'Quality',100, 'Fps',10);
(assuming you have the Xvid encoder installed).
EDIT:
Here is my implementation of the code you posted:
%%// extract blue ECG signal
%// retrieve picture: http://stackoverflow.com/q/29800089
imgRGB = imread('http://i.stack.imgur.com/cFOSp.png');
%// detect axis lines and labels
imgHSV = rgb2hsv(imgRGB);
BW = (imgHSV(:,:,3) < 1);
BW = imclose(imclose(BW, strel('line',40,0)), strel('line',10,90));
%// clear those masked pixels by setting them to background white color
imgRGB2 = imgRGB;
imgRGB2(repmat(BW,[1 1 3])) = 255;
%%// create sliding-window video
len = 40;
signal = imgRGB2(:,42:532,:);
figure('Menubar','none', 'NumberTitle','off', 'Color','k')
hImg = imshow(signal(:,1:1+len,:), ...
'InitialMagnification',100, 'Border','tight');
vid = VideoWriter('signal.avi');
vid.Quality = 100;
vid.FrameRate = 60;
open(vid);
N = size(signal,2);
for k=1:N-len
set(hImg, 'CData',signal(:,k:k+len,:))
writeVideo(vid, getframe());
end
close(vid);
The result look like this:

Color and Texture-Based Shadow Detection

I'm doing a project on tracking and Object classification in video surveillance,and i have some difficulties with removing the shadows from the foreground objects.
The problem is that i can't just use any method that i want, i have to use the same method described in this article Shadow removal with blob based morphological reconstruction .
In the article they use a hybrid shadow removal method- RGB color based detection and texture based detection. Both the colour and texture based procedures are used in parallel, followed by an assertion process that combines the results of the two.
So i would like to get some help with the shadow removal Matlab code.
my code so far
function Tracking_Objects()
% Create System objects used for reading video, detecting moving objects,
% and displaying the results.
obj = setupSystemObjects();
tracks = initializeTracks(); % Create an empty array of tracks.
nextId = 1; % ID of the next track
% Detect moving objects, and track them across video frames.
while ~isDone(obj.reader)
frame = readFrame();
[centroids, bboxes, mask] = detectObjects(frame);
predictNewLocationsOfTracks();
[assignments, unassignedTracks, unassignedDetections] = ...
detectionToTrackAssignment();
updateAssignedTracks();
updateUnassignedTracks();
deleteLostTracks();
createNewTracks();
displayTrackingResults();
end
%% Create System Objects
function obj = setupSystemObjects()
% Initialize Video I/O
% Create objects for reading a video from a file, drawing the tracked
% objects in each frame, and playing the video.
% Create a video file reader.
obj.reader = vision.VideoFileReader('input.avi');
% Create two video players, one to display the video,
% and one to display the foreground mask.
obj.videoPlayer = vision.VideoPlayer('Position', [10, 250, 700, 400]);
obj.maskPlayer = vision.VideoPlayer('Position', [720, 250, 700, 400]);
obj.detector = vision.ForegroundDetector('NumGaussians', 3, ...
'NumTrainingFrames', 40, 'MinimumBackgroundRatio', 0.7);
obj.blobAnalyser = vision.BlobAnalysis('BoundingBoxOutputPort', true, ...
'AreaOutputPort', true, 'CentroidOutputPort', true, ...
'MinimumBlobArea', 75);
end
%% Initialize Tracks
function tracks = initializeTracks()
% create an empty array of tracks
tracks = struct(...
'id', {}, ...
'bbox', {}, ...
'kalmanFilter', {}, ...
'age', {}, ...
'totalVisibleCount', {}, ...
'consecutiveInvisibleCount', {});
end
%% Read a Video Frame
% Read the next video frame from the video file.
function frame = readFrame()
frame = obj.reader.step();
end
%% Detect Objects
function [centroids, bboxes, mask] = detectObjects(frame)
% Detect foreground.
mask = obj.detector.step(frame);
% Apply morphological operations to remove noise and fill in holes.
mask = imopen(mask, strel('rectangle', [3,3]));
mask = imclose(mask, strel('rectangle', [15, 15]));
mask = imfill(mask, 'holes');
% Perform blob analysis to find connected components.
[~, centroids, bboxes] = obj.blobAnalyser.step(mask);
end
%% Predict New Locations of Existing Tracks
function predictNewLocationsOfTracks()
for i = 1:length(tracks)
bbox = tracks(i).bbox;
% Predict the current location of the track.
predictedCentroid = predict(tracks(i).kalmanFilter);
% Shift the bounding box so that its center is at
% the predicted location.
predictedCentroid = int32(predictedCentroid) - bbox(3:4) / 2;
tracks(i).bbox = [predictedCentroid, bbox(3:4)];
end
end
%% Assign Detections to Tracks
function [assignments, unassignedTracks, unassignedDetections] = ...
detectionToTrackAssignment()
nTracks = length(tracks);
nDetections = size(centroids, 1);
% Compute the cost of assigning each detection to each track.
cost = zeros(nTracks, nDetections);
for i = 1:nTracks
cost(i, :) = distance(tracks(i).kalmanFilter, centroids);
end
% Solve the assignment problem.
costOfNonAssignment = 20;
[assignments, unassignedTracks, unassignedDetections] = ...
assignDetectionsToTracks(cost, costOfNonAssignment);
end
%% Update Assigned Tracks
function updateAssignedTracks()
numAssignedTracks = size(assignments, 1);
for i = 1:numAssignedTracks
trackIdx = assignments(i, 1);
detectionIdx = assignments(i, 2);
centroid = centroids(detectionIdx, :);
bbox = bboxes(detectionIdx, :);
% Correct the estimate of the object's location
% using the new detection.
correct(tracks(trackIdx).kalmanFilter, centroid);
% Replace predicted bounding box with detected
% bounding box.
tracks(trackIdx).bbox = bbox;
% Update track's age.
tracks(trackIdx).age = tracks(trackIdx).age + 1;
% Update visibility.
tracks(trackIdx).totalVisibleCount = ...
tracks(trackIdx).totalVisibleCount + 1;
tracks(trackIdx).consecutiveInvisibleCount = 0;
end
end
%% Update Unassigned Tracks
% Mark each unassigned track as invisible, and increase its age by 1.
function updateUnassignedTracks()
for i = 1:length(unassignedTracks)
ind = unassignedTracks(i);
tracks(ind).age = tracks(ind).age + 1;
tracks(ind).consecutiveInvisibleCount = ...
tracks(ind).consecutiveInvisibleCount + 1;
end
end
%% Delete Lost Tracks
function deleteLostTracks()
if isempty(tracks)
return;
end
invisibleForTooLong = 20;
ageThreshold = 8;
% Compute the fraction of the track's age for which it was visible.
ages = [tracks(:).age];
totalVisibleCounts = [tracks(:).totalVisibleCount];
visibility = totalVisibleCounts ./ ages;
% Find the indices of 'lost' tracks.
lostInds = (ages < ageThreshold & visibility < 0.6) | ...
[tracks(:).consecutiveInvisibleCount] >= invisibleForTooLong;
% Delete lost tracks.
tracks = tracks(~lostInds);
end
%% Create New Tracks
function createNewTracks()
centroids = centroids(unassignedDetections, :);
bboxes = bboxes(unassignedDetections, :);
for i = 1:size(centroids, 1)
centroid = centroids(i,:);
bbox = bboxes(i, :);
% Create a Kalman filter object.
kalmanFilter = configureKalmanFilter('ConstantVelocity', ...
centroid, [200, 50], [100, 25], 100);
% Create a new track.
newTrack = struct(...
'id', nextId, ...
'bbox', bbox, ...
'kalmanFilter', kalmanFilter, ...
'age', 1, ...
'totalVisibleCount', 1, ...
'consecutiveInvisibleCount', 0);
% Add it to the array of tracks.
tracks(end + 1) = newTrack;
% Increment the next id.
nextId = nextId + 1;
end
end
%% Display Tracking Results
% The |displayTrackingResults| function draws a bounding box and label ID
% for each track on the video frame and the foreground mask. It then
% displays the frame and the mask in their respective video players.
function displayTrackingResults()
% Convert the frame and the mask to uint8 RGB.
frame = im2uint8(frame);
mask = uint8(repmat(mask, [1, 1, 3])) .* 255;
minVisibleCount = 8;
if ~isempty(tracks)
% Noisy detections tend to result in short-lived tracks.
% Only display tracks that have been visible for more than
% a minimum number of frames.
reliableTrackInds = ...
[tracks(:).totalVisibleCount] > minVisibleCount;
reliableTracks = tracks(reliableTrackInds);
% Display the objects. If an object has not been detected
% in this frame, display its predicted bounding box.
if ~isempty(reliableTracks)
% Get bounding boxes.
bboxes = cat(1, reliableTracks.bbox);
% Get ids.
ids = int32([reliableTracks(:).id]);
% Create labels for objects indicating the ones for
% which we display the predicted rather than the actual
% location.
labels = cellstr(int2str(ids'));
predictedTrackInds = ...
[reliableTracks(:).consecutiveInvisibleCount] > 0;
isPredicted = cell(size(labels));
isPredicted(predictedTrackInds) = {' predicted'};
labels = strcat(labels, isPredicted);
% Draw the objects on the frame.
frame = insertObjectAnnotation(frame, 'rectangle', ...
bboxes, labels);
% Draw the objects on the mask.
mask = insertObjectAnnotation(mask, 'rectangle', ...
bboxes, labels);
end
end
% Display the mask and the frame.
obj.maskPlayer.step(mask);
obj.videoPlayer.step(frame);
end
end
It would appear that you would need to modify the detectObjects function with the code to eliminate shadows. Currently, all it does is it takes a foreground mask from background subtraction (vision.ForegroundDetector), removes some noise and fills in small gaps using morphology, and then it finds connected components, a.k.a. "blobs". Typically, the blobs do include shadows.
If your shadow removal algorithm operates on a single frame, than this is where the code for it would go.
I think your problem is in your object detection. Your code is using an imopen and and imclose. But I think you want to use imdilate and imerode
%% Detect Objects
function [centroids, bboxes, mask] = detectObjects(frame)
% Detect foreground.
mask = obj.detector.step(frame);
% Apply morphological operations to remove noise and fill in holes.
%this makes the white space smaller to remove small dots/noise
mask = imerode(mask, strel('rectangle', [3,3]));
%this makes the white regions larger to restore the original size
mask = imclose(mask, strel('rectangle', [15, 15]));
mask = imfill(mask, 'holes');
% Perform blob analysis to find connected components.
[~, centroids, bboxes] = obj.blobAnalyser.step(mask);
end
I changed your imopen and imclose you may need to change your structuring elements as well. If you look at the matlab documentation imopen is the same as erosion followed by dilation, or imopened = imdilate(imerode(im,se)));
Imclose is dilation followed by erosion or imcloseed = imerode(imdilate(im,se))
the paper is using an erosion followed by a dilation (an imopen operation). So that is what I put in the code. If you want to use the same structuring element for both operations you can change
%this makes the white space smaller to remove small dots/noise
mask = imerode(mask, strel('rectangle', [3,3]));
%this makes the white regions larger to restore the original size
mask = imclose(mask, strel('rectangle', [15, 15]));
to
mask = imopen(mask,strel('rectangle',[15 15]));
since you didn't include your pictures I can't try it out, but I think it should work after you play with your strel function