Expanding a 2D Matrix in Matlab with Interpolation - matlab

Let's say I have a 4 pixel by 4 pixel image with values between 0 and 255 and I want to expand it to an 8-by-8 image, interpolating where necessary. I know how to interpolate a vector this way with interp1:
interp1(linspace(0,1,numel(vector)), vector, linspace(0,1,newSize))
But I'm unclear how to use interp2 to do the same thing for a matrix.
EDIT: Would it be the same if I were to create a meshgrid after using linspace for each dimension?
EDIT2: Yep, that worked. It's the same, but with a meshgrid.

For data structured in the form of a regular grid, you can use interp2 as you correctly stated, but since you are dealing with an image, I suggest you to use the imresize function, which is fine-tuned for rescaling images using appropriate interpolation algorithms:
% Load an image and display it...
img = imread('peppers.png');
figure(),imshow(img);
% Create a second image that is
% twice the size of the original
% one and display it...
img2 = imresize(img,2);
figure(),imshow(img2);
Anyway, if you really want to use the aforementioned function, here is how I would perform the interpolation:
% Load an image, convert it into double format
% and retrieve its basic properties...
img = imread('rice.png');
img = im2double(img);
[h,w] = size(img);
% Perform the interpolation...
x = linspace(1,w,w*2);
y = linspace(1,h,h*2);
[Xq,Yq] = meshgrid(x,y);
img2 = interp2(img,Xq,Yq,'cubic') ./ 255;
% Display the original image...
figure(),imshow(img);
%Display the rescaled image...
figure(),imshow(img2,[]);

Related

Dividing image into blocks in Matlab [duplicate]

I've been using blockproc for processing images blockwise. Unfortunately, blockproc is part of the Image Processing Toolbox, which I don't have on my personal computer.
Is there a combination of functions in base Matlab that can substitute for blockproc?
My initial guess was to use im2col to transform each block into columns, and then arrayfun to process each column. Then I realized that im2col is also a part of the Image Processing Toolbox, so that doesn't solve my problem.
Here is an example using MAT2CELL. It dividing the image into N-by-M tiles, and handles the case when the image size is not evenly divisible by the number of tiles.
%# 2D grayscale image
I = imread('coins.png');
%# desird number of horizontal/vertical tiles to divide the image into
numBlkH = 4;
numBlkW = 4;
%# compute size of each tile in pixels
[imgH,imgW,~] = size(I);
szBlkH = [repmat(fix(imgH/numBlkH),1,numBlkH-1) imgH-fix(imgH/numBlkH)*(numBlkH-1)];
szBlkW = [repmat(fix(imgW/numBlkW),1,numBlkW-1) imgW-fix(imgW/numBlkW)*(numBlkW-1)];
%# divide into tiles, and linearize using a row-major order
C = mat2cell(I, szBlkH, szBlkW)';
C = C(:);
%# display tiles i subplots
figure, imshow(I)
figure
for i=1:numBlkH*numBlkW
subplot(numBlkH,numBlkW,i), imshow( C{i} )
end
The input image and the resulting tiles:
Won't mat2tiles together with cellfun and cell2mat do more or less what blockproc does?
You could write a wrapper yourself to make it use the same arguments as blockproc, I don't think it should be that hard to do.

Apply a gaussian distribution in a specific part of an image

I have for example the following image and a corresponding mask.
I would like to weight the pixels inside the white circle with a Gaussian, g = #(x,y,xc,yc) exp(-( ((x-xc)^2)/0.5 + ((y-yc)^2)/0.5 ));, placed in the centroid (xc,yc) of the mask. x, y are the coordinates of the corresponding pixels. Could you please someone suggest a way to do that without using for loops?
Thanks.
By "weighting" pixels inside the ellipse, I assume you mean multiply elementwise by a 2D gaussian. If so, here's the code:
% Read images
img = imread('img.jpg');
img = im2double(rgb2gray(img));
mask = imread('mask.jpg');
mask = im2double(rgb2gray(mask)) > 0.9; % JPG Compression resulted in some noise
% Gaussian function
g = #(x,y,xc,yc) exp(-(((x-xc).^2)/500+((y-yc).^2)./200)); % Should be modified to allow variances as parameters
% Use rp to get centroid and mask
rp_mask = regionprops(mask,'Centroid','BoundingBox','Image');
% Form coordinates
centroid = round(rp_mask.Centroid);
[coord_x coord_y] = meshgrid(ceil(rp_mask.BoundingBox(1)):ceil(rp_mask.BoundingBox(1))+rp_mask.BoundingBox(3)-1, ...
ceil(rp_mask.BoundingBox(2)):ceil(rp_mask.BoundingBox(2))+rp_mask.BoundingBox(4)-1);
% Get Gaussian Mask
gaussian_mask = g(coord_x,coord_y,centroid(1),centroid(2));
gaussian_mask(~rp_mask.Image) = 1; % Set values outside ROI to 1, this negates weighting outside ROI
% Apply Gaussian - Can use temp variables to make this shorter
img_g = img;
img_g(ceil(rp_mask.BoundingBox(2)):ceil(rp_mask.BoundingBox(2))+rp_mask.BoundingBox(4)-1, ...
ceil(rp_mask.BoundingBox(1)):ceil(rp_mask.BoundingBox(1))+rp_mask.BoundingBox(3)-1) = ...
img(ceil(rp_mask.BoundingBox(2)):ceil(rp_mask.BoundingBox(2))+rp_mask.BoundingBox(4)-1, ...
ceil(rp_mask.BoundingBox(1)):ceil(rp_mask.BoundingBox(1))+rp_mask.BoundingBox(3)-1) .* gaussian;
% Show
figure, imshow(img_g,[]);
The result:
If you instead want to perform some filtering within that roi, there's a function called roifilt2 which will allow you to filter the image within that region as well:
img_filt = roifilt2(fspecial('gaussian',[21 21],10),img,mask);
figure, imshow(img_filt,[]);
The result:

How to plot a 2D FFT in Matlab?

I am using fft2 to compute the Fourier Transform of a grayscale image in MATLAB.
What is the common way to plot the magnitude of the result?
Assuming that I is your input image and F is its Fourier Transform (i.e. F = fft2(I))
You can use this code:
F = fftshift(F); % Center FFT
F = abs(F); % Get the magnitude
F = log(F+1); % Use log, for perceptual scaling, and +1 since log(0) is undefined
F = mat2gray(F); % Use mat2gray to scale the image between 0 and 1
imshow(F,[]); % Display the result
Here is an example from my HOW TO Matlab page:
close all; clear all;
img = imread('lena.tif','tif');
imagesc(img)
img = fftshift(img(:,:,2));
F = fft2(img);
figure;
imagesc(100*log(1+abs(fftshift(F)))); colormap(gray);
title('magnitude spectrum');
figure;
imagesc(angle(F)); colormap(gray);
title('phase spectrum');
This gives the magnitude spectrum and phase spectrum of the image. I used a color image, but you can easily adjust it to use gray image as well.
ps. I just noticed that on Matlab 2012a the above image is no longer included. So, just replace the first line above with say
img = imread('ngc6543a.jpg');
and it will work. I used an older version of Matlab to make the above example and just copied it here.
On the scaling factor
When we plot the 2D Fourier transform magnitude, we need to scale the pixel values using log transform to expand the range of the dark pixels into the bright region so we can better see the transform. We use a c value in the equation
s = c log(1+r)
There is no known way to pre detrmine this scale that I know. Just need to
try different values to get on you like. I used 100 in the above example.

Is there a substitute for blockproc in Matlab?

I've been using blockproc for processing images blockwise. Unfortunately, blockproc is part of the Image Processing Toolbox, which I don't have on my personal computer.
Is there a combination of functions in base Matlab that can substitute for blockproc?
My initial guess was to use im2col to transform each block into columns, and then arrayfun to process each column. Then I realized that im2col is also a part of the Image Processing Toolbox, so that doesn't solve my problem.
Here is an example using MAT2CELL. It dividing the image into N-by-M tiles, and handles the case when the image size is not evenly divisible by the number of tiles.
%# 2D grayscale image
I = imread('coins.png');
%# desird number of horizontal/vertical tiles to divide the image into
numBlkH = 4;
numBlkW = 4;
%# compute size of each tile in pixels
[imgH,imgW,~] = size(I);
szBlkH = [repmat(fix(imgH/numBlkH),1,numBlkH-1) imgH-fix(imgH/numBlkH)*(numBlkH-1)];
szBlkW = [repmat(fix(imgW/numBlkW),1,numBlkW-1) imgW-fix(imgW/numBlkW)*(numBlkW-1)];
%# divide into tiles, and linearize using a row-major order
C = mat2cell(I, szBlkH, szBlkW)';
C = C(:);
%# display tiles i subplots
figure, imshow(I)
figure
for i=1:numBlkH*numBlkW
subplot(numBlkH,numBlkW,i), imshow( C{i} )
end
The input image and the resulting tiles:
Won't mat2tiles together with cellfun and cell2mat do more or less what blockproc does?
You could write a wrapper yourself to make it use the same arguments as blockproc, I don't think it should be that hard to do.

How can I implement a fisheye lens effect (barrel transformation) in MATLAB?

How can one implement the fisheye lens effect illustrated in that image:
One can use Google's logo for a try:
BTW, what's the term for it?
I believe this is typically referred to as either a "fisheye lens" effect or a "barrel transformation". Here are two links to demos that I found:
Sample code for how you can apply fisheye distortions to images using the 'custom' option for the function maketform from the Image Processing Toolbox.
An image processing demo which performs a barrel transformation using the function tformarray.
Example
In this example, I started with the function radial.m from the first link above and modified the way it relates points between the input and output spaces to create a nice circular image. The new function fisheye_inverse is given below, and it should be placed in a folder on your MATLAB path so you can use it later in this example:
function U = fisheye_inverse(X, T)
imageSize = T.tdata(1:2);
exponent = T.tdata(3);
origin = (imageSize+1)./2;
scale = imageSize./2;
x = (X(:, 1)-origin(1))/scale(1);
y = (X(:, 2)-origin(2))/scale(2);
R = sqrt(x.^2+y.^2);
theta = atan2(y, x);
cornerScale = min(abs(1./sin(theta)), abs(1./cos(theta)));
cornerScale(R < 1) = 1;
R = cornerScale.*R.^exponent;
x = scale(1).*R.*cos(theta)+origin(1);
y = scale(2).*R.*sin(theta)+origin(2);
U = [x y];
end
The fisheye distortion looks best when applied to square images, so you will want to make your images square by either cropping them or padding them with some color. Since the transformation of the image will not look right for indexed images, you will also want to convert any indexed images to RGB images using ind2rgb. Grayscale or binary images will also work fine. Here's how to do this for your sample Google logo:
[X, map] = imread('logo1w.png'); % Read the indexed image
rgbImage = ind2rgb(X, map); % Convert to an RGB image
[r, c, d] = size(rgbImage); % Get the image dimensions
nPad = (c-r)/2; % The number of padding rows
rgbImage = cat(1, ones(nPad, c, 3), rgbImage, ones(nPad, c, 3)); % Pad with white
Now we can create the transform with maketform and apply it with imtransform (or imwarp as recommended in newer versions):
options = [c c 3]; % An array containing the columns, rows, and exponent
tf = maketform('custom', 2, 2, [], ... % Make the transformation structure
#fisheye_inverse, options);
newImage = imtransform(rgbImage, tf); % Transform the image
imshow(newImage); % Display the image
And here's the image you should see:
You can adjust the degree of distortion by changing the third value in the options array, which is the exponential power used in the radial deformation of the image points.
I think you are referring to the fisheye lens effect. Here is some code for imitating fisheye in matlab.
Just for the record:
This effect is a type of radial distortion called "barrel distortion".
For more information please see:
http: //en.wikipedia.org/wiki/Distortion_(optics)
Here is a different method to apply an effect similar to barrel distortion using texture mapping (adapted from MATLAB Documentation):
[I,map] = imread('logo.gif');
[h,w] = size(I);
sphere;
hS = findobj('Type','surface');
hemisphere = [ones(h,w),I,ones(h,w)];
set(hS,'CData',flipud(hemisphere),...
'FaceColor','texturemap',...
'EdgeColor','none')
colormap(map)
colordef black
axis equal
grid off
set(gca,'xtick',[],'ztick',[],'ytick',[],'box','on')
view([90 0])
This will give you the circular frame you are looking for but the aliasing artifacts might be too much to deal with.