Error: Subscripted assignment dimension mismatch

I'm following the digit classification example but using different datasets. However, I get the following error:
Subscripted assignment dimension mismatch.
Error in hog_svm (line 62)
features(i, :) = extractHOGFeatures(img, 'CellSize', cellSize);
At first, I thought it was because the images being used are of different sizes, so I made them all the same size, but that didn't work. Maybe I resized them in the wrong time? The code is shown below.
url = 'http://www.vision.caltech.edu/Image_Datasets/Caltech101/101_ObjectCategories.tar.gz';
% Store the output in a temporary folder
outputFolder = fullfile(tempdir, 'caltech101'); % define output folder
if ~exist(outputFolder, 'dir') % download only once
disp('Downloading 126MB Caltech101 data set...');
untar(url, outputFolder);
end
rootFolder = fullfile(outputFolder, '101_ObjectCategories');
imgSets = [ imageSet(fullfile(rootFolder, 'airplanes')), ...
imageSet(fullfile(rootFolder, 'ferry')), ...
imageSet(fullfile(rootFolder, 'laptop')) ];
minSetCount = min([imgSets.Count]);
imgSets = partition(imgSets, minSetCount, 'randomize');
% for image = 1:numel(imgSets)
% image = imresize(image, [20 20]);
% end
%numel - total number of array elements
[trainingSets, testSets] = partition(imgSets, 0.3, 'randomize');
img = read(trainingSets(1), 2);
% Extract HOG features and HOG visualization
[hog_2x2, vis2x2] = extractHOGFeatures(img,'CellSize',[2 2]);
[hog_4x4, vis4x4] = extractHOGFeatures(img,'CellSize',[4 4]);
[hog_8x8, vis8x8] = extractHOGFeatures(img,'CellSize',[8 8]);
% Show the original image
figure;
subplot(2,3,1:3); imshow(img);
% Visualize the HOG features
subplot(2,3,4);
plot(vis2x2);
title({'CellSize = [2 2]'; ['Feature length = ' num2str(length(hog_2x2))]});
subplot(2,3,5);
plot(vis4x4);
title({'CellSize = [4 4]'; ['Feature length = ' num2str(length(hog_4x4))]});
subplot(2,3,6);
plot(vis8x8);
title({'CellSize = [8 8]'; ['Feature length = ' num2str(length(hog_8x8))]});
cellSize = [4 4];
hogFeatureSize = length(hog_4x4);
trainingFeatures = [];
trainingLabels = [];
for image = 1:numel(trainingSets)
numImages = trainingSets(image).Count;
features = zeros(numImages, hogFeatureSize, 'single');
for i = 1:numImages
% img = rgb2gray(read(trainingSets(image), i));
% img = imbinarize(img);
img = read(trainingSets(image), i);
lvl = graythresh(img);
img = im2bw(img, lvl);
% img = im2single(img);
% img =imresize(img, .5);
features(i, :) = extractHOGFeatures(img, 'CellSize', cellSize);
end
labels = repmat(trainingSets(image).Description, numImages, 1);
trainingFeatures = [trainingFeatures; features];
trainingLabels = [trainingLabels; labels];
end
classifier = fitcecoc(trainingFeatures, trainingLabels);
[testFeatures, testLabels] = helperExtractHOGFeaturesFromImageSet(testSets, hogFeatureSize, cellSize);
% Make class predictions using the test features.
predictedLabels = predict(classifier, testFeatures);
% Tabulate the results using a confusion matrix.
confMat = confusionmat(testLabels, predictedLabels);
helperDisplayConfusionMatrix(confMat)

Answers (1)

As a debugging step, assign the output of the extraction to a variable, and then check the size of the variable compared to the size of your features array.
Note: your commented out img =imresize(img, .5); would not resize all of the images to the same size: it would resize them to half of the size they were. You would need to provide a particular target size instead of a ratio if you want to resize them to the same size.

23 Comments

From your advice, I added
first = extractHOGFeatures(img, 'CellSize', cellSize);
features(i, :) = extractHOGFeatures(img, 'CellSize', cellSize);
The matrix size of first and features differ in both row and column size. Comparing this to the digit classification example, where I also added the same line, first had value of 1x324 single while features had 101x324 single. So, the hint is to have the same column size? In fact, the variable, hog_4x4, is the same size as first, so that should be the case for my code as well?
Also, I don't think resizing all the images to same size is the answer because doing so gave me an error in the classification example too. I am pretty much doing the same as the example in http://www.mathworks.com/help/vision/examples/digit-classification-using-hog-features.html but yet, it doesn't yield the same result.
It is okay for the number of rows to not match as you are writing each "first" into a different row of "features".
In this current program, what shows up for size(first) and size(features), and what shows up for the value hogFeatureSize and for size(hog_4x4) ?
size(first) ans = 1 167256
size(features) ans = 170496
hogFeatureSize ans = 170496
size(hog_4x4) ans = 1 170496
The size changes each time I run the program, whereas in the original example, the column size didn't change.
size(features) would be a pair of numbers, you only showed one here.
If you look at http://www.mathworks.com/help/vision/ref/extracthogfeatures.html#output_argument_features then you can see that N will change depending on the size of the image, because the BlocksPerImage will change. You need to resize all of your images to be the same size that you used for the original "img" from your training set.
oops, sorry. size(features) ans = 40 170496
40 doesn't change as you might know already since a constant value is being used(trainingset is 30% of the imageset).
yea, i've done that above just before i divided the imageset into training and test sets with the following code:
for image = 1:numel(imgSets)
image = imresize(image, [20 20]);
end
it didn't work. could you pull me in the right direction to how i can do it? Maybe I didn't do it right.
That uses "image" as the name of a loop index, and assigns scalar numeric values from 1 to numel(imgSets) to "image". Inside the loop, it resizes the scalar numeric loop counter to be 20 x 20, and assigns the result on top of the loop counter. The next iteration of the loop, MATLAB ignores the change that has been made to the loop counter and goes on to the next scalar value. At no time was anything meaningful saved, and instead the important MATLAB graphics primitive image() has been interfered with.
Then later in your code you read() out of the partitioned imageSet, which effectively fetches a file name from its list of file names and imread()'s the file in. And you do not imresize() that result.
Do not try to imresize() at that stage. Just, after you first do
img = read(trainingSets(1), 2);
then add
train_img_size = size(img);
Then, inside your loop where you have
img = read(trainingSets(image), i);
after that add
img = imresize(img, train_img_size);
thank you. that helped get rid of the error. I'm sorry to bother you again but I received a new error after adding your lines.
Error using coder.internal.errorIf (line 8)
Function IMRESIZE expected input number 2, MAP, to be a valid colormap. Valid colormaps cannot have values
outside the range [0,1].
Error in iptcheckmap (line 47)
coder.internal.errorIf(true, 'images:validate:badMapValues', ...
Error in imresize>parsePreMethodArgs (line 343)
iptcheckmap(map, mfilename, 'MAP', 2);
Error in imresize>parseInputs (line 248)
[params.A, params.map, params.scale, params.output_size] = ...
Error in imresize (line 141)
params = parseInputs(varargin{:});
Error in hog_svm (line 61)
img = imresize(img, train_img_size);
Ah, you could get that if you had RGB images. The adjustment:
train_img_size = [size(img,1), size(img,2)]; %ignore additional planes
I see. That way, the dimensions of the colors are ignored. I came across this error.
Error using vertcat
Dimensions of matrices being concatenated are not consistent.
Error in hog_svm (line 50)
trainingLabels = [trainingLabels; labels];
The sizes of the following were:
trainingLabels = 20x9 char
labels = 20x5 char
I don't understand how trainingLabels came to a different size.
"Information about the image set, specified as a string. When you create an image set by recursively searching folders or by specifying a single folder location, the Description property is set to the folder name."
Notice this is just a string. So when you use
labels = repmat(trainingSets(image).Description, numImages, 1);
the trainingSets(image).Description part is extracting a string (that is to say, a row vector of char) and making vertical copies of it, ending up with a char array with the same width as the number of characters in the string.
Eventually there is a different folder name, which probably has a different width of string. So then when you use
trainingLabels = [trainingLabels; labels];
you are attempting to do a vertical concatenation of a char array of one width and a char array of a different width. That fails.
The fix is easy: change to
labels = repmat({trainingSets(image).Description}, numImages, 1);
Thank you.
This is probably the last error.
Subscripted assignment dimension mismatch.
Error in helperExtractHOGFeaturesFromImageSet (line 20)
features(j, :) = extractHOGFeatures(img,'CellSize',cellSize);
Error in hog_svm (line 96)
[testFeatures, testLabels] = helperExtractHOGFeaturesFromImageSet(testSets, hogFeatureSize, cellSize);
I know this occurred because the testset still has RGB images. In this case, the test features are being extracted from the set itself, rather than one image at a time, like for the trainingset. If I resized each image in the set like you showed previously, how would I save each new resized image back in the testset?
You need the resizing each time you pull out from the set. Do not save the resized image back.
Sometimes it makes sense to pre-process, to run through an image set and create resized versions of them that you save somewhere, and then create a new imageSet from the place you stored the resized versions.
Hi, using the 'train_img_size' variable to resize the images in test set, i added the following lines:
for image = 1:numel(testSets)
numImages = testSets(image).Count;
for i = 1:numImages
img = read(testSets(image), i);
img = imresize(img, train_img_size);
lvl = graythresh(img);
img = im2bw(img, lvl);
end
end
But I'm getting this error.
Subscripted assignment dimension mismatch.
Error in helperExtractHOGFeaturesFromImageSet (line 20)
features(j, :) = extractHOGFeatures(img,'CellSize',cellSize);
Error in hog_svm (line 84)
[testFeatures, testLabels] = helperExtractHOGFeaturesFromImageSet(testSets, hogFeatureSize, cellSize);
You do not call the hog routines in that loop. You do not do anything with the img after you convert it to bw
I'm sorry. Could you elaborate on that? Are you saying I should not do graythresh and im2bw for the testset? When I erased them, I still get the error.
Or that I should do the other hog routines that were done to the trainingset? Like I should do the extracthog for testset one image at a time, like it was done to the training set?
What I mean is that the error message you should is not possible with the code you show. You have shown us the wrong section of code.
This is the updated code.
rootFolder = fullfile('/Users/Bishwo/Downloads/101_ObjectCategories');
imgSets = [ imageSet(fullfile(rootFolder, 'airplanes')), ...
imageSet(fullfile(rootFolder, 'ferry')), ...
imageSet(fullfile(rootFolder, 'starfish')) ];
minSetCount = min([imgSets.Count]);
imgSets = partition(imgSets, minSetCount, 'randomize');
[trainingSets, testSets] = partition(imgSets, 0.3, 'randomize');
img = read(trainingSets(1), 2);
train_img_size = [size(img, 1), size(img, 2)];
for image = 1:numel(testSets)
numImages = testSets(image).Count;
for i = 1:numImages
img = read(testSets(image), i);
img = imresize(img, train_img_size);
lvl = graythresh(img);
img = im2bw(img, lvl);
end
end
% Extract HOG features and HOG visualization
[hog_4x4, vis4x4] = extractHOGFeatures(img,'CellSize',[4 4]);
cellSize = [4 4];
hogFeatureSize = length(hog_4x4);
trainingFeatures = [];
trainingLabels = [];
for image = 1:numel(trainingSets)
numImages = trainingSets(image).Count;
features = zeros(numImages, hogFeatureSize, 'single');
for i = 1:numImages
img = read(trainingSets(image), i);
img = imresize(img, train_img_size);
lvl = graythresh(img);
img = im2bw(img, lvl);
features(i, :) = extractHOGFeatures(img, 'CellSize', cellSize);
end
labels = repmat({trainingSets(image).Description}, numImages, 1);
trainingFeatures = [trainingFeatures; features];
trainingLabels = [trainingLabels; labels];
end
classifier = fitcecoc(trainingFeatures, trainingLabels);
[testFeatures, testLabels] = helperExtractHOGFeaturesFromImageSet(testSets, hogFeatureSize, cellSize);
% Make class predictions using the test features.
predictedLabels = predict(classifier, testFeatures);
% Tabulate the results using a confusion matrix.
confMat = confusionmat(testLabels, predictedLabels);
helperDisplayConfusionMatrix(confMat)
One issue I can think of is maybe the testLabels need to be processed like how the trainingLabels were?
Another thing I noticed was the 'warnings' on the variables, trainingFeatures and trainingLabels
trainingFeatures = [trainingFeatures; features];
trainingLabels = [trainingLabels; labels];
Warning says that they change size on every loop iteration. Could this be an issue?
Take a look at your code
for image = 1:numel(testSets)
numImages = testSets(image).Count;
for i = 1:numImages
img = read(testSets(image), i);
img = imresize(img, train_img_size);
lvl = graythresh(img);
img = im2bw(img, lvl);
end
end
Notice that after you im2bw(), you do not do anything with img, so it will be overwritten with the next iteration of "for i", and that will be carried out over the complete "for image". That is a waste of time, as the end result will be the same as if you had just processed the very last image of the very last set of images.
Do not name a variable "image"; doing so interferes with using the important graphics primitive image(), and confuses the other people reading your code.
The error you are running into is in your line
[testFeatures, testLabels] = helperExtractHOGFeaturesFromImageSet(testSets, hogFeatureSize, cellSize);
which looks like it is doing similar code. You do not show us that routine, though. You are not passing in train_img_size to that routine, so we need to assume that if it is resizing the images at all that it might be doing so to a different size.
I see. So, I've changed the HOG feature extraction to image by image. This way, train_img_size will be used in the testset.
rootFolder = fullfile('/Users/Bishwo/Downloads/101_ObjectCategories');
imgSets = [ imageSet(fullfile(rootFolder, 'airplanes')), ...
imageSet(fullfile(rootFolder, 'ferry')), ...
imageSet(fullfile(rootFolder, 'starfish')) ];
minSetCount = min([imgSets.Count]);
imgSets = partition(imgSets, minSetCount, 'randomize');
[trainingSets, testSets] = partition(imgSets, 0.3, 'randomize');
img = read(trainingSets(1), 2);
train_img_size = [size(img, 1), size(img, 2)];
% Extract HOG features and HOG visualization
[hog_4x4, vis4x4] = extractHOGFeatures(img,'CellSize',[4 4]);
cellSize = [4 4];
hogFeatureSize = length(hog_4x4);
trainingFeatures = [];
trainingLabels = [];
for pic = 1:numel(trainingSets)
numImages = trainingSets(pic).Count;
features = zeros(numImages, hogFeatureSize, 'single');
for i = 1:numImages
img = read(trainingSets(pic), i);
img = imresize(img, train_img_size);
lvl = graythresh(img);
img = im2bw(img, lvl);
features(i, :) = extractHOGFeatures(img, 'CellSize', cellSize);
end
labels = repmat({trainingSets(pic).Description}, numImages, 1);
trainingFeatures = [trainingFeatures; features];
trainingLabels = [trainingLabels; labels];
end
testFeatures = [];
testLabels = [];
for pic = 1:numel(testSets)
numImages = testSets(pic).Count;
tfeatures = zeros(numImages, hogFeatureSize, 'single');
for i = 1:numImages
img = read(testSets(pic), i);
img = imresize(img, train_img_size);
lvl = graythresh(img);
img = im2bw(img, lvl);
tfeatures(i, :) = extractHOGFeatures(img, 'CellSize', cellSize);
end
tlabels = repmat({testSets(pic).Description}, numImages, 1);
testFeatures = [testFeatures; tfeatures];
testLabels = [testLabels; tlabels];
end
classifier = fitcecoc(trainingFeatures, trainingLabels);
% [testFeatures, testLabels] = helperExtractHOGFeaturesFromImageSet(testSets, hogFeatureSize, cellSize);
% Make class predictions using the test features.
predictedLabels = predict(classifier, testFeatures);
% Tabulate the results using a confusion matrix.
confMat = confusionmat(testLabels, predictedLabels);
helperDisplayConfusionMatrix(confMat)
digit | 0 1 2 3 4 5 6 7 8 9
---------------------------------------------------------------------------------------------------
0 | 0.70 0.19 0.11
1 | 0.06 0.77 0.17
2 | 0.13 0.26 0.62
3 | Index exceeds matrix dimensions.
Error in helperDisplayConfusionMatrix (line 14)
fprintf('%-9.2f', confMat(idx,:));
Error in hog_svm_test (line 72)
helperDisplayConfusionMatrix(confMat)
Now, from the result, it looks like its trying to show the answer from that 'Digit Classification' example. Even the labels are from the example(digits 0-9), but I'm using the labels from my folders(airplanes, ferry, starfish). Am I not?
I just noticed. The very definition of "helperDisplayConfusionMatrix" has table made of digits. So I guess I just need to make my own table.
It would seem to make sense to put your HOG extraction code into a function in which you passed an imageSet and a target image size, and returned the feature matrix. That would save you from duplicating the code.

Sign in to comment.

Asked:

on 4 Apr 2016

Commented:

on 11 Apr 2016

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!