Why does downsample appear as a gray image? - image

In the implementation of downsampling by a factor of 2 to the image, the downsampled image is gray. What should I do in order to add all of the color components to the downsampling implementation so that it will be a color image?
I = imread('lena.gif','gif');
[j k] = size(I)
x_new = j./2;
y_new = k./2;
x_scale = j./x_new;
y_scale = k./y_new;
M = zeros(x_new,y_new);
for count1 = 1:x_new
for count2 = 1:y_new
M(count1,count2) = I(count1.*x_scale,count2.*y_scale);
end
end
figure,imshow(I);
title('Original Image');
M = uint8(M);
figure,imshow(M);
title('Downsample');

GIF images are what are known as indexed images. This means that what you read in with imread are values that are indices to a colour map. Each index generates a unique colour for you, and that's how GIF images are stored. They choose from a predefined set of colours, and each pixel in the GIF image comes from one of the colours in the colour map.
You first need to convert the image into RGB, and you do that with ind2rgb. However, you need to read in the colour map first with the two-output version of imread. You also will want to convert the images to uint8 as good practice with im2uint8:
[X,map] = imread('lena.gif');
I = im2uint8(ind2rgb(X,map));
What you need to do next is what #NKN suggested. You must apply the algorithm to all channels.
As such, simply make an output matrix that has three channels, and apply the algorithm to each plane independently. If I can make a suggestion, when accessing pixels this way after you downsample, make sure you floor or round the image coordinates so you're not inadvertently specifying locations that aren't defined - things like (13.8, 25.5) for example. Image pixel locations are integer, so you need to make sure the coordinates are integer too.
[X,map] = imread('lena.gif');
I = im2uint8(ind2rgb(X,map));
j = size(I,1); %// Change
k = size(I,2);
x_new = j./2;
y_new = k./2;
x_scale = j./x_new;
y_scale = k./y_new;
M = zeros(x_new,y_new,size(I,3)); %// Change
for jj = 1 : size(I,3) %// Change
for count1 = 1:x_new
for count2 = 1:y_new
M(count1,count2,jj) = I(floor(count1.*x_scale),floor(count2.*y_scale),jj); %// Change
end
end
end
figure,imshow(I);
title('Original Image');
M = uint8(M);
figure,imshow(M);
title('Downsample');
To test this, I'm using the mandrill dataset that's part of MATLAB. It is an indexed image with an associated colour map. These are coincidentally stored in X and map respectfully:
load mandrill;
I = im2uint8(ind2rgb(X,map));
Running the modified code, I get these two figures:

When you read the original image it contains 3 layers, R-G-B (as suggested by #rayryeng:
[X,map] = imread('lena.gif');
I = ind2rgb(X,map);
size(I)
ans =
768 1024 3
You should perform the down-sampling process on all the layers:
The code you provided does not down-sample. A simple downsampling example is as follows:
imshow(I(1:2:end,1:2:end,:))

Related

Matlab picture intensity level adjustment

I have a specific question to ask about the intensity adjustment for image processing. I need high constraint value to find small gaps in the image which is shown as a red circle in the image. I used a manual threshold value 0.99 to convert the grayscale image to binary image for other processing methods. However, as the illumination on the surface did not distribute evenly, some parts of the image is lost. I used the adaptive method suggested by Matlab, however, the results is similar to a global threshold graythresh.
I will show my code and result below.
I0 = imread('1_2.jpg');
[R,C,K] = size(I0);
if K==1
I1 = I0;
else
I1 = rgb2gray(I0);
end
%Adjsut image to get a standar binary picture
%Adjust image intensity value
I1 = imadjust(I1,[0.1 0.7],[]);
BW0 = im2bw(I1,0.99);
figure;
BW0 = bwareaopen(BW0,10000);
%Fill non_crack hole error
BW0 = bwareaopen(1-BW0,500);
BW0 = 1-BW0;
imshow(BW0);
After this process, only half of the image will be left. I want a whole image, with locally intensity threshold but show the same feature as the high-level threshold. What can I do?
Thanks
Try adaptthresh:
I0 = imread('1_2.jpg');
[R,C,K] = size(I0);
if K==1
I1 = I0;
else
I1 = rgb2gray(I0);
end
T = adaptthresh(I1, 0.4); %adaptive thresholding
% Convert image to binary image, specifying the threshold value.
BW = imbinarize(I1,T);
% Display the original image with the binary version, side-by-side.
figure
imshowpair(I1, BW, 'montage')

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!

Image Fusion using stationary wavelet transform (SWT) (MATLAB)

I'm trying to fuse two images using SWT. But I'm getting this error :
The level of decomposition 1
and the size of the image (1,5)
are not compatible.
Suggested size: (2,6)
How to change the size of the image to make it compatible for transform?
Code I've used is :
clc
i=1;
fol=1;
n=0;
for fol=1:5
f='folder';
folder = strcat(f, num2str(fol));
cd(folder)
d= numel(D);
i=(n+1);
Fname1 = strcat(int2str(i),'.bmp');
Fname2 = strcat(int2str(i+1),'.bmp');
im1 = imread(Fname1);
im2 = imread(Fname2);
im1=double(im1);
im2=double(im2);
% image decomposition using discrete stationary wavelet transform
[A1L1,H1L1,V1L1,D1L1] = swt2(im1,1,'sym2');
[A2L1,H2L1,V2L1,D2L1] = swt2(im2,1,'sym2');
% fusion start
AfL1 = 0.5*(A1L1+A2L1);
D = (abs(H1L1)-abs(H2L1))>=0;
HfL1 = D.*H1L1 + (~D).*H2L1;
D = (abs(V1L1)-abs(V2L1))>=0;
VfL1 = D.*V1L1 + (~D).*V2L1;
D = (abs(D1L1)-abs(D2L1))>=0;
DfL1 = D.*D1L1 + (~D).*D2L1;
% fused image
imf = iswt2(AfL1,HfL1,VfL1,DfL1,'sym2');
figure;
imshow(imf,[]);
Iname= strcat(int2str(fol),'.bmp');
imwrite(imf,Iname);
end
To address your first problem, that image is really small. I'm assuming that's an image of size 1 x 5. I would suggest changing your image so that it's larger, or perhaps do an imresize on the image. However, as what Ander said in his comment to you... I wouldn't call a 1 x 5 matrix an image.
To address your second problem, once you finally load in an image, the wavelet transform will most likely give you floating point numbers that are beyond the dynamic range of any sensible floating point precision image. As such, it's good that you normalize the image first, then save it to file.
Therefore, do this right before you save the image:
%// ...
%// Your code...
imshow(imf,[]);
%// Normalize the image - Change
imf = (imf - min(imf(:))) / (max(imf(:)) - min(imf(:)));
%// Your code again
%// Now save
Iname= strcat(int2str(fol),'.bmp');
imwrite(imf,Iname);
The above transformation normalizes an image so that the minimum is 0 and the maximum is 1. Once you do that, it should be visualized properly. FWIW, doing imshow(imf,[]); does this normalization for you and displays that result, but it doesn't modify the image.

drawn image, converted back

i want to draw image, do not know how to portray the image output kmeans
my code:
close all; clc; clear;
img = imread('pic7.png');
figure(), imshow(img);
impixelregion;
% nastavenie noveho obrazka
[y x z] = size(img)
for i=1:1:y
for j=1:1:x
imgNew(i, j, :) = 0;
end
end
[X_no_dither, map]= rgb2ind(img,8,'nodither');
figure, imshow(X_no_dither, map);
impixelregion;
m = im2double(X_no_dither)
idx = kmeans(m,4,'emptyaction','singleton');
how i draw image ?
Thanks.
In kmeans, the rows are the things we want to cluster (i.e. pixels by colour), the columns are the variables. Therefore, we cannot just pass in a image straight in, it has to be reshaped first. For example if we look at this MATLAB example., the image is first converted into lab colorspace (and is in lab_he).
First, they take only the a and b elements:
ab = double(lab_he(:,:,2:3));
Then, reshape so that ab is of size n x m where n = total number of pixels and m = 2 - this is because each pixel is being clustered based on both a and b values:
nrows = size(ab,1);
ncols = size(ab,2);
ab = reshape(ab,nrows*ncols,2);
Now, sort those pixels into three colors:
nColors = 3;
% repeat the clustering 3 times to avoid local minima
[cluster_idx cluster_center] = kmeans(ab,nColors,'distance','sqEuclidean', ...
'Replicates',3);
The result then has to be reshape'd back into an image to be displayed:
pixel_labels = reshape(cluster_idx,nrows,ncols);
imshow(pixel_labels,[]), title('image labeled by cluster index');
In your case, as you're using a indexed image, try something like this:
idx = kmeans(m(:),4,'emptyaction','singleton');
idx = reshape(idx,size(m));
imshow(idx, []);
m(:) just arranges the pixels as a single column. kmeans then sorts them into four clusters. Afterwards, we reshape the indexes back using the size of our input image, and then display with imshow as normal.
You should read the linked example closely and make sure you understand what they are doing and why.

How to remove non-barcode region in an image? - MATLAB

After I did a 'imclearborder', there are still a bit of unwanted object around the barcode. How can I remove those objects to isolate the barcode? I have pasted my code for your reference.
rgb = imread('barcode2.jpg');
% Resize Image
rgb = imresize(rgb,0.33);
figure(),imshow(rgb);
% Convert from RGB to Gray
Igray = double(rgb2gray(rgb));
% Calculate the Gradients
[dIx, dIy] = gradient(Igray);
B = abs(dIx) - abs(dIy);
% Low-Pass Filtering
H = fspecial('gaussian', 20, 10);
C = imfilter(B, H);
C = imclearborder(C);
figure(),imagesc(C);colorbar;
Well, i have already explained it in your previous question How to find the location of red region in an image using MATLAB? , but with a opencv code and output images.
Instead of asking for code, try to implement it yourself.
Below is what to do next.
1) convert image 'C' in your code to binary.
2) Apply some erosion to remove small noises.( this time, barcode region also shrinks)
3) Apply dilation to compensate previous erosion.(most of noise will have removed in previous erosion. So they won't come back)
4) Find contours in the image.
5) Find their area. Most probably, contour which has maximum area will be the barcode, because other things like letters, words etc will be small ( you can understand it in the grayscale image you have provided)
6) Select contour with max. area. Draw a bounding rectangle for it.
Its result is already provided in your previous question. It works very nice. Try to implement it yourself with help of MATLAB documentation. Come here only when you get an error which you don't understand.
%%hi, i am ading my code to yours at the end of your code%%%%
clear all;
rgb = imread('barcode.jpeg');
% Resize Image
rgb = imresize(rgb,0.33);
figure(),imshow(rgb);
% Convert from RGB to Gray
Igray = double(rgb2gray(rgb));
Igrayc = Igray;
% Calculate the Gradients
[dIx, dIy] = gradient(Igray);
B = abs(dIx) - abs(dIy);
% Low-Pass Filtering
H = fspecial('gaussian', 10, 5);
C = imfilter(B, H);
C = imclearborder(C);
imshow(Igray,[]);
figure(),imagesc(C);colorbar;
%%%%%%%%%%%%%%%%%%%%%%%%from here my code starts%%%%%%%%%%%%%%%%
bw = im2bw(C);%%%binarising the image
% imshow(bw);
%%%%if there are letters or any other noise is present around the barcode
%%Note: the size of the noise and letters should be smaller than the
%%barcode size
labelImage = bwlabel(bw,8);
len=0;labe=0;
for i=1:max(max(labelImage))
a = find(labelImage==i);
if(len<length(a))
len=length(a);
labe=i;
end
end
imag = zeros(size(l));
imag(find(labelImage==labe))=255;
% imtool(imag);
%%%if Necessary do errossion
% se2 = strel('line',10,0);
% imag= imerode(imag,se2);
% imag= imerode(imag,se2);
[r c]= find(imag==255);
minr = min(r);
maxc = max(c);
minc = min(c);
maxr = max(r);
imag1 = zeros(size(l));
for i=minr:maxr
for j=minc:maxc
imag1(i,j)=255;
end
end
% figure,imtool(imag1);
varit = find(imag1==0);
Igrayc(varit)=0;
%%%%%result image having only barcode
imshow(Igrayc,[]);
%%%%%original image
figure(),imshow(Igray,[]);
Hope it is useful

Resources