how to separate the white regions bounded by black in a binary image - matlab

I am working with lung cancer detection in MATLAB. I want to segment the binary image of lung CT scan to fetch the region of interest.
In the picture you can see a white region inside the black region.The black objects signifies the lung and the white region inside black object signifies cancer effected portion of lung. I want to obtain the white region from the image. I want to get the output as only that white region in black background nothing else. How can I achieve this?

How about something like this:
% Read in image and convert to BW
BW = im2bw(imread('http://i.stack.imgur.com/pxpOz.jpg'));
% Invert so that the lung appears white white
BW = ~BW;
% Create a structuring element. Tune the '2' depending on the size of the gap
se = strel('disk',2);
% Perform mophological closing
closeBW = imclose(BW,se);
% Fill the holes
lungBW = imfill(closeBW,'holes');
% subtract the lung image from the closed image
cancerBW = (lungBW - closeBW);
% Display the results
figure; imshow(cancerBW);
Click here for the output

You have not given code, so I am also answering without code.
You could
use morpholocical closing operation to get rid of the open channel which connects the white region to the surrounding
Then look for white holes in each black region (e.g. by doing a blob analysis /threshold operation only on the (masked) region which is black)
Alternatively, you could
look for convexity defects of contours such as described here (This is a python version, but similar functions should be around in matlab)

Related

Region of interest extraction in MATLAB

I am writing a MATLAB code to implement a specific filter on a selected (from auto ROI) grayscale region of a forearm image which consists of veins. I also uploaded the forearm of a subject (after foreground has extracted).
Basically, I have NIR camera images of the forearm of different subjects with different orientations. I wrote the code that has extracted the foreground grayscale image of the arm, that gave me the white background with the forearm. I used Sobel edge to find edges. I also found the nonzero indices using the find function. I got the row and col indices. I need an idea on how to extract image inside (almost 10 pixels) of the edges detected on both sides of the forearm (black and white edged image-also uploaded).
Sobel-edge:
Foreground image:
ROI image that I need to extract:
clear all
close all
clc
image= rgb2gray(imread('Subj1.jpg'));
image1=~im2bw(image,0.1);
image1=im2uint8(image1);
foreground=imadd(image1,image);
imshow(foreground);
edgesmooth=medfilt2(foreground);
sobeledge= edge(edgesmooth,'sobel');
sobeledge=im2uint8(sobeledge);
figure
imshow(sobeledge);
[col,row]=find(sobeledge~=0);
Starting from the mask image that you make here:
image1=~im2bw(image,0.1);
but inverted, such that the mask is zero for the background and non-zero for the foreground:
image1 = im2bw(image,0.1);
you can use imdilate to expand it by a fixed distance:
se = strel('disk',20); % This will extend by 20/2=10 pixels
image2 = imdilate(image1,se);
image2 will be like image1, but expanded by 10 pixels in all directions.
imerode does the opposite, it shrinks regions.

How to create an inverse gray scale?

I have an image with dark blue spots on a black background. I want to convert this to inverse gray scale. By inverse, I mean, I want the black ground to be white.
When I convert it to gray scale, it makes everything look black and it makes it very hard to differentiate.
Is there a way to do an inverse gray scale where the black background takes the lighter shades?
Or, another preferable option is to represent the blue as white and the black as black.
I am using img = rgb2gray(img); in MATLAB for now.
From mathworks site:
IM2 = imcomplement(IM)
Is there a way to do an inverse gray scale where the black
background takes the lighter shades?
Based on your image description I created an image sample.png:
img1 = imread('sample.png'); % Read rgb image from graphics file.
imshow(img1); % Display image.
Then, I used the imcomplement function to obtain the complement of the original image (as suggested in this answer).
img2 = imcomplement(img1); % Complement image.
imshow(img2); % Display image.
This is the result:
Or, another preferable option is to represent the blue as white and
the black as black.
In this case, the simplest option is to work with the blue channel. Now, depending on your needs, there are two approaches you can use:
Approach 1: Convert the blue channel to a binary image (B&W)
This comment suggests using the logical operation img(:,:,3) > 0, which will return a binary array of the blue channel, where every non-zero valued pixel will be mapped to 1 (white), and the rest of pixels will have a value of 0 (black).
While this approach is simple and valid, binary images have the big disadvantage of loosing intensity information. This can alter the perceptual properties of your image. Have a look at the code:
img3 = img1(:, :, 3) > 0; % Convert blue channel to binary image.
imshow(img3); % Display image.
This is the result:
Notice that the round shaped spots in the original image have become octagon shaped in the binary image, due to the loss of intensity information.
Approach 2: Convert the blue channel to grayscale image
A better approach is to use a grayscale image, because the intensity information is preserved.
The imshow function offers the imshow(I,[low high]) overload, which adjusts the color axis scaling of the grayscale image through the DisplayRange parameter.
One very cool feature of this overload, is that we can let imshow do the work for us.
From the documentation:
If you specify an empty matrix ([]), imshow uses [min(I(:)) max(I(:))]. In other words, use the minimum value in I as black, and the maximum value as white.
Have a look at the code:
img4 = img1(:, :, 3); % Extract blue channel.
imshow(img4, []); % Display image.
This is the result:
Notice that the round shape of the spots is preserved exactly as in the original image.

Removing specific colored edge section of an image using MATLAB

How can I remove the purple colored section from the edge of the image but not from inside of the image using MATLAB. Please suggest me a general code which can be applied future for any kind of this type image.
Main Image
In case you don't get which section is to be removed I marked the section with red color
So, this is what I came with. I hope the code is self explanatory.
There are 2 values you need to play with. One of them is the number in imdilate. That one will define "how big the boundary is". Of course that depends on you.
The other one is the value for HSV color segmentation. In HSV, H is color, and purple is around 250-335 range. The problem is that blue is very similar to purple, and the limit between purple and blue is very ambiguous. I used 250 as lower limit in my code, but you may wan to modify that.
If you have any question please ask.
% The image is indexed image. Else convert.
[img,c]=imread('https://i.imgur.com/dxkJSi0.png');
% Get part with color
bwimg=img~=0;
% get only the biggest part
lblimg=bwlabel(bwimg,4);
stat = regionprops(lblimg,'Centroid','Area','PixelIdxList');
[maxValue,index] = max([stat.Area]);
todelete=1:size(stat,1);
todelete(index)=[];
for ii=todelete
bwimg(stat(ii).PixelIdxList)=0;
end
%update image with without "noise"
img(~bwimg)=0;
% get the contour of the image (thanks #rayryeng)
er = imerode(bwimg, strel('square', 3));
out = imsubtract(bwimg, er);
% we will increase the boundary so we pick a larger region
% Here you need your input. it depedns how much you dilate the image, the
% part of the of the image that will be considered boudnary will increase.
boundary=imdilate(out,strel('square', 10));
% now lets see withc colors are purple. For that we get HSV space. Shades
% of purple are aruond 265~335 H
hsvc=rgb2hsv(c);
purple=find(hsvc(:,1)>250/360&hsvc(:,1)<335/360);
% Get purple in the whole image
purpleimg=zeros(size(img));
for ii=1:size(purple)
purpleimg(img==purple(ii))=purple(ii);
end
% get locations of purple in the boudnary
purpbound=purpleimg.*boundary~=0;
% delete them from the original image
imgNOpurple=img;
imgNOpurple(purpbound)=0;
% plot results
figure(1)
subplot(221)
imshow(purpleimg,c)
title('purple in the image')
subplot(222)
imshow(purpleimg.*boundary,c);
title('purple boundary')
subplot(223)
imshow(img,c)
title('original image')
subplot(224)
imshow(imgNOpurple,c);
title('Image without purple boundary')

MATLAB Image Processing - Find Edge and Area of Image

As a preface: this is my first question - I've tried my best to make it as clear as possible, but I apologise if it doesn't meet the required standards.
As part of a summer project, I am taking time-lapse images of an internal melt figure growing inside a crystal of ice. For each of these images I would like to measure the perimeter of, and area enclosed by the figure formed. Linked below is an example of one of my images:
The method that I'm trying to use is the following:
Load image, crop, and convert to grayscale
Process to reduce noise
Find edge/perimeter
Attempt to join edges
Fill perimeter with white
Measure Area and Perimeter using regionprops
This is the code that I am using:
clear; close all;
% load image and convert to grayscale
tyrgb = imread('TyndallTest.jpg');
ty = rgb2gray(tyrgb);
figure; imshow(ty)
% apply a weiner filter to remove noise.
% N is a measure of the window size for detecting coherent features
N=20;
tywf = wiener2(ty,[N,N]);
tywf = tywf(N:end-N,N:end-N);
% rescale the image adaptively to enhance contrast without enhancing noise
tywfb = adapthisteq(tywf);
% apply a canny edge detection
tyedb = edge(tywfb,'canny');
%join edges
diskEnt1 = strel('disk',8); % radius of 4
tyjoin1 = imclose(tyedb,diskEnt1);
figure; imshow(tyjoin1)
It is at this stage that I am struggling. The edges do not quite join, no matter how much I play around with the morphological structuring element. Perhaps there is a better way to complete the edges? Linked is an example of the figure this code outputs:
The reason that I am trying to join the edges is so that I can fill the perimeter with white pixels and then use regionprops to output the area. I have tried using the imfill command, but cannot seem to fill the outline as there are a large number of dark regions to be filled within the perimeter.
Is there a better way to get the area of one of these melt figures that is more appropriate in this case?
As background research: I can make this method work for a simple image consisting of a black circle on a white background using the below code. However I don't know how edit it to handle more complex images with edges that are less well defined.
clear all
close all
clc
%% Read in RGB image from directory
RGB1 = imread('1.jpg') ;
%% Convert RPG image to grayscale image
I1 = rgb2gray(RGB1) ;
%% Transform Image
%CROP
IC1 = imcrop(I1,[74 43 278 285]);
%BINARY IMAGE
BW1 = im2bw(IC1); %Convert to binary image so the boundary can be traced
%FIND PERIMETER
BWP1 = bwperim(BW1);
%Traces perimeters of objects & colours them white (1).
%Sets all other pixels to black (0)
%Doing the same job as an edge detection algorithm?
%FILL PERIMETER WITH WHITE IN ORDER TO MEASURE AREA AND PERIMETER
BWF1 = imfill(BWP1); %This opens figure and allows you to select the areas to fill with white.
%MEASURE PERIMETER
D1 = regionprops(BWF1, 'area', 'perimeter');
%Returns an array containing the properties area and perimeter.
%D1(1) returns the perimeter of the box and an area value identical to that
%perimeter? The box must be bounded by a perimeter.
%D1(2) returns the perimeter and area of the section filled in BWF1
%% Display Area and Perimeter data
D1(2)
I think you might have room to improve the effect of edge detection in addition to the morphological transformations, for instance the following resulted in what appeared to me a relatively satisfactory perimeter.
tyedb = edge(tywfb,'sobel',0.012);
%join edges
diskEnt1 = strel('disk',7); % radius of 4
tyjoin1 = imclose(tyedb,diskEnt1);
In addition I used bwfill interactively to fill in most of the interior. It should be possible to fill the interior programatically but I did not pursue this.
% interactively fill internal regions
[ny nx] = size(tyjoin1);
figure; imshow(tyjoin1)
tyjoin2=tyjoin1;
titl = sprintf('click on a region to fill\nclick outside window to stop...')
while 1
pts=ginput(1)
tyjoin2 = bwfill(tyjoin2,pts(1,1),pts(1,2),8);
imshow(tyjoin2)
title(titl)
if (pts(1,1)<1 | pts(1,1)>nx | pts(1,2)<1 | pts(1,2)>ny), break, end
end
This was the result I obtained
The "fractal" properties of the perimeter may be of importance to you however. Perhaps you want to retain the folds in your shape.
You might want to consider Active Contours. This will give you a continous boundary of the object rather than patchy edges.
Below are links to
A book:
http://www.amazon.co.uk/Active-Contours-Application-Techniques-Statistics/dp/1447115570/ref=sr_1_fkmr2_1?ie=UTF8&qid=1377248739&sr=8-1-fkmr2&keywords=Active+shape+models+Andrew+Blake%2C+Michael+Isard
A demo:
http://users.ecs.soton.ac.uk/msn/book/new_demo/Snakes/
and some Matlab code on the File Exchange:
http://www.mathworks.co.uk/matlabcentral/fileexchange/28149-snake-active-contour
and a link to a description on how to implement it: http://www.cb.uu.se/~cris/blog/index.php/archives/217
Using the implementation on the File Exchange, you can get something like this:
%% Load the image
% You could use the segmented image obtained previously
% and then apply the snake on that (although I use the original image).
% This will probably make the snake work better and the edges
% in your image is not that well defined.
% Make sure the original and the segmented image
% have the same size. They don't at the moment
I = imread('33kew0g.jpg');
% Convert the image to double data type
I = im2double(I);
% Show the image and select some points with the mouse (at least 4)
% figure, imshow(I); [y,x] = getpts;
% I have pre-selected the coordinates already
x = [ 525.8445 473.3837 413.4284 318.9989 212.5783 140.6320 62.6902 32.7125 55.1957 98.6633 164.6141 217.0749 317.5000 428.4172 494.3680 527.3434 561.8177 545.3300];
y = [ 435.9251 510.8691 570.8244 561.8311 570.8244 554.3367 476.3949 390.9586 311.5179 190.1085 113.6655 91.1823 98.6767 106.1711 142.1443 218.5872 296.5291 375.9698];
% Make an array with the selected coordinates
P=[x(:) y(:)];
%% Start Snake Process
% You probably have to fiddle with the parameters
% a bit more that I have
Options=struct;
Options.Verbose=true;
Options.Iterations=1000;
Options.Delta = 0.02;
Options.Alpha = 0.5;
Options.Beta = 0.2;
figure(1);
[O,J]=Snake2D(I,P,Options);
If the end result is an area/diameter estimate, then why not try to find maximal and minimal shapes that fit in the outline and then use the shapes' area to estimate the total area. For instance, compute a minimal circle around the edge set then a maximal circle inside the edges. Then you could use these to estimate diameter and area of the actual shape.
The advantage is that your bounding shapes can be fit in a way that minimizes error (unbounded edges) while optimizing size either up or down for the inner and outer shape, respectively.

matlab encircle white areas in a black image

I have a grayscale image, which I convert to black and white image, and do some processing on it. After the processing, I have a black and white image which has groups of white pixels in a black image. So I want to place circles around the areas which are white in resultant image, but in original image.
I have thought of many approaches but am still unable to start with any approach.
Please help.
You can use regionprops to get some statistics about connected white regions in a binary image, and estimate a region radius from that.
im = imread('moon.jpg');
bw = im2bw(im);
stats = regionprops(bw);
imshow(im);
hold on;
t = 0:.01:2*pi;
for i = 1:numel(stats)
bb = stats(i).BoundingBox;
radius = mean([bb(3),bb(4)])/2;
plot(bb(1)+radius+radius*sin(t), bb(2)+radius+radius*cos(t));
end
Gives: