Index exceeds matrix dimensions when trying to access position vectors - image

I am simply reading an image and wish to visualize the bounding boxes returned by blob analysis of matlab which returns position vectors.
Here is my code
img = imread(file_name);
img = im2bw(img);
gblob = vision.BlobAnalysis('AreaOutputPort', true, ... % Set blob analysis handling
'CentroidOutputPort', true, ...
'BoundingBoxOutputPort', true', ...
'MinimumBlobArea', 0, ...
'MaximumBlobArea', 600000, ...
'MaximumCount', 1000, ...
'MajorAxisLengthOutputPort',true, ...
'MinorAxisLengthOutputPort',true, ...
'OrientationOutputPort',true);
[Area,centroid, bbox, MajorAxis, MinorAxis,Orientation] = step(gblob, img);
% each bbox is position vector of the form [x y width height]
for i = 1:1:length(MajorAxis)
figure;imshow(img(bbox(i,2):bbox(i,2) + bbox(i,4),bbox(i,1):bbox(i,1)+bbox(i,3)));
end
On doing so i get an error Index exceeds matrix dimensions. I have also tried
figure;imshow(img(bbox(i,1):bbox(i,1) + bbox(i,3),bbox(i,2):bbox(i,2)+bbox(i,4)));
but i still end up getting the same error.
here is a sample image where this code gives an error

It's a simple case of mis-indexing. The blob detector returns the x and y coordinates of the top left corner of the blob. x in this case are the horizontal coordinates while y is the vertical. Therefore, you simply need to swap how you're accessing the image as the vertical needs to come first, then horizontal after.
Also with regards to your image, I would invert the image because the object would be considered as a dark object on white background once you convert it to binary. The blob detector works by detecting white objects on black background. Therefore, invert the image and do some morphological closing to clean up the noise once that happens:
img = imread('http://www.aagga.com/wp-content/uploads/2016/02/Sample.jpg');
img = ~im2bw(img); %// Change - invert
img_clean = imclose(img, strel('square', 7)); %// Change, clean the image
I get this image now:
imshow(img_clean);
Not bad.... now run your actual blob detector. Take note that the image you put inside the blob detector is the run variable name. You'll need to call it img_clean now:
gblob = vision.BlobAnalysis('AreaOutputPort', true, ...
'CentroidOutputPort', true, ...
'BoundingBoxOutputPort', true', ...
'MinimumBlobArea', 0, ...
'MaximumBlobArea', 600000, ...
'MaximumCount', 1000, ...
'MajorAxisLengthOutputPort',true, ...
'MinorAxisLengthOutputPort',true, ...
'OrientationOutputPort',true);
[Area,centroid, bbox, MajorAxis, MinorAxis,Orientation] = step(gblob, img_clean);
Now finally extract out each blob:
% each bbox is position vector of the form [x y width height]
for i = 1:1:length(MajorAxis)
figure;
imshow(img_clean(bbox(i,2):bbox(i,2) + bbox(i,4),bbox(i,1):bbox(i,1)+bbox(i,3))); %// Change
end
I now get the following 9 figures:
Take note that the above isn't perfect because the perimeter of the sign is disconnected so the blob detector will interpret this as different blobs. One way you could combat this is to vary the threshold of the image, or perhaps use graythresh to perform adaptive thresholding so you can ensure that the border is connected properly. However, this is a good way to start tackling your problem.
Minor Note
A much easier way to do this is to do away with the Computer Vision Toolbox and use the Image Processing Toolbox. Specifically use regionprops and use the Image property to extract out the actual images that the blobs contain themselves:
%// Code from before
img = imread('http://www.aagga.com/wp-content/uploads/2016/02/Sample.jpg');
img = ~im2bw(img); %// Change - invert
img_clean = imclose(img, strel('square', 7)); %// Change, clean the image
%// Create regionprops structure with desired properties
out = regionprops(img_clean, 'BoundingBox', 'Image');
%// Cycle through each blob and show the image
for ii = 1 : numel(out)
figure;
imshow(out(ii).Image);
end
This should achieve the same thing as I showed you above. You can look at the documentation for more details on what kinds of properties regionprops returns for you per blob.

Related

need to plot a 2D graph of the gray image intensity in matlab

what I am trying is to compare two gray scale images by ploting their intensity into graph. The code is bellow is for single image.
img11 = imread('img.bmp');
[rows cols ColorChannels] = size(img11);
for i=1:cols
for j=1:rows
intensityValue = img11(j,i);
end
end
% below trying different plot method
plot(intensityValue);
plot(1:length(img11),img11);
plot(img11(:))
My expected result for two images is like below pictures: here
not like
this here
Based on your code you should be able to do the following.
img11 = imread('img1.bmp');
img22 = imread('img2.bmp');
figure;
imagesc(img11); % verify you image
figure;
plot(img11(:)); hold on;
plot(img22(:));
Using the command (:) will flatten a matrix into a single vector starting at the top left and going down in columns. If that is not the orientation that you want you try to rotate/transpose the image (or try using reshape(), but it might be confusing at the start). Additionally, if your image has large variations in the pixel intensity moving average filter can be useful.
Len = 128;
smooth_vector = filter(ones(Len,1)/Len,1,double(img11(:)));
figure; plot(smooth_vector);

How to rescale the intensity range of a grayscale 3 dimension image (x,y,z) using Matlab

I can't find information online about the intensity rescaling of a 3D image made of several 2D images.
I'm looking for the same function as imadjust which only works for 2D images.
My 3D image is the combination of 2D images stacked together but I have to process the 3D image and not the 2D images one by one.
I can't loop imadjust because I want to process the images as one, to consider all the information available, in all directions.
For applying imadjust for set of 2D grayscale images taking the whole value into account, this trick might work
a = imread('pout.tif');
a = imresize(a,[256 256]); %// re-sizing to match image b's dimension
b = imread('cameraman.tif');
Im = cat(3,a,b);
%//where a,b are separate grayscale images of same dimensions
%// if you have the images separately you could edit this line to
%// Im = cat(2,a,b);
%// and also avoid the next step
%// reshaping into a 2D matrix to apply imadjust
Im = reshape(Im,size(Im,1),[]);
out = imadjust(Im); %// applying imadjust
%// finally reshaping back to its original shape
out = reshape(out,size(a,1),size(a,2),[]);
To check:
x = out(:,:,1);
y = out(:,:,2);
As you could see from the Workspace image, the first image (variable x) is not re-scaled to 0-255 as its previous range (variable a) was not near the 0 point.
WorkSpace:
Edit: You could do this as a one-step process like this: (as the other answer suggests)
%// reshaping to single column using colon operator and then using imadjust
%// then reshaping it back
out = reshape(imadjust(Image3D(:)),size(Image3D));
Edit2:
As you have image as cell arrays in I2, try this:
I2D = cat(2,I2{:})
The only way to do this for 3D image is to treat the data as a vector and then reshape back.
Something like this:
%create a random 3D image.
x = rand(10,20,30);
%adjust intensity range
x_adj = imadjust( x(:), size(x) );

Display an image scale space in MATLAB

I have 8 images and I want to show them in a scale-space format shown below. The original image height and width is 256. Then on right side of original image, at every level the size is reduced by 2. Like here, image height and width is 256. On the right side of original image, height and width is 128, 64, 32, 16, 8, 4 , 2.
I have all the images in their respective dimensions. I just want to know how do I arrange the images according the pattern shown below. Thanks in advance.
This looks like you are trying to build a scale-space and displaying the results to the user. This isn't a problem to do. Bear in mind that you will have to do this with for loops, as I don't see how you will be able to do this unless you copy and paste several lines of code. Actually, I'm going to use a while loop, and I'll tell you why soon.
In any case, you need to declare an output image that has as many rows as the original image, but the columns will be 1.5 times the original image to accommodate for the images on the right.
First, write code that places the original image on the left side, and the version that is half the size on the right. Once you do this, you write a for loop, use indexing to place the images in the right spots until you run out of scales, and you need to keep track of where the next image starts and next image ends. Bear in mind that the origin of where to write the next images after the first subsampled one will start at the column location of the original image, and the row is right where the previous one ends. As an example, let's use the cameraman.tif image that is exactly 256 x 256, but I will write code so that it fits any image resolution you want. When I subsample the image, I will use imresize in MATLAB to help with the resizing of the image, and I'll specify a sampling factor of 0.5 to denote the subsampling by 2. The reason why I would use a while loop instead, is because we can keep looping and resizing until one of the dimensions of the resized image is 1. When this is the case, there are no more scales to process, and so we can exit.
As such:
%// Read in image and get dimensions
im = imread('cameraman.tif');
[rows,cols] = size(im);
%// Declare output image
out = zeros(rows, round(1.5*cols), 'uint8');
out(:,1:cols) = im; %// Place original image to the left
%// Find first subsampled image, then place in output image
im_resize = imresize(im, 0.5, 'bilinear');
[rows_resize, cols_resize] = size(im_resize);
out(1:rows_resize,cols+1:cols+cols_resize) = im_resize;
%// Keep track of the next row we need to write at
rows_counter = rows_resize + 1;
%// For the rest of the scales...
while (true)
%// Resize the image
im_resize = imresize(im_resize, 0.5, 'bilinear');
%// Get the dimensions
[rows_resize, cols_resize] = size(im_resize);
%// Write to the output
out(rows_counter:rows_counter+rows_resize-1, cols+1:cols+cols_resize) = ...
im_resize;
%// Move row counter over for writing the next image
rows_counter = rows_counter + rows_resize;
%// If either dimension gives us 1, there are no more scales
%// to process, so exit.
if rows_resize == 1 || cols_resize == 1
break;
end
end
%// Show the image
figure;
imshow(out);
This is the image I get:

How to process a "Very Large image file" in MATLAB and find out the pixel with largest value

I have to process a very large image ( say 10 MB image file or even more).I have to remove artifacts and dead pixels in MATLAB
I have read about Block Processing of Large Images, but have no idea how to apply it to a 16 bit image.
I am referring to removal of pixels which have highest value into the average value of surrounding pixel .my code is not working on my image which is 80 MB of size
numIterations = 30;
avgPrecisionSize = 16; % smaller is better, but takes longer
% Read in the image grayscale:
originalImage = double(rgb2gray(imread('C:\Documents and Settings\admin\Desktop\TM\image5.tif')));
% get the bad pixels where = 0 and dilate to make sure they get everything:
badPixels = (originalImage == 0);
badPixels = imdilate(badPixels, ones(12));
%# Create a big gaussian and an averaging kernel to use:
G = fspecial('gaussian',[1 1]*100,50);
H = fspecial('average', [1,1]*avgPrecisionSize);
%# User a big filter to get started:
newImage = imfilter(originalImage,G,'same');
newImage(~badPixels) = originalImage(~badPixels);
% Now average to
for count = 1:numIterations
newImage = imfilter(newImage, H, 'same');
newImage(~badPixels) = originalImage(~badPixels);
end
%% Plot the results
figure(123);
clf;
% Display the mask:
subplot(1,2,1);
imagesc(badPixels);
axis image
title('Region Of the Bad Pixels');
% Display the result:
subplot(1,2,2);
imagesc(newImage);
axis image
set(gca,'clim', [0 255])
title('Infilled Image');
colormap gray
newImage2 = roifill(originalImage, badPixels);
figure(44);
clf;
imagesc(newImage2);
colormap gray
You are doing a few things which are obvious problems (but it might depend specifically on how far you can get into the code before you run out of memory)
1) You are immediately converting the whole image to double
2) You are identifying certain pixels which you want to replace, but passing the whole image to imfilter and then throwing away (presumably) most of the output:
newImage = imfilter(originalImage,G,'same'); % filter across the entire image
newImage(~badPixels) = originalImage(~badPixels); % replace all the good pixels!
Without converting to double, why not first check where the bad pixels are, do your processing on subregions of the appropriate size around those pixels (the subregions can be converted to double and back), and then reassemble the image at the end?
blockproc may work if you can write your filtering option as a function which takes in an image area and returns the correct area - you'll have to use the border_size option appropriately and make sure your function just returns the original image without bothering to do any filtering if it hits a block with no bad pixels in. You can even have it write out to file as well.

How can I "plot" an image on top of another image with a different colormap?

I've got two images, one 100x100 that I want to plot in grayscale and one 20x20 that I want to plot using another colormap. The latter should be superimposed on the former.
This is my current attempt:
A = randn(100);
B = ones(20);
imagesc(A);
colormap(gray);
hold on;
imagesc(B);
colormap(jet);
There are a couple of problems with this:
I can't change the offset of the smaller image. (They always share the upper-left pixel.)
They have the same colormap. (The second colormap changes the color of all pixels.)
The pixel values are normalised over the composite image, so that the first image changes if the second image introduces new extreme values. The scalings for the two images should be separate.
How can I fix this?
I want an effect similar to this, except that my coloured overlay is rectangular and not wibbly:
Just change it so that you pass in a full and proper color matrix for A (i.e. 100x100x3 matrix), rather than letting it decide:
A = rand(100); % Using rand not randn because image doesn't like numbers > 1
A = repmat(A, [1, 1, 3]);
B = rand(20); % Changed to rand to illustrate effect of colormap
imagesc(A);
hold on;
Bimg = imagesc(B);
colormap jet;
To set the position of B's image within its parent axes, you can use its XData and YData properties, which are both set to [1 20] when this code has completed. The first number specifies the coordinate of the leftmost/uppermost point in the image, and the second number the coordinate of the rightmost/lowest point in the image. It will stretch the image if it doesn't match the original size.
Example:
xpos = get(Bimg, 'XData');
xpos = xpos + 20; % shift right a bit
set(Bimg, 'XData', xpos);

Resources