I am trying to make a binary region of interest mask over an image stack (GUI). Here is what I have thus far:
% Initalize lesion mask
LesionMask = zeros(size(handles.ImageOne));
% Create an ellipse for roi analysis
Lesion = imellipse(handles.axes1);
% Save roi to 3D binary mask
LesionMask(:,:,handles.CurrentSlice) = Lesion.createMask();
boundary = bwboundaries(LesionMask(:,:,handles.CurrentSlice))
Now I would like to overlay the boundary over my image, in particular, I would like it to stay even when I go through my image stack.
In short, I would like to plot the edge of the ellipse over my image.
Thanks!
This might work for you when added to your code at the end -
hold on
for k = 1:numel(boundary)
plot(boundary{k}(:,2), boundary{k}(:,1), 'r', 'Linewidth', 3) %// Red border
end
Inspired from this blog
If you would like to keep the edge on the image saved for later usage, try this -
[M,N,C] = size(handles.ImageOne)
t1 = cell2mat(boundary);
ind1 = sub2ind([M N],t1(:,1),t1(:,2));
ind2 = bsxfun(#plus,ind1,[0:C-1].*(M*N));
handles.ImageOne(ind2)=0; %// Creates a black border
Related
I'm using the watershed algorithm to segment bright spots on a dark background. The code is provided below, along with some images it generates.
In the second image, I've marked with red crosses the areas of enclosed background which are segmented as 'cells' (they're not biological cells, just using the word) - this is incorrect, they're part of the background, just enclosed by 'cells'. I see that this creates a false minimum, any help on how to prevent this?
% Improve contrast, binarize
RFP_adjust = imadjust(RFP_blur, stretchlim(RFP_blur, 0.001));
figure, imshow(RFP_adjust), title('Contrast adjust');
RFP_binarized = imbinarize(RFP_adjust);
RFP_perimeters = bwperim(RFP_binarized);
% figure, imshow(RFP_binarized), title('Otsu thresholding');
%2B - SEGMENTATION BY WATERSHED METHOD
% Discover putative cell centroids and process
RFP_maxs = imextendedmax(RFP_adjust, 3000);
RFP_maxs = imclose(RFP_maxs, strel('disk',5));
RFP_maxs = imfill(RFP_maxs, 'holes');
RFP_maxs = bwareaopen(RFP_maxs, 5);
RFP_max_overlay = imoverlay(RFP_adjust, RFP_perimeters | RFP_maxs, [1 .3 .3]);
figure, imshow(RFP_max_overlay), title('Maxima');
% Obtain complement - maxima become low-points (required for watershed)
RFP_comp = imcomplement(RFP_adjust);
RFP_imposemin = imimposemin(RFP_comp, ~RFP_binarized | RFP_maxs);
figure, imshow(RFP_imposemin), title('Inverted Maxima');
% Apply watershed
RFP_watershed = watershed(RFP_imposemin);
mask = im2bw(RFP_watershed, 1);
overlay3 = imoverlay(RFP_adjust, mask, [1 .3 .3]);
figure, imshow(overlay3), title('Segmented cells');
% Segment
RFP_cc = bwconncomp(RFP_watershed);
RFP_label_matrix = labelmatrix(RFP_cc);
whos labeled;
RFP_label = label2rgb(RFP_label_matrix, #spring, 'c', 'shuffle');
figure, imshow(RFP_label), title('Cells segmented');
Image 0 - result for image titled 'Maxima' (i.e. adjusted original image with maxima and outlines overlaid).
Image 1 - the result for image titled 'inverted maxima'
Image 2 - the result for image titled 'Cells segmented'
I would suggest something like what is done in the example included for the watershed function: use the background mask to set those pixels to Inf, perform the watershed operation, then set the background pixels in the result to 0. I believe you could change the watershed section of your code like so to achieve this:
% Apply watershed
RFP_watershed = RFP_imposemin; % Added
RFP_watershed(~RFP_binarized) = Inf; % Added
RFP_watershed = watershed(RFP_watershed); % Modified
RFP_watershed(~RFP_binarized) = 0; % Added
mask = im2bw(RFP_watershed, 1);
overlay3 = imoverlay(RFP_adjust, mask, [1 .3 .3]);
figure, imshow(overlay3), title('Segmented cells');
There no magic bullet, but a few things you can try.
One is to filter the image with a very large circular disc, creating a blurry image that looks like the background. Then subtract it from the original image. That will tend to force the actual background to zero.
Another is to Otsu threshold to separate foreground from background. That creates a binary image. Then do a morphological open operation using a mask designed to look like the actual cells.
I'm working on an application and I'm at a stage where I'm comparing two images to see if they have any resemblance, with one another. I have managed to do this, an example you can find here.
From the image, it will display white spaces for pixels that are near the same for both images given. What I want to do next is get the coordinates of the white spaces and plot them onto the original image to highlight the strongest features about the coin. However, I'm unsure how to do this as I'm rather new to Matlab.
firstImage = sprintf('M:/Project/MatLab/Coin Image Processing/Image Processing/test-1.jpg');
secondImage = sprintf('M:/Project/MatLab/Coin Image Processing/Image Processing/test-99.jpg');
a = rgb2gray(imread(firstImage));
b = rgb2gray(imread(secondImage));
axes(handles.axes4);
imshow(a==b);
title('Scanning For Strongest Features', 'fontweight', 'bold')
From using disp(a==b), I can see which points of both pictures are the same. So my guess is that I need to do something where I get the coordinates of all the zeroes and then plot them onto the original image in a way that highlights it, similar to using a yellow highlighter, but I just don't know how.
If I got your question, I think you should use find to collect all the coordinates for which a==b:
[X, Y] = find(a == b); % Find coordinates for which the two images are equal
imshow(a), axis image; % Show first image
hold on
plot(Y, X, 'y.'); % Overlay those coordinates
hold off
You can use a transparent overlay to plot the region of interest.
figure
imshow(originalImage); % plot the original image
hold on
% generate a red overlay
overlay(:, :, 1) = ones(size(a)); % red channel
overlay(:, :, 2) = zeros(size(a)); % green channel
overlay(:, :, 3) = zeros(size(a)); % blue channel
h = imshow(overlay); % plot the overlay
set(h, 'AlphaData', (a == b) * 0.5); % set the transparency to 50% if a == b and 0% otherwise
I'm trying to measure the areas of each particle shown in this image:
I managed to get the general shape of each particle using MSER shown here:
but I'm having trouble removing the background. I tried using MATLAB's imfill, but it doesn't fill all the particles because some are cut off at the edges. Any tips on how to get rid of the background or find the areas of the particles some other way?
Cheers.
Edit: This is what imfill looks like:
Edit 2: Here is the code used to get the outline. I used this for the MSER.
%Compute region seeds and elliptial frames.
%MinDiversity = how similar to its parent MSER the region is
%MaxVariation = stability of the region
%BrightOnDark is used as the void is primarily dark. It also prevents dark
%patches in the void being detected.
[r,f] = vl_mser(I,'MinDiversity',0.7,...
'MaxVariation',0.2,...
'Delta',10,...
'BrightOnDark',1,'DarkOnBright',0) ;
%Plot region frames, but not used right now
%f = vl_ertr(f) ;
%vl_plotframe(f) ;
%Plot MSERs
M = zeros(size(I)) ; %M = no of overlapping extremal regions
for x=r'
s = vl_erfill(I,x) ;
M(s) = M(s) + 1;
end
%Display region boundaries
figure(1) ;
clf ; imagesc(I) ; hold on ; axis equal off; colormap gray ;
%Create contour plot using the values
%0:max(M(:))+.5 is the no of contour levels. Only level 0 is needed so
%[0 0] is used.
[c,h]=contour(M,[0 0]) ;;
set(h,'color','r','linewidth',1) ;
%Retrieve the image data from the contour image
f = getframe;
I2 = f.cdata;
%Convert the image into binary; the red outlines are while while the rest
%is black.
I2 = all(bsxfun(#eq,I2,reshape([255 0 0],[1 1 3])),3);
I2 = imcrop(I2,[20 1 395 343]);
imshow(~I2);
Proposed solution / trick and code
It seems you can work with M here. One trick that you can employ here would be to pad zeros all across the boundaries of the image M and then fill its holes. This would take care of filling the blobs that were touching the boundaries before, as now there won't be any blob touching the boundaries because of the zeros padding.
Thus, after you have M, you can add this code -
%// Get a binary version of M
M_bw = im2bw(M);
%// Pad zeros all across the grayscale image
padlen = 2; %// length of zeros padding
M_pad = padarray(M_bw,[padlen padlen],0);
%// Fill the holes
M_pad_filled = imfill(M_pad,'holes');
%// Get the background mask after the holes are gone
background_mask = ~M_pad_filled(padlen+1:end-padlen,padlen+1:end-padlen);
%// Overlay the background mask on the original image to show that you have
%// a working background mask for use
I(background_mask) = 0;
figure,imshow(I)
Results
Input image -
Foreground mask (this would be ~background_mask) -
Output image -
I have a code that detects a face in an image and places a bounding box around the image like below.
But I want to go further and colour the area outside the bounding box black so that only the face can be seen and the background becomes black.
Original code..
FDetect = vision.CascadeObjectDetector;
I = imread('PresidentClinton.jpg');
%Returns Bounding Box values based on number of objects
BB = step(FDetect,I);
figure,
imshow(I); hold on
for i = 1:size(BB,1)
rectangle('Position',BB(i,:),'LineWidth',5,'LineStyle','-','EdgeColor','r');
end
title('Face Detection');
hold off;
Here is a simple method in which you first create a target image of the same size/class as your original image and fill it with black. Then you get the rectangle coordinates and assign the data from the original image to the target image:
clear
close all
A = imread('peppers.png');
B = zeros(size(A),class(A)); % //Pre-define target image of identical size and class than original.
%// You could also use this line:
%//B = zeros(size(A),'like',A);
hRect = rectangle('Position',[100 100 200 160],'LineWidth',3); %// Define rectangle
RectPos = get(hRect, 'Position'); %// Get the coordinates of the rectangle.
x = RectPos(1):RectPos(1)+RectPos(3); %// Define x- and y-span
y = RectPos(2):RectPos(2)+RectPos(4);
B(x,y,:) = A(x,y,:); %// Assign the selected part of the image to B
figure
subplot(1,2,1)
imshow(A)
subplot(1,2,2)
imshow(B)
Giving something like this:
There are other ways of course but I think this one is straightforward and easy to implement in a loop.
I am trying to fit a curve on a specific area in an image using the color of the pixels. As it is shown in the image (https://db.tt/PcxHGbT3), there is a region in the image with grey color that can be detected using image processing in Matlab. Once I found the position of the pixels using the following code in Matlab:
im = imread('layer.jpg');
figure,imshow(im);title('Original Image');
[y,x] = find(all(im<100, 3));
I need to find the position of the points sitting on the central line of the region which is shown in the image (https://db.tt/PcxHGbT3). I was thinking to somehow fit a curve, but I have no idea on how I can do this in Matlab. Is there any shorter way other than processing all of the points?
Can you use im2bw(im, 100/256) to threshold the image and bwmorph(BW, 'thin', INF) to thin the result?
You could use matlab binary image operations to get centroids of the points withing the gray area. Having centroids you can do whatever with them, e.g. fitting lines. This is one example based on your image, how this can be done.
% convert rgb to gray scale
im = rgb2gray(imread('layer.jpg'));
% mask of gray-color with points
bwMask1 = im < 100;
% mask with points only
bwMask2 = im < 20;
% remove points outside gray area
bwMask3 = bwareaopen(bwMask1, 400);
% points only withing gray ![enter image description here][1]area
bwMask4 = bwMask2 & ~(bwMask3 - bwMask2);
% label all points
[L] = bwlabel(bwMask4, 8);
% calculate points parameters
pointStats = regionprops(L);
% get centroids of each point
pointCentroidsCell = {pointStats(:).Centroid};
pointCentroidsMat = vertcat(pointCentroidsCell{:});
%plot results:
RGB = label2rgb(L);
figure, imshow(RGB); title('labeled points');
![enter image description here][2]
figure,imshow(im); hold on;
plot(pointCentroidsMat(:, 1), pointCentroidsMat(:, 2), 'r*');
title('Found centroinds');