Display an image scale space in MATLAB - image

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:

Related

Index exceeds matrix dimensions when trying to access position vectors

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.

Draw a horizontal line on an image whose row corresponds to the largest count of dark pixels

I wish to draw a horizontal line on a binary image in MATLAB which has the maximum amount of black pixels. So in this word for example:
... I have to identify the horizontal line with most pixels.
I understand that I can open the binary image variable editor, and plot a row which has maximum zeroes however that doesn't seem to work.
I have to make a baseline of this word like this:
... as the output assuming that the maximum pixels lie where I drew the line.
Purely going by your definition, you want to figure out the row that has the largest amount of black pixels. Simply sum over all columns of each row and find the maximum. Then when you're done, locate the row with the largest count and set this line to red.
Something like this comes to mind. I'm going to read your image from StackOverflow directly and am going to use the image processing toolbox to help me with this analysis:
%// Read image from SO
im = imread('http://s15.postimg.org/cwg2sxnwr/mathworksss.png');
%// Keep a copy of a binary version
im_bw = im2bw(im);
%// Sum over all of the columns and look for dark pixels
row_sums = sum(~im_bw, 2);
%// Find row with max sum
[~,row_max] = max(row_sums);
%// Draw a red line through the original image as it's in RGB
im(row_max,:,1) = 255;
im(row_max,:,2:3) = 0;
%// Show the image
imshow(im);
The first image reads in the image directly from SO and puts it into the MATLAB workspace. The next line thresholds the image to binary to allow the analysis to be easier. We also keep a copy of the original image so we can mark the baseline with red. The next line after that uses sum and sums over every column of each row individually and adds up the black pixels. This is achieved by inverting the binary image so that dark pixels become bright to facilitate the summing. We then use max to figure out the row with the largest sum and that's done by looking at the second output of max. Once we find this location, we use this row and set all of the pixels in this row to red, or RGB = (255,0,0).
I get this image:
Now the above code draws a line from the left to the right. If you wanted to limit this and only draw a red line where there is text, perhaps find the left most and right most dark pixel and add a bit of breathing room to them, then draw a line through.... something like this comes to mind:
%// Read image from SO
im = imread('http://s15.postimg.org/cwg2sxnwr/mathworksss.png');
%// Keep a copy of a binary version
im_bw = im2bw(im);
%// Sum over all of the columns and look for dark pixels
row_sums = sum(~im_bw, 2);
%// Find row with max sum
[~,row_max] = max(row_sums);
%// Find left most and right most black columns
[~,left_most] = find(~im_bw,1,'first');
[~,right_most] = find(~im_bw,1,'last');
%// Buffer for drawing the line before the first and after the last column
buf = 20;
%// Draw the line
im(row_max,left_most-buf:right_most+buf,1) = 255;
im(row_max,left_most-buf:right_most+buf,2:3) = 0;
%// Show the image
imshow(im);
As you can see, most of the code remains the same (reading in the image, thresholding, column summing and max) but towards the end, I use find to find the first and last instance of a black pixel with respect to the columns. I then use these columns with the same maximum row found earlier, then subtracting the left most black column pixel location and adding the right most black column pixel location by a buffer amount (I chose 20 here), then setting the line of pixels within this region to red.
We get:
Now, it is your wish to find the row with the second highest sum and draw another line through that row. That's not bad to do. However, this will require some post-processing because the outer edges of each character is not a single pixel thick... so the second highest sum may actually still give you a row that is around the first maximum. As such, I would suggest shrinking the text slightly then applying the row sum logic again. You can do this with morphological binary erosion with a small structuring element... say, a 3 x 3 square. This can be done with imerode for the erosion and using strel to specify the square structuring element.
You'd apply the row sum logic to this new image, but then use these results and draw on the original image. You don't want to operate on this new image because it looks like there are some areas of the text that are a single pixel thick and these will be eliminated after erosion.
Something like this comes to mind:
%// Read image from SO
im = imread('http://s15.postimg.org/cwg2sxnwr/mathworksss.png');
%// Keep a copy of a binary version - also invert for ease
im_bw = ~im2bw(im);
%// Slightly erode the text
im_bw = imerode(im_bw, strel('square', 3));
%// Sum over all of the columns and look for dark pixels
row_sums = sum(im_bw, 2);
%// Sort the column sums in descending order and figure out the two highest sums
[~,ind_sort] = sort(row_sums,'descend');
%// First highest sum is the bottom - mark as red
red_row1 = ind_sort(1);
%// Second highest sum is the middle - mark as red too
red_row2 = ind_sort(2);
%// Find left most and right most black columns
[~,left_most] = find(im_bw,1,'first');
[~,right_most] = find(im_bw,1,'last');
%// Buffer for drawing the line before the first and after the last column
buf = 20;
%// Draw the two red lines
im(red_row1,left_most-buf:right_most+buf,1) = 255;
im(red_row1,left_most-buf:right_most+buf,2:3) = 0;
im(red_row2,left_most-buf:right_most+buf,1) = 255;
im(red_row2,left_most-buf:right_most+buf,2:3) = 0;
%// Show the image
imshow(im);
As you can see, most of the logic is the same. The only thing I really changed was that I eroded the image, sorted the row sums in descending order and extracted the first two locations that are the highest. I then repeated the logic to draw a line through the row, but instead of one row, we have two now.
We get:

Remove spacing in matlab subplot

How should i remove the empty space between these images?i need to combine all these images without any space.
bot=imread('bot.jpeg');
for i= 1:25
subplot(5,5,i),imshow(bot);
end
You need to specify axes' 'Position' property when you create them with subplot.
Also, you have to adjust figure aspect ratio to match that of the image, so that all figures fit without vertical or horizontal space.
If you show a different image in each subplot, all images should have the same aspect ratio, otherwise it's not possible for them to fit in the figure without empty spaces.
bot = imread('peppers.png');
for i= 1:25
subplot('Position',[(mod(i-1,5))/5 1-(ceil(i/5))/5 1/5 1/5])
imshow(bot); %// or show a different image on each subplot
end
p = get(gcf,'Position');
k = [size(bot,2) size(bot,1)]/(size(bot,2)+size(bot,1));
set(gcf,'Position',[p(1) p(2) (p(3)+p(4)).*k]) %// adjust figure x and y size
The most canonical way would be to take a look at this answer by bla here. This answer uses a function from the MATLAB File Exchange in order to achieve the answer. However, that requires learning a new function and playing around with the parameters.
If you want something working immediately, instead of showing each subimage in a separate grid on a plot, I would simply create a new image that stacks all of those images together:
bot_new = repmat(bot, [5 5]);
imshow(bot_new);
repmat takes a matrix and duplicates / stacks / tiles itself together for as many rows and as many columns (or in any dimension) that you want. In this case, I chose to stack the image so that there are 5 rows and 5 columns of it. We next show the stacked image together with imshow.
If we used an example image from MATLAB:
bot = imread('onion.png');
If we ran the above code that tiles the images together and showed the image, this is what we get:
I copy the answer from mathworks:
For each subplot, store its handle.
h = subplot(2,3,1);
Then set the 'position' property of h to be anything you want.
p = get(h, 'pos');
This is a 4-element vector [left, bottom, width, height] which
by default is in normalized coordinates (percentage of
figure window). For instance, to add 0.05 units (5% of
figure window) to the width, do this:
p(3) = p(3) + 0.05;
set(h, 'pos', p);
The SUBPLOT command picks standard values for these
parameters, but they could be anything you want. You
could put axes anywhere on the figure you want,
any size you want.
You can check for it:
http://www.mathworks.com/matlabcentral/newsreader/view_thread/144116

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