Image upsampling in MATLAB producing white images using image() and imshow() - image

When I display my reconstructed images, they are just white. Is there something obviously wrong with my program?
The reconstructed images should have the values of the downsampled image at one pixel in the upsampled 2x2 pixel block. The interpolation method I'm using here is simply taking the value from one row above and filling the next row with it, repeating this process for the columns.
%% Image Resampling
close all; clear all; clc;
s_dir=pwd;
cd Images;
I=imread('aivazovsky78g.tif','tif');
cd(s_dir)
[N M]=size(I);
figure;
imshow(I)
axis image; hold on;
for k=1:4
pause(1)
I=I(1:2:N, 1:2:M);
[N M]=size(I);
image(I)
end
%% Image Reconstruction
Irec=zeros(2*size(I));
for r=1:5
for n=1:N-1
for m=1:M-1
Irec(2*n-1,2*m-1)=I(n,m);
end
end
[N M]=size(Irec);
for n=2:2:N
for m=2:2:M
Irec(n,:)=Irec(n-1,:);
Irec(:,m)=Irec(:,m-1);
end
end
I=Irec;
figure;
imshow(I)
end

You may use B = imresize(A, scale, 'box') where a scale of 2 doubles the amount of pixels in x and y. The z dimension will still have the same value.
The resizing method box will copy the initial pixel value (i, j) to its 3 new neighbors (i+1, j), (i, j+1), and (i+1, j+1) - the same method you programmed.

Not the most efficient way, but here is a working code:
% 256x256 grayscale image
I = imread('cameraman.tif');
% double in size
I2 = zeros(2*size(I),class(I));
for i=1:2:size(I2,1)
for j=1:2:size(I2,2)
I2([i i+1],[j j+1]) = I((i-1)/2 + 1, (j-1)/2 + 1);
end
end
% compare against #Magla's solution
I3 = imresize(I,2,'box');
isequal(I2,I3)

Related

How to flip image in matlab without using built in functions?

Write a MATLAB code that reads a gray scale image and generates the flipped image of original image.enter image description here
i am trying this code but is not giving me correct flipped image.Help will be much appreciated.Thankyou
clear all
clc
a=imread('pout.tif');
[r,c]=size(a);
for i=r:-1:1
k=1;
for j=1:1:c
temp=a(k,j);
result(k,j)=a(i,j);
result(i,j)=temp;
k=k+1;
end
end
subplot(1,2,1), imshow(a)
subplot(1,2,2),imshow(result)
What you're doing with indices is kind of unclear. You should also pre-allocate memory for the result.
clear all
clc
a=imread('pout.tif');
[r,c]=size(a);
result = a; % preallocate memory for result
for i=1:r
for j=1:c
result(r-i+1,j)=a(i,j);
end
end
subplot(1,2,1), imshow(a)
subplot(1,2,2),imshow(result)
You can use basic indexing to flip a matrix. 2D case (gray-scale image):
a = a(:,end:-1:1); % horizontal flip
a = a(end:-1:1,:); % vertical flip
a = a(end:-1:1,end:-1:1); % flip both: 180 degree rotation
For the 3D case (color image) add a 3rd index ::
a = a(:,end:-1:1,:); % horizontal flip

Like an ordinary indexed image,in the figure’s colormap. The difference is that the matrix values are linearly

find pixels location that have value/color =white
for i=1:row
for j=1:colo
if i==x if the row of rgb image is the same of pixel location row
end
end
end
end
what's Wrong
You can use logical indexing.
For logical indexing to work, you need the mask (bw2) to be the same size as RGB.
Since RGB is 3D matrix, you need to duplicate bw2 three times.
Example:
%Read sample image.
RGB = imread('autumn.tif');
%Build mask.
bw2 = zeros(size(RGB, 1), size(RGB, 2));
bw2(1+(end-30)/2:(end+30)/2, 1+(end-30)/2:(end+30)/2) = 1;
%Convert bw2 mask to same dimensions as RGB
BW = logical(cat(3, bw2, bw2, bw2));
RGB(BW) = 255;
figure;imshow(RGB);
Result (just decoration):
In case you want to fix your for loops implementation, you can do it as follows:
[x, y] = find(bw2 == 1);
[row, colo, z]=size(RGB); %size of rgb image
for i=1:row
for j=1:colo
if any(i==x) %if the row of rgb image is the same of pixel location row
if any(j==y(i==x)) %if the colos of rgb image is the same of pixel loca colo
RGB(i,j,1)=255; %set Red color channel to 255
RGB(i,j,2)=255; %set Green color channel to 255
RGB(i,j,3)=255; %set Blue color channel to 255
end
end
end
end
[x, y] = find(bw2 == 1)
x and y are arrays unless there is only one pixel is white.
However, if i==x and if j==y are comparing a single number with an array. This is wrong.
As Anthony pointed out, x and y are arrays so i==x and j==y won't work as intended. Furthermore RGB(i,j) only uses the first two dimensions, but RGB images have three dimensions. Lastly, from an optimization point of view, the for-loops are unnecessary.
%% Create some mock data.
% Generate a black/white image.
bw2 = rand(10);
% Introduce some 1's in the BW image
bw2(1:5,1:5)=1;
% Generate a RGB image.
RGB = rand(10,10,3)*255;
%% Do the math.
% Build a mask from the bw2 image
bw_mask = bw2 == 1;
% Set RGB at bw_mask pixels to white.
RGB2 = bsxfun(#plus, bw_mask*255, bsxfun(#times, RGB, ~bw_mask)); % MATLAB 2016a and earlier
RGB2 = bw_mask*255 + RGB .* ~bw_mask; % MATLAB 2016b and later.

Re-sizing a rectangular image to a square image

I have an image, size 213 x 145 pixels. I want to resize it to 128 x 128 pixels for example. I've already tried the code below:
i = imread ('alif1.png');
I = imresize (i, [128 128], 'bilinear');
OR
i = imread ('alif1.png');
I = imresize (i, [128 128], 'lanczos3');
it gave me a square image, but the image became disproportionate. However, I believe the aspect ratio was preserved.
I want to resize the image to a square shape without distorting or stretching the image, rather to pad/crop the white background instead. I still can't figure out the right code. I hope anyone could help.
any help will be very much appreciated :)
I = imread('alifi.png');
Crop image, specifying crop rectangle.
I2 = imcrop(I,[75 68 128 128]);
Size and position of the crop rectangle, specified as a four-element position vector of the form [xmin ymin width height].
for more understanding follow this(matlab ) and this(blog) links.
If you want to resize (not crop) the image and keep the aspect ratio (so you don't loose any part of the image AND it doesn't get distorted), you can first add margins to make the image squared.
You can achieve this using the function padarray, or just creating a new image of zeros and then adding your image in the appropiate coordinates.
Once your image is squared, you can resize it to 128x128 using imresize.
In order to add margins, you will have to see where to add them (top&bottom OR left&right).
Also since padarray adds the same amount of margins in both sides, you have to check if the number you need is even. If it's odd add first a last row (or column) of zeros to your image.
So basically you have three options:
Make the image squared by not preserving aspect ratio (which is what you already tried)
Cropping the image as suggested by #ShvetChakra and #bla (but you will loose some image info)
Add margins to the image and resize (but you will end up with a squared image with margins)
Magic doesn't exist so "you must choose, but choose wisely"
(Quote from Indiana Jones and the Last Crusade).
EDIT:
% Example with a 5x2 image, so an extra column will be added
% in order to use padarray.
im = [1 2; 3 4; 5 6; 7 8; 9 10];
nrows = size(a,1);
ncols = size(a,2);
d = abs(ncols-nrows); % difference between ncols and nrows:
if(mod(d,2) == 1) % if difference is an odd number
if (ncols > nrows) % we add a row at the end
im = [im; zeros(1, ncols)];
nrows = nrows + 1;
else % we add a col at the end
im = [im zeros(nrows, 1)];
ncols = ncols + 1;
end
end
if ncols > nrows
im = padarray(im, [(ncols-nrows)/2 0]);
else
im = padarray(im, [0 (nrows-ncols)/2]);
end
% Here im is a 5x5 matix, not perfectly centered
% because we added an odd number of columns: 3

Extract a page from a uniform background in an image

If I have an image, in which there is a page of text shot on a uniform background, how can I auto detect the boundaries between the paper and the background?
An example of the image I want to detect is shown below. The images that I will be dealing with consist of a single page on a uniform background and they can be rotated at any angle.
One simple method would be to threshold the image by some known value once you convert the image to grayscale. The problem with that approach is that we are applying a global threshold and so some of the paper at the bottom of the image will be lost if you make the threshold too high. If you make the threshold too low, then you'll certainly get the paper, but you'll include a lot of the background pixels too and it will probably be difficult to remove those pixels with post-processing.
One thing I can suggest is to use an adaptive threshold algorithm. An algorithm that has worked for me in the past is the Bradley-Roth adaptive thresholding algorithm. You can read up about it here on a post I commented on a while back:
Bradley Adaptive Thresholding -- Confused (questions)
However, if you want the gist of it, an integral image of the grayscale version of the image is taken first. The integral image is important because it allows you to calculate the sum of pixels within a window in O(1) complexity. However, the calculation of the integral image is usually O(n^2), but you only have to do that once. With the integral image, you scan neighbourhoods of pixels of size s x s and you check to see if the average intensity is less than t% of the actual average within this s x s window then this is pixel classified as the background. If it's larger, then it's classified as being part of the foreground. This is adaptive because the thresholding is done using local pixel neighbourhoods rather than using a global threshold.
I've coded an implementation of the Bradley-Roth algorithm here for you. The default parameters for the algorithm are s being 1/8th of the width of the image and t being 15%. Therefore, you can just call it this way to invoke the default parameters:
out = adaptiveThreshold(im);
im is the input image and out is a binary image that denotes what belongs to foreground (logical true) or background (logical false). You can play around with the second and third input parameters: s being the size of the thresholding window and t the percentage we talked about above and can call the function like so:
out = adaptiveThreshold(im, s, t);
Therefore, the code for the algorithm looks like this:
function [out] = adaptiveThreshold(im, s, t)
%// Error checking of the input
%// Default value for s is 1/8th the width of the image
%// Must make sure that this is a whole number
if nargin <= 1, s = round(size(im,2) / 8); end
%// Default value for t is 15
%// t is used to determine whether the current pixel is t% lower than the
%// average in the particular neighbourhood
if nargin <= 2, t = 15; end
%// Too few or too many arguments?
if nargin == 0, error('Too few arguments'); end
if nargin >= 4, error('Too many arguments'); end
%// Convert to grayscale if necessary then cast to double to ensure no
%// saturation
if size(im, 3) == 3
im = double(rgb2gray(im));
elseif size(im, 3) == 1
im = double(im);
else
error('Incompatible image: Must be a colour or grayscale image');
end
%// Compute integral image
intImage = cumsum(cumsum(im, 2), 1);
%// Define grid of points
[rows, cols] = size(im);
[X,Y] = meshgrid(1:cols, 1:rows);
%// Ensure s is even so that we are able to index the image properly
s = s + mod(s,2);
%// Access the four corners of each neighbourhood
x1 = X - s/2; x2 = X + s/2;
y1 = Y - s/2; y2 = Y + s/2;
%// Ensure no co-ordinates are out of bounds
x1(x1 < 1) = 1;
x2(x2 > cols) = cols;
y1(y1 < 1) = 1;
y2(y2 > rows) = rows;
%// Count how many pixels there are in each neighbourhood
count = (x2 - x1) .* (y2 - y1);
%// Compute row and column co-ordinates to access each corner of the
%// neighbourhood for the integral image
f1_x = x2; f1_y = y2;
f2_x = x2; f2_y = y1 - 1; f2_y(f2_y < 1) = 1;
f3_x = x1 - 1; f3_x(f3_x < 1) = 1; f3_y = y2;
f4_x = f3_x; f4_y = f2_y;
%// Compute 1D linear indices for each of the corners
ind_f1 = sub2ind([rows cols], f1_y, f1_x);
ind_f2 = sub2ind([rows cols], f2_y, f2_x);
ind_f3 = sub2ind([rows cols], f3_y, f3_x);
ind_f4 = sub2ind([rows cols], f4_y, f4_x);
%// Calculate the areas for each of the neighbourhoods
sums = intImage(ind_f1) - intImage(ind_f2) - intImage(ind_f3) + ...
intImage(ind_f4);
%// Determine whether the summed area surpasses a threshold
%// Set this output to 0 if it doesn't
locs = (im .* count) <= (sums * (100 - t) / 100);
out = true(size(im));
out(locs) = false;
end
When I use your image and I set s = 500 and t = 5, here's the code and this is the image I get:
im = imread('http://i.stack.imgur.com/MEcaz.jpg');
out = adaptiveThreshold(im, 500, 5);
imshow(out);
You can see that there are some spurious white pixels at the bottom white of the image, and there are some holes we need to fill in inside the paper. As such, let's use some morphology and declare a structuring element that's a 15 x 15 square, perform an opening to remove the noisy pixels, then fill in the holes when we're done:
se = strel('square', 15);
out = imopen(out, se);
out = imfill(out, 'holes');
imshow(out);
This is what I get after all of that:
Not bad eh? Now if you really want to see what the image looks like with the paper segmented, we can use this mask and multiply it with the original image. This way, any pixels that belong to the paper are kept while those that belong to the background go away:
out_colour = bsxfun(#times, im, uint8(out));
imshow(out_colour);
We get this:
You'll have to play around with the parameters until it works for you, but the above parameters were the ones I used to get it working for the particular page you showed us. Image processing is all about trial and error, and putting processing steps in the right sequence until you get something good enough for your purposes.
Happy image filtering!

How can I draw a circle on an image in MATLAB?

I have an image in MATLAB:
im = rgb2gray(imread('some_image.jpg');
% normalize the image to be between 0 and 1
im = im/max(max(im));
And I've done some processing that resulted in a number of points that I want to highlight:
points = some_processing(im);
Where points is a matrix the same size as im with ones in the interesting points.
Now I want to draw a circle on the image in all the places where points is 1.
Is there any function in MATLAB that does this? The best I can come up with is:
[x_p, y_p] = find (points);
[x, y] = meshgrid(1:size(im,1), 1:size(im,2))
r = 5;
circles = zeros(size(im));
for k = 1:length(x_p)
circles = circles + (floor((x - x_p(k)).^2 + (y - y_p(k)).^2) == r);
end
% normalize circles
circles = circles/max(max(circles));
output = im + circles;
imshow(output)
This seems more than somewhat inelegant. Is there a way to draw circles similar to the line function?
You could use the normal PLOT command with a circular marker point:
[x_p,y_p] = find(points);
imshow(im); %# Display your image
hold on; %# Add subsequent plots to the image
plot(y_p,x_p,'o'); %# NOTE: x_p and y_p are switched (see note below)!
hold off; %# Any subsequent plotting will overwrite the image!
You can also adjust these other properties of the plot marker: MarkerEdgeColor, MarkerFaceColor, MarkerSize.
If you then want to save the new image with the markers plotted on it, you can look at this answer I gave to a question about maintaining image dimensions when saving images from figures.
NOTE: When plotting image data with IMSHOW (or IMAGE, etc.), the normal interpretation of rows and columns essentially becomes flipped. Normally the first dimension of data (i.e. rows) is thought of as the data that would lie on the x-axis, and is probably why you use x_p as the first set of values returned by the FIND function. However, IMSHOW displays the first dimension of the image data along the y-axis, so the first value returned by FIND ends up being the y-coordinate value in this case.
This file by Zhenhai Wang from Matlab Central's File Exchange does the trick.
%----------------------------------------------------------------
% H=CIRCLE(CENTER,RADIUS,NOP,STYLE)
% This routine draws a circle with center defined as
% a vector CENTER, radius as a scaler RADIS. NOP is
% the number of points on the circle. As to STYLE,
% use it the same way as you use the rountine PLOT.
% Since the handle of the object is returned, you
% use routine SET to get the best result.
%
% Usage Examples,
%
% circle([1,3],3,1000,':');
% circle([2,4],2,1000,'--');
%
% Zhenhai Wang <zhenhai#ieee.org>
% Version 1.00
% December, 2002
%----------------------------------------------------------------
Funny! There are 6 answers here, none give the obvious solution: the rectangle function.
From the documentation:
Draw a circle by setting the Curvature property to [1 1]. Draw the circle so that it fills the rectangular area between the points (2,4) and (4,6). The Position property defines the smallest rectangle that contains the circle.
pos = [2 4 2 2];
rectangle('Position',pos,'Curvature',[1 1])
axis equal
So in your case:
imshow(im)
hold on
[y, x] = find(points);
for ii=1:length(x)
pos = [x(ii),y(ii)];
pos = [pos-0.5,1,1];
rectangle('position',pos,'curvature',[1 1])
end
As opposed to the accepted answer, these circles will scale with the image, you can zoom in an they will always mark the whole pixel.
Hmm I had to re-switch them in this call:
k = convhull(x,y);
figure;
imshow(image); %# Display your image
hold on; %# Add subsequent plots to the image
plot(x,y,'o'); %# NOTE: x_p and y_p are switched (see note below)!
hold off; %# Any subsequent plotting will overwrite the image!
In reply to the comments:
x and y are created using the following code:
temp_hull = stats_single_object(k).ConvexHull;
for k2 = 1:length(temp_hull)
i = i+1;
[x(i,1)] = temp_hull(k2,1);
[y(i,1)] = temp_hull(k2,2);
end;
it might be that the ConvexHull is the other way around and therefore the plot is different. Or that I made a mistake and it should be
[x(i,1)] = temp_hull(k2,2);
[y(i,1)] = temp_hull(k2,1);
However the documentation is not clear about which colum = x OR y:
Quote: "Each row of the matrix contains the x- and y-coordinates of one vertex of the polygon. "
I read this as x is the first column and y is the second colum.
In newer versions of MATLAB (I have 2013b) the Computer Vision System Toolbox contains the vision.ShapeInserter System object which can be used to draw shapes on images. Here is an example of drawing yellow circles from the documentation:
yellow = uint8([255 255 0]); %// [R G B]; class of yellow must match class of I
shapeInserter = vision.ShapeInserter('Shape','Circles','BorderColor','Custom','CustomBorderColor',yellow);
I = imread('cameraman.tif');
circles = int32([30 30 20; 80 80 25]); %// [x1 y1 radius1;x2 y2 radius2]
RGB = repmat(I,[1,1,3]); %// convert I to an RGB image
J = step(shapeInserter, RGB, circles);
imshow(J);
With MATLAB and Image Processing Toolbox R2012a or newer, you can use the viscircles function to easily overlay circles over an image. Here is an example:
% Plot 5 circles at random locations
X = rand(5,1);
Y = rand(5,1);
% Keep the radius 0.1 for all of them
R = 0.1*ones(5,1);
% Make them blue
viscircles([X,Y],R,'EdgeColor','b');
Also, check out the imfindcircles function which implements the Hough circular transform. The online documentation for both functions (links above) have examples that show how to find circles in an image and how to display the detected circles over the image.
For example:
% Read the image into the workspace and display it.
A = imread('coins.png');
imshow(A)
% Find all the circles with radius r such that 15 ≤ r ≤ 30.
[centers, radii, metric] = imfindcircles(A,[15 30]);
% Retain the five strongest circles according to the metric values.
centersStrong5 = centers(1:5,:);
radiiStrong5 = radii(1:5);
metricStrong5 = metric(1:5);
% Draw the five strongest circle perimeters.
viscircles(centersStrong5, radiiStrong5,'EdgeColor','b');
Here's the method I think you need:
[x_p, y_p] = find (points);
% convert the subscripts to indicies, but transposed into a row vector
a = sub2ind(size(im), x_p, y_p)';
% assign all the values in the image that correspond to the points to a value of zero
im([a]) = 0;
% show the new image
imshow(im)

Resources