Spheroids detction from Images - matlab

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.

Related

Background subtraction And foreground detection using Kalman Filter

I need to separate the background from the foreground in a video using Kalman filter. Can somebody give me some resources or code examples to follow.
Update: i've found a good example here Traffic detection.It worked excellent for Traffic detection but i want to re-adapt it for people extraction. I've found some variables that's need to be adapted for example:
1. alpha = learning constant
2. K= #of guassians in the mixture
3. T = min. portion of background
4. initVariance = initial variance
5. pixelThresh = threshold condition for computing adaptive process on pixel
Here is an overview of the main file (In case just you want an overview)
function foregroundEstimation(movie)
%Load video into memory and prepare output video for writing
v = VideoReader(movie);
numFrames = 150;
foregroundVideo = VideoWriter('foreground.avi');
open(foregroundVideo);
%video constants
initFrame = read(v,1);
global height;
global width;
height = size(initFrame,1);
width = size(initFrame,2);
%initialize GMM parameters: (based upon Stauffer notation)
%http://www.ai.mit.edu/projects/vsam/Publications/stauffer_cvpr98_track.pdf
% alpha = learning constant
% K= #of guassians in the mixture
% T = min. portion of background
% initVariance = initial variance
% pixelThresh = threshold condition for computing adaptive process on pixel
alpha=0.05; % 0.05
K=5; % 5
global T; % T = 0.8
T=0.8;
global initVariance;
initVariance=75; % 75
pixelThresh=45; % 45
referenceDistance = 40; % 40 %shortcut to speed up processing time. Compare current pixel to pixel referenceDistance frames back and skip adaptive process if similar. Downside is doesn't collect background evidence as well.
sideWeight = (K-1)/(1-T);
global matchThres;
matchThres = sqrt(3);
global ccThreshold;
ccThreshold = 9000; % 5000
global deltaT;
deltaT = 1;
global numParticles;
numParticles = 100;
trackingOn = 0; % will superimpose tracking color marker on detected vehicles in output video. tackingOn should equal 1 or 0
prevCentSize = 0;
%structures to pass information between frames for detection purposes.
field = 'f';
filterValue = {[];[];};
prevFilter = struct(field,filterValue);
modelValue = {[];prevFilter};
prevModel = struct(field,modelValue);
%initiailze video process components
initColorBoxes();
foreFrame = zeros(height,width,3);
backFrame = zeros(height,width,3);
%map represents pixels at a given frame to perform adaptive process
pixThreshMap = ones(height,width);
%individual pixel process components
pixel = zeros(3,1);
pixMean = zeros(3,1,K);
pixVar = ones(1,K);
pixWeight = zeros(1,K);
%global pixel process components
globalWeight = (ones(height,width,K)/sideWeight);
globalWeight(:,:,1) = T;
%globalWeight = (ones(height,width,K)/K);
globalMean = zeros(height,width,3,K);
globalVar = ones(height,width,K);
%=====================================================
%Extract Foreground and Background by K-mixture model
%=====================================================
%initialize g-mixture model
globalVar = globalVar*initVariance;
for k=1:K
globalMean(:,:,1,k)=initFrame(:,:,1);
globalMean(:,:,2,k)=initFrame(:,:,2);
globalMean(:,:,3,k)=initFrame(:,:,3);
end;
distVec = zeros(numFrames,1);
%adaptive g-mixture background segmentation
for frameIndex=2:numFrames
%get current frame and the refernece frame
%tic;
frameIndex
currentFrame = double(read(v,frameIndex));
if (frameIndex<=referenceDistance)
referenceFrame= double(read(v,1));
else
referenceFrame= double(read(v,frameIndex-referenceDistance));
end;
frameDifference = abs(currentFrame - referenceFrame);
%creates map of pixel locations where we will perform adaptive process. Based
%upon threshold that detects low change regions based on previous frame in
%order to save computation.
pixThreshMap = min(sum(+(frameDifference(:,:,:)>pixelThresh),3),1);
for index=1:3
backFrame(:,:,index)=(+(pixThreshMap(:,:)==0)).*currentFrame(:,:,index);
end;
%extract the parts considered "stable background" from current frame
%reset foreground frame
foreFrame = ones(height,width,3)*255;
%gaussian mixture matching & model updating
[i,j]=find(pixThreshMap(:,:)==1);
%loop through every pixel location where adaptive process should be performed
for k = 1:size(i,1)
pixel = reshape(currentFrame(i(k),j(k),:),3,1);
pixMean = reshape(globalMean(i(k),j(k),:,:),3,1,K);
pixVar = reshape(globalVar(i(k),j(k),:,:),1,K);
pixWeight=reshape(globalWeight(i(k),j(k),:),1,K);
%update gaussian mixture according to new pix value
match=matchingCriterion(pixMean,pixVar,pixel);
matchWeight = 0;
if(match>0)
%match found so update weights/normalize
pixWeight = (1-alpha)*pixWeight;
pixWeight(match)= pixWeight(match) + alpha;
pixWeight = pixWeight/sum(pixWeight);
matchWeight = pixWeight(1,match);
%NOTE ALPHA SHOULD BE REPACED WITH SOME KIND OF RHO EVENTUALLY
%WHERE RHO IS PRODUCT OF ALPHA AND CONDITIONAL PROBABILITY MEASURE
%update variance
pixVar(:,match) = (1-alpha)*pixVar(:,match) + ...
alpha*(pixel - pixMean(:,:,match))'*(pixel-pixMean(:,:,match));
%update mean
pixMean(:,:,match) = (1-alpha)*pixMean(:,:,match) + alpha*pixel;
else
%no match currently found.
%replace one with lowest sigma value
rankVector = pixWeight./sqrt(pixVar(1,:));
[mini minIndex] = min(rankVector);
pixMean(:,:,minIndex) = pixel;
pixVar(:,minIndex) = initVariance;
end
%rerank all pixel components
rankCriterionVector = pixWeight./sqrt(pixVar(1,1,:));
[rankSort rankIndex] = sort(rankCriterionVector);
pixMean = pixMean(rankIndex);
pixVar = pixVar(rankIndex);
pixWeight = pixWeight(rankIndex);
%repopulate global structures with updated values
globalWeight(i(k),j(k),:) = pixWeight(:,1);
globalMean(i(k),j(k),:,:) = pixMean(:,1,:);
globalVar(i(k),j(k),:,:) = pixVar(:,:,:);
%now need to perform the background segmentation based upon weight
%threshold
bgIndex = segmentBackground(pixWeight);
if(ismember(matchWeight, pixWeight))
matchIndex = find(pixWeight == matchWeight,1);
else
matchIndex = 0;
end
if((matchIndex>=bgIndex) || (matchIndex == 0))
%also check against initFrame for match
%NOTE CHANGE
if(initMatch(initFrame(i(k),j(k),:),pixel) == 0)
foreFrame(i(k),j(k),:) = pixel;
end
end
end
%Now write foreground frame to foreground estimation video
contrastFrame = foreFrame/max(abs(foreFrame(:)));
%remove all connected components associated with foreground objects that are smaller than what we expect a vehicle should be.
[cleanFrame centroids]= connectedComponentCleanup(contrastFrame);
if(trackingOn == 1)
if(size(centroids,1) > prevCentSize)
prevModel = addModel(prevModel, centroids, height, width);
elseif (size(centroids,1) < prevCentSize)
prevModel = removeModel(prevModel, centroids, height, width);
end
if(size(centroids,1) > 0)
%implies there is a car in frame for tracking
[curModel orderedCentroids] = vehicleTracking(centroids, prevModel);
prevModel = curModel;
trackFrame = colorBox(cleanFrame, curModel,orderedCentroids, height, width);
else
trackFrame = cleanFrame;
end
else
trackFrame = cleanFrame;
end
writeVideo(foregroundVideo,trackFrame);
prevCentSize = size(centroids,1);
end
Thanks.
Basically this is not task for kalman filter, look at background subtraction in opencv.
Kalman filter could be used after that to track objects between frames, you could look for example here
http://studentdavestutorials.weebly.com/kalman-filter-with-matlab-code.html

Take a text line in an image file to create a new image file MATLAB

I need to take each line of text from an image file and create a new separate image for each of the lines. i already have a way to count how many lines are in the image file.
if anybody has any suggestions it would be a huge help because i'm not too good with images. im not allowed to use the image processing toolbox.
This is the code:
function out = countLines( imgFile )
% count the number of lines in the image file
im = imread(imgFile);
im = 255 - im;
imbw = uint8(0.33*im(:,:,1) + 0.34*im(:,:,2) + 0.33*im(:,:,3)) > 127;
imwrite(imbw, 'temp.jpg');
rvec = sum(imbw');
rvec1 = [0 rvec 0];
svec = [rvec 0 0];
out = sum(rvec1 == 0 & svec ~= 0);
I tried this method on a test image I found on the internet and it seemed to work alright provided the text is straight. Basically you look for entries in your rvec vector whose neighbouring entries are both smaller than them. That is to say you look for the local maximum entries (first image). After that you group the clusters of lines together to decide where to split the image (second image).
clear; clc;
im = imread('text.png'); % load the image
[Nrows,Ncols,~] = size(im); % get the size
imgray = rgb2gray(im); % convert to grayscale
vec = mean(imgray,2); % average intensities of each row
localMax=[]; % list of local maximum entries
for i = 2:Nrows-1 % accept local max rows that do not have text
hasText = sum( imgray(i,:)<100 )>0;
if vec(i)>vec(i-1) && vec(i)>vec(i+1) && ~hasText
localMax = [localMax;i];
end
end
numMax = length(localMax);
% get distances between local max rows
distances = localMax(2:end) - localMax(1:end-1);
thresh = mean(distances); % the average distance will be our threshold
splitRows = []; % rows where we will split the image
cluster = localMax(1); % start a cluster with the first local max row
for i = 1:numMax-1;
if distances(i) < thresh % if rows are close together, keep them in a cluster
cluster = [cluster;localMax(i+1)];
else % average the cluster to get the row where we split the image
newSplit = round(mean(cluster));
splitRows = [ splitRows ; newSplit ];
cluster = localMax(i+1);
end
end
newSplit = round(mean(cluster)); % add the last cluster as well
splitRows = [ splitRows ; newSplit ];

Image template matching using correlation

I am developing a template matching program in MATLAB. The code runs well, and finds the closest result. My first question, in this code, I am using the function corr2(). I would like to try a version using the formula (I tried to upload a picture of but I need 10 reputations).
I understand the formula itself, but I am not sure what variables should I use to use it. For example, what is exactly the m and n mean in my images where can I get them? In another words, what does the formula take as inputs?
Second question is, when I run the code I have now, it takes long, is there any thing I can change to speed it up?
Original = imread('Red.jpg'); % Read original image
Template = imread('temp.png'); % Read template image
OriDu = im2double(Original); % convert original image
TempDu = im2double(Template); % convert template
OriH = size(Original, 1); %height of the Original image
OriW = size(Original, 2); %width of the Original image
OriD = size(Original, 3); %colour depth
TempH = size(Template, 1); %height of the Template image
TempW = size(Template, 2); %width of the Template image
TempD = size(Template, 3); %colour depth
TempDu = reshape(TempDu, TempH*TempW, 3);
corr = 0; % to check the best correlation found
%% two for loops to go through the original image.
for i = 1:OriH-TempH
for j = 1:OriW-TempW
% take a segment of the original image( same size as the template size)
segment = OriDu(i: (i - 1) + TempH, j: (j - 1) + TempW, :);
segment = reshape(segment, TempH*TempW, 3);
output = corr2(TempDu, segment);
if output > corr
corr = output;
x = i;
y = j;
end
end
end
figure;
subplot(1,2,1), imshow(Template), title('Template');
subplot(1,2,2), imshow(OriDu(x:x+TempH, y:y+TempW, :)),title('Segment of the similar part');

How to convert rgb to gray but keep one colour unchanged

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:

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