Receiving this error code when extracting centroid and plotting motion
2 views (last 30 days)
Show older comments
Sara K Takiguchi
on 22 Mar 2023
Answered: Image Analyst
on 1 Apr 2023
I keep getting this error when running my code:
Intermediate dot '.' indexing produced a comma-separated list with 2 values, but
it must produce a single value when followed by subsequent indexing operations.
Error in referencemotionplot (line 57)
xhand1(frameIndex) = props.Centroid(1);
This is the code I am running on 2021b MATLAB to plot the coordinates of my hand motion:
% Clear the command windowv1
close all; % Close all figures (except those of imtool.)
clear; % Erase all existing variables. Or clearvars if you want.
workspace; % Make sure the workspace panel is showing.
format long
format compact
fontSize = 14;
vidObj = VideoReader('v3.MOV');
numberOfFrames = 50;
for frameIndex = 1 : numberOfFrames
frame = read(vidObj, frameIndex);
figure(1)
subplot(2, 3, 1);
imshow(frame)
axis('on', 'image');
caption = sprintf('Original Image Frame %d of %d', frameIndex, numberOfFrames);
title(caption, 'fontSize', fontSize);
drawnow;
% Convert to gray scale
grayImage = rgb2gray(frame);
% Crop frame to get rid of white window to the right.
grayImage = grayImage(:, 1 : 500); % You need to determine the column
subplot(2, 3, 2);
imshow(grayImage)
axis('on', 'image');
impixelinfo;
caption = sprintf('Gray Scale Image Frame %d of %d', frameIndex, numberOfFrames);
title(caption, 'fontSize', fontSize);
drawnow;
%========================================================
% First find the white paddle.
% Threshold or call imbinarize()
hand = imbinarize(grayImage);
% Fill holes
hand = imfill(hand, 'holes');
% Take largest blob only. That's the white paddle
hand = bwareafilt(hand, 1);
% We need to shrink the paddle because the edges are less bright and they
% get detected when we try to get the dot. So let's explude edges.
se = strel('disk', 15, 0);
hand = imerode(hand, se);
figure(2)
subplot(2, 3, 3);
axis('on', 'image');
imshow(hand)
impixelinfo;
title('hand', 'fontSize', fontSize);
drawnow;
% Find centroid of white paddle.
props = regionprops(hand, 'Centroid');
% Skip it if the paddle can't be found, like it's too dark or something.
if isempty(props)
continue;
end
% Get x and y
xhand1(frameIndex) = props.Centroid(1);
yhand1(frameIndex) = props.Centroid(2);
%========================================================
% Now get the black dot.
thresholdValue = 0;
whiteBlobs = grayImage > thresholdValue;
% Erase junk outside the paddle
whiteBlobs = whiteBlobs & hand;
% Erase the axle.
whiteBlobs(104:157, 264:319) = false;
% Note, black dot might not be resolved enough to find it!
% Take blobs only if they're in the 2-50 pixel range.
% That should get us the black dot.
props = regionprops(whiteBlobs, 'Centroid', 'Area');
allAreas = [props.Area];
whiteBlobs = bwareafilt(whiteBlobs,1, "smallest");
% Sometimes there is noise, and we get 2 blobs, so just take the largest blob in that range.
whiteBlobs = bwareafilt(whiteBlobs, 1);
figure(2)
subplot(2, 3, 4);
imshow(whiteBlobs)
impixelinfo;
axis('on', 'image');
title('Black Dot', 'fontSize', fontSize);
drawnow;
% Find centroid of black dot.
props = regionprops(whiteBlobs, 'Centroid', 'Area');
allAreas = [props.Area];
% Skip it if the dot can't be found, like it's too blurred or something.
if isempty(props)
fprintf('No dot found on frame #%d of %d.\n', frameIndex, numberOfFrames);
continue;
end
% Get x and y
figure(3)
xDot(frameIndex) = props.Centroid(1);
yDot(frameIndex) = props.Centroid(2);
subplot(2, 3, 5:6);
plot(xDot, yDot, 'r');
hold on;
grid off;
title('verticalplot_4');
xlabel('x', 'fontSize', fontSize);
ylabel('y', 'fontSize', fontSize);
xlim([100 500])
ylim([1000 2000])
if frameIndex == 1
% Maximize the figure window.
g = gcf;
g.WindowState = 'maximized';
end
drawnow;
end
% Interpolate any missing ones.
missingIndexes = isnan(xDot);
if any(missingIndexes)
xFit = 1 : numberOfFrames;
xDot = interp1(find(~missingIndexes), xDot(~missingIndexes), xFit, 'spline');
yDot = interp1(find(~missingIndexes), yDot(~missingIndexes), xFit, 'spline');
subplot(2, 3, 5:6);
plot(xDot,yDot);
hold on;
grid on;
title('horizontal_plot1. X = Blue, y = red', 'fontSize', fontSize);
xlabel('Frame Number', 'fontSize', fontSize);
ylabel('Column or Row', 'fontSize', fontSize);
end
%%
xyDot=[xDot;yDot];
save('v16''xyDot')
filename='v16.mat';
save(filename,"xyDot");
Here is the video I am using:
Does anyone know why I am getting this error?
0 Comments
Accepted Answer
Image Analyst
on 1 Apr 2023
@Sara K Takiguchi this seems to work fine for finding one white paper on your hand.
% Demo to track green color. Finds and annotates centroid and bounding box of green blobs.
% Modify thresholds to detect different colors.
clc; % Clear the command window.
close all; % Close all figures (except those of imtool.)
imtool close all; % Close all imtool figures if you have the Image Processing Toolbox.
clear; % Erase all existing variables. Or clearvars if you want.
workspace; % Make sure the workspace panel is showing.
format long g;
format compact;
fontSize = 20;
% Specify input video file name.
folder = pwd;
% fullFileName = 'rhinos.avi';
% fullFileName = 'traffic.avi';
baseFileName = 'hand.mp4';
fullFileName = fullfile(folder, baseFileName);
% Check if the video file actually exists in the current folder or on the search path.
if ~exist(fullFileName, 'file')
% File doesn't exist -- didn't find it there. Check the search path for it.
fullFileNameOnSearchPath = baseFileName; % No path this time.
if ~exist(fullFileNameOnSearchPath, 'file')
% Still didn't find it. Alert user.
errorMessage = sprintf('Error: %s does not exist in the search path folders.', fullFileName);
uiwait(warndlg(errorMessage));
return;
end
end
% Instantiate a video reader object for this video.
videoObject = VideoReader(fullFileName);
% Setup other parameters
numberOfFrames = videoObject.NumberOfFrame;
% Preallocate x and y centroids.
xCentroid = nan(numberOfFrames, 1);
yCentroid = nan(numberOfFrames, 1);
% Read one frame at a time, and find specified color.
for k = 1 : numberOfFrames
% Read one frame
thisFrame=read(videoObject,k);
hImage=subplot(2, 2, 1);
% Display it.
imshow(thisFrame);
axis on;
caption = sprintf('Original RGB image, frame #%d of %d', k, numberOfFrames);
title(caption, 'FontSize', fontSize);
drawnow;
% Get the mask for this frame.
[mask,maskedRGBImage] = createMask(thisFrame);
% Get the largest blob only.
mask = bwareafilt(mask, 1);
subplot(2, 2, 2);
imshow(mask, []);
impixelinfo();
axis on;
title('Mask', 'FontSize', fontSize);
subplot(2, 2, 3);
if k == 1
% Enlarge figure to full screen.
set(gcf, 'Units', 'Normalized', 'OuterPosition', [0 0 1 1]);
% Give a name to the title bar.
set(gcf, 'Name', 'Demo by ImageAnalyst', 'NumberTitle', 'Off')
hCheckbox = uicontrol('Style','checkbox',...
'Units', 'Normalized',...
'String', 'Finish Now',...
'Value',0,'Position', [.02 .5 .4 .05], ...
'FontSize', 30, 'ForegroundColor', 'r');
end
[labeledImage, numberOfRegions] = bwlabel(mask);
if numberOfRegions >= 1
stats = regionprops(labeledImage, 'BoundingBox', 'Centroid');
% Delete old texts and rectangles
if exist('hRect', 'var')
delete(hRect);
end
if exist('hText', 'var')
delete(hText);
end
% Display the original image again.
hImage=subplot(2, 2, 3);
imshow(thisFrame);
axis on;
hold on;
caption = sprintf('%d blobs found in frame #%d of %d', numberOfRegions, k, numberOfFrames);
title(caption, 'FontSize', fontSize);
drawnow;
% This is a loop to bound the colored objects in a rectangular box.
for r = 1 : numberOfRegions
% Find location for this blob.
thisBB = stats(r).BoundingBox;
thisCentroid = stats(r).Centroid;
hRect(r) = rectangle('Position', thisBB, 'EdgeColor', 'r', 'LineWidth', 2);
hSpot = plot(thisCentroid(1), thisCentroid(2), 'y+', 'MarkerSize', 10, 'LineWidth', 2);
hText(r) = text(thisBB(1), thisBB(2)-20, strcat('X: ', num2str(round(thisCentroid(1))), ' Y: ', num2str(round(thisCentroid(2)))));
set(hText(r), 'FontName', 'Arial', 'FontWeight', 'bold', 'FontSize', 12, 'Color', 'yellow');
end
hold off
drawnow;
% Plot centroid in plot #4
subplot(2, 2, 4);
xCentroid(k) = stats(1).Centroid(1);
yCentroid(k) = stats(1).Centroid(2);
plot(xCentroid, yCentroid, 'b-', 'LineWidth', 2);
grid on;
title('Track of Centroid', 'FontSize',fontSize);
xlabel('X Centroid', 'FontSize',fontSize);
ylabel('Y Centroid', 'FontSize',fontSize);
axis ij; % Flip vertically
end
% See if they want to bail out
if get(hCheckbox, 'Value')
% Finish now checkbox is checked.
msgbox('Done with demo.');
return;
end
end
msgbox('Done with demo.');
%===================================================================================================
function [BW,maskedRGBImage] = createMask(RGB)
%createMask Threshold RGB image using auto-generated code from colorThresholder app.
% [BW,MASKEDRGBIMAGE] = createMask(RGB) thresholds image RGB using
% auto-generated code from the colorThresholder app. The colorspace and
% range for each channel of the colorspace were set within the app. The
% segmentation mask is returned in BW, and a composite of the mask and
% original RGB images is returned in maskedRGBImage.
% Auto-generated by colorThresholder app on 01-Apr-2023
%------------------------------------------------------
% Convert RGB image to chosen color space
I = RGB;
% Define thresholds for channel 1 based on histogram settings
channel1Min = 231.000;
channel1Max = 255.000;
% Define thresholds for channel 2 based on histogram settings
channel2Min = 221.000;
channel2Max = 255.000;
% Define thresholds for channel 3 based on histogram settings
channel3Min = 189.000;
channel3Max = 255.000;
% Create mask based on chosen histogram thresholds
sliderBW = (I(:,:,1) >= channel1Min ) & (I(:,:,1) <= channel1Max) & ...
(I(:,:,2) >= channel2Min ) & (I(:,:,2) <= channel2Max) & ...
(I(:,:,3) >= channel3Min ) & (I(:,:,3) <= channel3Max);
BW = sliderBW;
% Initialize output masked image based on input image.
maskedRGBImage = RGB;
% Set background pixels where BW is false to zero.
maskedRGBImage(repmat(~BW,[1 1 3])) = 0;
end
0 Comments
More Answers (2)
Image Analyst
on 22 Mar 2023
Not having run the code, it looks like your binary image may have two blobs in it. Even though you used bwareafilt to get just one blob, you then eroded it which may have produced two or more blobs. If you're expecting just one blob, then you had better call bwareafilt again to get just one blob.
8 Comments
Image Analyst
on 24 Mar 2023
You can use the color thresholder on the apps tab of the tool ribbon to get code to mask out that paper on your hand. See attached demo where I track a green sharpie marker.
If you still can't figure it out, let me know.
See Also
Categories
Find more on Image Processing and Computer Vision in Help Center and File Exchange
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!