How to convert rgb to gray but keep one colour unchanged - matlab

I have an image in which I want to only keep the green part and convert the others to gray scale.

It seems from the colors in your image, that the greens are actually so close to grayscale that you'll be unable to see anything. Either way this is how you do it:
im = imread('houses.jpg');
s= (im(:,:,2)>im(:,:,1))&(im(:,:,2)>im(:,:,3));
dim = double(im);
r = abs(dim(:,:,2)-((dim(:,:,1))+dim(:,:,2)+dim(:,:,3))/3) < 3;
q = s|r;
imgs = rgb2gray(im);
imgs3(:,:,1) = imgs;
imgs3(:,:,2) = imgs;
imgs3(:,:,3) = imgs;
imout = zeros(size(im));
for i=1:size(im,1),
for j=1:size(im,2),
if q(i,j) == 0,
imout(i,j,:) = imgs3(i,j,:);
else,
imout(i,j,:) = im(i,j,:);
end
end
end
imshow(uint8(imout))
imwrite(uint8(imout),'output.jpg');
if you want to see something useful you would probably want to do the following
im = imread('houses.jpg');
s= (im(:,:,2)>im(:,:,1))&(im(:,:,2)>im(:,:,3));
dim = double(im);
r = abs(dim(:,:,2)-((dim(:,:,1))+dim(:,:,2)+dim(:,:,3))/3) < 3;
q = s|r;
imgs = rgb2gray(im);
imgs3(:,:,1) = imgs;
imgs3(:,:,2) = imgs;
imgs3(:,:,3) = imgs;
imout = zeros(size(im));
for i=1:size(im,1),
for j=1:size(im,2),
if q(i,j) == 0,
imout(i,j,:) = imgs3(i,j,:);
else,
imout(i,j,1) = im(i,j,1);
imout(i,j,2) = 255;
imout(i,j,3) = im(i,j,3);
end
end
end
imshow(uint8(imout))
imwrite(uint8(imout),'output.jpg');
which gives this as result:

It should be something like this:
gray_img = rgb2gray(img);
green_mask = img(:,:,2) > img(:,:,1) & img(:,:,2) > img(:,:,3);
gray_img3 = cat(3, gray_img, gray_img, gray_img);
green_mask3 = cat(3, green_mask, green_mask, green_mask);
output_img = gray_img3;
output_img(green_mask3) = img(green_mask3);
I didn't check it, but I'm quite sure it should do the work.
The only thing you might want to modify is the computation of the mask, currently it will include all pixels that are more green than red or blue, but you may want to be more (or less) specific in choosing which pixels to leave unchanged.

I would suggest to use a purely hue=based approach, as you are interested in a specific color.
My approach would be to convert your images to the HSV colorspace and check the Hue channel.
img=imread('houses.jpg');
hsv=rgb2hsv(img);
% find the white areas of the image
gray_part=hsv(:,:,3)>0.7;
% find the green areas of the image that are not white
green_part=hsv(:,:,1)>(30/360) & hsv(:,:,1)<(210/360) & ~gray_part;
% create the output image
outimg=(uint8(double(img).*repmat(green_part,[1 1 3])));
figure;
subplot(121); imshow(img);
subplot(122); imshow(outimg);
This will give you the following image (left: original, right: resulting masked image):
Of course, if you need to get the rest of the image in grayscale you may use the previous results as follows:
pixel(1,1,1)=0;pixel(1,1,2)=255;pixel(1,1,3)=0;
green_img=repmat(pixel,[size(img,1) size(img,2), 1]);
green_part=repmat(green_part,[1 1 3]);
gray_img=rgb2gray(uint8(double(img).*~green_part));
gray_img=double(repmat(gray_img,[1 1 3]));
outimg=uint8(green_part.*green_img + gray_img);
figure; imshow(outimg);
This will display the image shown below:

Related

Gray code pattern looks like binary pattern. Is this correct?

I have this following gray code pattern but it looks like binary pattern to me. Please let me know if this is correct or something has to be changed?
n = ceil(log2(py)); T = length(n) ;
gray_pattrn = zeros(2^n,1) ; gray_pattrn(2) = 1; T = 2;
for k = 2:n
T2 = T+T ;
gray_pattrn(T+1:T2) = T + flipud(gray_pattrn(1:T)) ;
T = T2;
end
mat = transpose(flip(transpose(de2bi(gray_pattrn))));
gray_level = 4;
patternSeq = transpose(repmat(mat(:, gray_level), 1, 1024));
figure, imagesc(patternSeq); colormap gray;
figure, plot(patternSeq(512,:));
And I got the following images.
Despite the name, Gray code is binary and so what you are getting could very well be correct (I haven't actually checked your code). It's called Gray code because it was invented by Frank Gray, not because it outputs grayscale values (it doesn't).

Spheroids detction from Images

I need to find the blobs from the below image.
The major problem is background. background doesn't have uniform intensity. I tried couple of things like thresholding and edge detection in MATLAB but couldn't able to find a better ways to segment out all spheroids. I need to extract the blobs and I need to find the area of each blobs. Does anyone know how to work-around with this kind of background?
Edit (07/02/17):
As suggested by Spektre I tried Following things in MATLAB.
Method 1:
img_original = imread('~/my_image.jpg'); %Read image
img_ch = single(img_original(:,:,2)); %Pick one channel( here its green)
g = fspecial('gaussian',200,100); %Kernel matrix to make the img blurr
con_img = conv2(img_ch,g,'same'); %2D convolution, this wil make the img blurr
sub_img = (con_img - img_ch); %Simple matrix subtraction
sub_img(sub_img <= 10) = 0; %Thresholding
sub_img(sub_img ~= 0) = 1;
fil_sub = imfill(sub_img,'holes'); %Fill the regions
imgfilt = imfilter(fil_sub, ones(3)); %run filter using 3by3 matrx
imgfilt(imgfilt < 8) = 0; %Reduce noisy pixels by thresholding
mfilt_img = (medfilt2(imgfilt)); %reduce unwanted pixels
img = img_ch;
img(mfilt_img ~= 0) = 255;
img2 = img_ch;
img2(img2 < 70) = 0; %Threshold for darker pixels which are left out from above methode.
img(img2 ==0) = 255;
disp_img = img_original(:,:,1);
disp_img(img ==255) = 255;
img_original(:,:,1) = disp_img;
figure, imshow(img_original)
I got the segments but still not good enough I think. This method gave good segments in the high intensity background, Even if I reduce the threshold value segments are not clear in the darker background and brightest pixels in the blobs are excluded.
Method 2:
img_original = imread('~/cancer_cells/Snap-10234.jpg'); %Read image
img_ch = single(img_original(:,:,2)); %Pick one channel( here its green)
clear new_matcel cur_img matcel avg_matrx
s=3; % Set size of the square window
mat_img = img_ch; % Working image channel
% resize the working matrix so that the dimensions matches
resize_img = resizem(mat_img,round(size(mat_img)/s)*s);
% convert matrix into small s x s matrix and save each in cells
window_c = ones(1,size(resize_img,1)/s) * s;
window_r = ones(1,size(resize_img,2)/s) * s;
mat_cel = mat2cell(resize_img,window_c,window_r);
new_matcel = cell(size(mat_cel)); % initialize new variable
% get the average value for each window and replace the actual by avg value
for i = 1:size(mat_cel,1)
for j = 1:size(mat_cel,2)
cur_img = mat_cel{i,j};
avg_value = mean(mean(cur_img));
new_matcel{i,j} = ones(s) * avg_value;
end
end
avg_matrx = cell2mat(new_matcel); % convert cells to matrix
image_sub = (abs(resize_img - avg_matrx)); % take the absolute difference
image_sub(image_sub < 7) = 0; % thresholding
image_sub(image_sub~=0) = 1;
image_sub = bwmorph(image_sub,'bridge');% fill gaps
image_sub = imfill(image_sub,'holes'); % fill the bounded regioons
% image_sub(image_sub == 1) = 255;
image_sub = resizem(image_sub,size(img_ch)); % resize to original size
disp_img = img_original(:,:,1);
disp_img(image_sub == 1) = 255;
img_original(:,:,1) = disp_img;
figure, imshow(img_original)
Much better segmented image:
even brighter pixels are included in the segment. Thanks to Spektre.
Is there a way to improve the above code? or any other idea to get more precise segments?
Thanks.

MATLAB combine two avi. together

I created two avi. file and they have the same length.
I wanted to combine them on a same background and one on top another one on the bottom.
The code I used for one of the animation is below, the other one is similar.
Is there any way I can do that?
load Results.mat;
I = imread('hex08.jpg');
[rows,columns,numberOfColorChannels] = size(I);
if numberOfColorChannels >1
I = I(:,:,2);
end
background = imresize(background, [rows,columns]);
figure(1);
hold on;
for i=1:500
A=angle(i,:);
J = imrotate(I,A,'crop');
mask = J == 0;
mask = bwareafilt(mask,4);
J(mask) = background(mask);
pause(0.01)
imshow(J);
imwrite(J,[num2str(i),'.png']);
end
imageNames = dir(fullfile('*.png'));
imageNames = {imageNames.name}';
outputVideo = VideoWriter(fullfile('hex08.avi'));
outputVideo.FrameRate = 15;
open(outputVideo)
for ii = 1:length(imageNames)
img = imread(fullfile(imageNames{ii}));
writeVideo(outputVideo,img)
end
close(outputVideo)
Here is one way this can be done:
Just like you read the image into img, you can read a second image (from the second video) into img2. Then, you can create a combined image of the two: imgCombined = [img ; img2]; which will contain the first image on top and the second on bottom (This will work if both images are the same width, otherwise you will need to resize/crop). When you write to the video file, use writeVideo(outputVideo,imgCombined).

MATLAB vision.TextInserter does not insert text

I am trying to insert text message into an image. It does not display and I get no error.
close all
clear all
clc
hVideoPlayer = vision.VideoPlayer;
hVideoFileReader = vision.VideoFileReader;
hVideoFileReader.Filename = 'img1.jpg';
frame = step(hVideoFileReader);
hcsc = vision.ColorSpaceConverter;
hcsc.Conversion = 'RGB to intensity';
frame = step(hcsc, frame);
at = vision.Autothresholder;
frame = step(at, frame);
ccl = vision.ConnectedComponentLabeler;
[L NUM] = step(ccl, frame);
holeObjCount = 0;
for i=1:NUM
framei = changem(L==i, 1, i);
framei = imcomplement(framei);
[Li NUMi] = step(ccl, framei);
if NUMi > 1
holeObjCount = holeObjCount + 1;
end
end
message = sprintf('%d of %d objects have holes.', holeObjCount, NUM);
disp(message);
osdMsg = vision.TextInserter('%d of %d objects have holes.',...
'Color', uint8([255, 255, 255]), ...
'Location', [10 10],...
'FontSize', 22);
%The problem is here
frame = step(osdMsg, frame, int32([holeObjCount NUM]));
step(hVideoPlayer, frame);
release(hVideoFileReader);
release(hVideoPlayer);
The problem is because of color space of the image. I have attempted to display a RGB colored text on a B/W image which can not show natutally.
After removing color attribute, I could see the text
osdMsg = vision.TextInserter('%d of %d objects have holes.',...
'Location', [10 10],...
'FontSize', 22);
The problem is now, the text inserted is black and cannot be read clearly.
The problem is that after thresholding frame is a logical array. To make the text show up use im2uint8 to convert it to uint8.
A few other pointers: since you are working with a single image rather than with a video you can use imread instead of vision.VideoFileReader to read it in. You can also use imshow instead of vision.VideoPlayer for the same reason. Also, if you have MATLAB version R2013a or later, you can use the insertText function instead of vision.TextInserter.

Matlab: Check all images in a directory for grayscale?

I want to check all jpg-images in the current directory if they are grayscale or contain coloured pixels... I tried:
figdirectory = pwd;
fullpath = sprintf('%s/*.jpg', figdirectory);
d = dir(fullpath);
% Loop
pages = [];
for i = 1:length(d)
f = d(i).name;
fname_input = sprintf('%s/%s', figdirectory, f);
A = imread(fname_input);
B = rgb2gray(A);
if(A-B == 0)
hascolor = 0;
else
hascolor = 1;
end
pages = [pages; hascolor];
end
but this gives me an error about the matrix dimensions of A and B. Why has A a third dimension?
Thanks!
To do that:
0) Assuming your input is purely an 'image' and not a 'volume'.
1) [r c d] = size(im);
2) if d is larger than 1, then it is a colored image
3) other wise, it has to be a gray-scale image.
EDITS:
You can add one more condition to solidly distinguish grey scale img from color ones. Assuming ur color imgs are of 3 channels,
if d is equal to 3 then check if all 3 channels are equal
im(:,:,1)==im(:,:,2) && im(:,:,1)==im(:,:,3)
Then you have an grayscale image otherwise color img
Here is one simple solution based on IMFINFO:
%# some test images shipped with the Image Processing Toolbox
fNames = {
'circles.png' %# binary
'shadow.tif' %# indexed color
'coins.png' %# gray
'peppers.png' %# RGB
};
isGrayscale = false(size(fNames));
for i=1:numel(fNames)
imgInfo = imfinfo(fNames{i});
if strcmp(imgInfo.ColorType,'truecolor')
isGrayscale(i) = false;
elseif strcmp(imgInfo.ColorType,'grayscale')
isGrayscale(i) = true;
elseif strcmp(imgInfo.ColorType,'indexed')
%# indexed images colormap (the three channels should be all same)
isGrayscale(i) = all(all( diff(imgInfo.Colormap,[],2)==0 ,2),1);
end
end
The first part in your case can be:
dirName = 'C:\path\to\myimages';
files = dir( fullfile(dirName,'*.jpg') );
fNames = {files.name}';
EDIT:
#Adrian: With regards to the image you posed, as far as the image format saved, it IS a color image. Now the fact that all R/G/B channels are all the same is simply a special case...
Anyway if you want to be able to detect such cases, change the 'truecolor' part of the above code to:
#% ...
if strcmp(imgInfo.ColorType,'truecolor')
img = imread(fNames{i});
isGrayscale(i) = isequal(img(:,:,1),img(:,:,2),img(:,:,3));
elseif strcmp(imgInfo.ColorType,'grayscale')
#% ...
You can use IMFINFO for this task, so that you won't have to load the image into memory.
figdirectory = pwd;
fullpath = sprintf('%s/*.jpg', figdirectory);
d = dir(fullpath);
nImages = length(d);
%# imageType is a cell array with either 'grayscale', 'truecolor', or 'indexed',
%# depending on the kind of image you have.
imageType = cell(nImages,1);
for iImg = 1:nImages
info = imfinfo(d(iImg).name);
imageType{iImg} = info.ColorType;
end
%# isGrayscale is true for grayscale images, false otherwise
%# (though note that there might be mapped images that map to a grayscale colormap).
isGrayscale = cellfun(#(x)strcmp(x,'grayscale'),imageType);
EDIT
%# the indexed images have to be loaded in order for you to check
%# for grayscale maps
indexedIdx = find(cellfun(#(x)strcmp(x,'indexed'),imageType));
for iImg = indexedIdx(:)'
[~,map] = imread(fullfile(figDirectory,d(iImg).name));
%# It's a grayscale image if rgb map values are all equal
isGrayscale(iImg) = all(all(bsxfun(#eq,map,map(:,1)),2),1);
end
%# finally, it is possible that the images are *stored* as truecolor
%# but containing, in fact, a grayscale image
truecolorIdx = find(cellfun(#(x)strcmp(x,'truecolor'),imageType));
for iImg = truecolorIdx(:)'
img = imread(fullfile(figDirectory,d(iImg).name));
%# It's a grayscale image if rgb map values are all equal
isGrayscale(iImg) = all(all(all(bsxfun(#eq,img(:,:,1),img),1),2),3);
end
From the manual for imread http://www.mathworks.co.uk/help/techdoc/ref/imread.html
If the file contains a grayscale image, A is an M-by-N array. If the
file contains a truecolor image, A is an M-by-N-by-3 array.
So A will have a third dimension for the coloured images.
If you want to test for greyscale then you could convert the image to hsv.
B = rgb2hsv(A)
from the manual, http://www.mathworks.co.uk/help/techdoc/ref/hsv2rgb.html
When B(:,2) is 0, the colors are unsaturated (i.e., shades of gray).
In the case of a true colour image like the one posted it will be if unique(B(:,:,2)) is zero, hence
A = imread(fname_input);
B = rgb2hsv(A);
%# if saturation levels are zero then it's a greyscale image
if(unique(B(:,:,2)) == 0)
hascolor = 0;
else
hascolor = 1;
end