Converting a grayscale image to black and white - image

I have a grayscale image that only has the values 60 and 117. How can I convert the image to only black and white without graylevels?
I tried the matlab function gray2ind, but didn't get the expected output.
Thanks.

Try im2bw(img, level) with level = 0.5.
This is a matlab function that takes a grayscale image img, applies a threshold of level (a value between [0,1]) and returns a black and white image.
This function is part of the Image Processing Toolbox. Your case is simple enough that you could also try something like:
bwImg = false(size(img));
bwImg(img == 117) = true;
I edited the above to set values equal to false/true to more closely mimic Matlab's im2bw() which returns a matrix of logical values rather than ints.
2nd Edit: Modified the code block to reflect improvements suggested by #Amro

Related

imshow command does not show the same binary image with original

I read the image with:
W=double(imread('rose32.bmp'));
Then:
imshow(W,[]);
or
imshow(W);
But the shown image seems to be inverted with respect to the original image. How can I solve this problem ? Is it a MATLAB problem?
The problem is probably caused by the formatting the the imagefile!
When you use imread what it returns depends of the formatting of the image in the image file. imread returns tree values [A,map,transparency] = imread(___), where A might be hxw-matrix or a hxwx3-matrix (h and w are short for height and width) of several different possible classes (eg. double or uint8).
In the case of the hxwx3-matrix the output-variable map will be empty, and you can show the image directly using imshow(A). This is called an RGB-image.
The other possibility (called an indexed image) is the hxw-matrix. In this case map is a colormap, and you can show the image by imshow(A,map).
You can easily convert between these two types of images by ind2rgb(A,map) and rgb2ind(A).
The other thing you need to be careful with is the class of the image.
If you have an rgb-image of class uint8, then the values of image will be integers between 0 and 255, whereas rgb-images of type double have values between 0 and 1. You should never convert an image to double-class by the double-function like you do; in stead use im2double.
So to solve your problem try the following code:
[img,map] = imread('rose32.bmp');
if ~isempty(map)
img = ind2rgb(img,map);
end
img = im2double(img);
Now imshow(img) should show the image correctly. Or you can simply use the following code:
[W,map] = imread('rose32.bmp');
imshow(W,map);

Image blending with mask

I'm trying to combine the two images based on the information from the mask. I'm using the color information from the background image if the mask is 0 and color information from foreground image if the mask is 1. Because the mask and both
Images are of the same size, I would like to use logical indexing of matrices to achieve this.
My attempt:
mask = imread('mask.png');
foreground = imread('fg.jpg');
background = imread('bg.jpg');
[r,c,~]=size(mask);
A = zeros(size(mask));
for i=1:r
for j=1:c
if mask(i,j) == 0
A(i,j,:) = background(i,j,:);
end
if mask(i,j) > 0
A(i,j,:) = foreground(i,j,:);
end
end
end
imshow(A);
The result looks like a flickering blue image, but I don't want that. Please help.
You can do this a bit more concisely:
f = double(foreground).*double(mask);
b = double(background).*double(~mask);
blend = f+b;
imshow(blend, []);
Using logical indexing you could also do
foreground(logical(mask)) = 0;
background(logical(~mask)) = 0;
blend = foreground+background;
The ISNOT operator '~' inverts your matrix in the second line, so you cut out the area you would like for background.
NOTE: This works for black and white (one channel). For coloured images see rayryeng's solution.
There are two problems with your code. The first problem is that you are trying to assign colour pixels to the output image A, yet this image is only two-dimensional. You want an image with three channels, not two. In addition, the output image type you are specifying is wrong. By default, the output image A is of type double, yet you are copying values into it that aren't double... most likely unsigned 8-bit integer.
As such, cast the image to the same type as the input images. Assuming both input images are the same type, initialize your A so that:
A = zeros(size(foreground), class(foreground));
This correctly makes a colour image with the same type as any of the inputs, assuming that they're both the same type.
Now, your for loop is fine, but it's better if you do this in one shot with logical indexing. If you want to use logical indexing, create a new image that's initially blank like what you've done, but then make sure your mask has three channels to match the number of channels the other images have. After, you simply need to index into each image and set the right locations accordingly:
mask = imread('mask.png');
foreground = imread('fg.jpg');
background = imread('bg.jpg');
[r,c,d]=size(mask); %// Change
%// If your mask isn't three channels, make it so
%// Change
if d ~= 3
mask = cat(3, mask, mask, mask);
end
A = zeros(size(foreground), class(foreground)); %// Change
A(mask) = foreground(mask); %// Assign pixels to foreground
A(~mask) = background(~mask); %// Assign pixels to background
imshow(A);

how to denormalize the image in matlab

I am working on a project where i have to first normalize the image i.e convert the pixel range of my image from 16-235 (as it is only luminance component of the image , pixel values are always defined in the range 16-235) to 0 - 1 then i perform dwt and idwt on the image after the processing i want to again maps these pixels values from 0 - 1 to 16 - 235. ie if the pixel value is 1 value then it should be stored in the image matrix as 235.
for which i tried the following matlab code ,this code works perfectly fine when i denormalize the image immediately after normalization , but output becomes complete white if i use this code after performing dwt and idwt.
for j = 1:1:361
for k=1:1:361 %dimensions of my matrix
if(distorted1(j,k)~=0)
temp=distorted1(j,k);
temp1=temp/0.0045;
distorted1(j,k)=int8(temp1)+1;
end
end
end
imshow(distorted1);
it seems like the result of your idwt is of type double ( or single ) and not int anymore. convert to uint8 and then imshow it.
Trying to imshow an image of type double/single will saturate all pixels with values larger than 1.0 (rather than 255 for images of type int).

Writing a greyscale video using Videowriter/avifile

I am writing a function that generates a movie mimicking a particle in a fluid. The movie is coloured and I would like to generate a grayscaled movie for the start. Right now I am using avifile instead of videowriter. Any help on changing this code to get grayscale movie? Thanks in advance.
close all;
clear variables;
colormap('gray');
vidObj=avifile('movie.avi');
for i=1:N
[nx,ny]=coordinates(Lx,Ly,Nx,Ny,[x(i),-y(i)]);
[xf,yf]=ndgrid(nx,ny);
zf=zeros(size(xf))+z(i);
% generate a frame here
[E,H]=nfmie(an,bn,xf,yf,zf,rad,ns,nm,lambda,tf_flag,cc_flag);
Ecc=sqrt(real(E(:,:,1)).^2+real(E(:,:,2)).^2+real(E(:,:,3)).^2+imag(E(:,:,1)).^2+imag(E(:,:,2)).^2+imag(E(:,:,3)).^2);
clf
imagesc(nx/rad,ny/rad,Ecc);
writetif(Ecc,i);
if i==1
cl=caxis;
else
caxis(cl)
end
axis image;
axis off;
frame=getframe(gca);
cdata_size = size(frame.cdata);
data = uint8(zeros(ceil(cdata_size(1)/4)*4,ceil(cdata_size(2)/4)*4,3));
data(1:cdata_size(1),1:cdata_size(2),1:cdata_size(3)) = [frame.cdata];
frame.cdata = data;
vidObj = addframe(vidObj,frame);
end
vidObj = close(vidObj);
For your frame data, use rgb2gray to convert a colour frame into its grayscale counterpart. As such, change this line:
data(1:cdata_size(1),1:cdata_size(2),1:cdata_size(3)) = [frame.cdata];
To these two lines:
frameGray = rgb2gray(frame.cdata);
data(1:cdata_size(1),1:cdata_size(2),1:cdata_size(3)) = ...
cat(3,frameGray,frameGray,frameGray);
The first line of the new code will convert your colour frame into a single channel grayscale image. In colour, grayscale images have all of the same values for all of the channels, which is why for the second line, cat(3,frameGray,frameGray,frameGray); is being called. This stacks three copies of the grayscale image on top of each other as a 3D matrix and you can then write this frame to your file.
You need to do this stacking because when writing a frame to file using VideoWriter, the frame must be colour (a.k.a. a 3D matrix). As such, the only workaround you have if you want to write a grayscale frame to the file is to replicate the grayscale image into each of the red, green and blue channels to create its colour equivalent.
BTW, cdata_size(3) will always be 3, as getframe's cdata structure always returns a 3D matrix.
Good luck!

segment object(leaf) which is on the white paper using image processing

I want to get only leaf from an image.
The background is a normal white paper(A4) and there is some shadow.
I apply some method (structure element,edge detection using filter) but I cannot find the general way which can apply all the image.
these are examples.
Are there better methods for this problem??
thank you
another example.
and the result I got is
By using
hsv_I = rgb2hsv(I);
Is = hsv_I(:,:,2);
Is_d = imdilate(Is,strel('diamond',4));
Is_e = imerode(Is,strel('diamond',2));
Is_de = imerode(Is_d,strel('disk',2));
Is_def = imfill(Is_de,'holes');
Is_defe = imerode(Is_def,strel('disk',5));
Then Is_defe is a mask to segment
But the method that i did is very specific. I cannot use this in general.
If you have the Image Processing Toolbox, you could do as follows:
The code below first estimates the threshold with the function graythresh, thresholds the image and fills holes with the imfill function. Suppose I is a cell containing your RGB images:
for k=1:length(I)
t=graythresh(rgb2gray(I{k}));
BW{k}=imfill(~im2bw(I{k}, t), 'holes');
subplot(length(I),1,k), imshow(BW{k});
end

Resources