Get outer indecies of a region in a logical image - matlab

If I've any m x n logical image of a white region like the following:
How to get the indices of the boundary line between the white and black regions?

This simply comes down to detecting the edges of the given image. MATLAB already has a built-in implementation for that in the edge command. Here's an example of detecting the boundaries of an image I using the Canny filter:
A = edge(I, 'canny');
The non-zero elements in the resulting image A are what you're after. You can then use find to obtain their indices.

Since your input is a clear binary image, there is no need to use edge as suggested by #EitanT.
Getting the perimeter using morphological operations imdilate, imerode and regionprops:
% let input image be bw
we = bw & ~imerode( bw, strel('disk', 1) ); % get a binary image with only the boundary pixels set
st = regionprops(we, 'PixelIdxList'); % get the linear indices of the boundary
% get a binary image with pixels on the outer side of the shape set
be = ~bw & imdilate( bw, strel('disk', 1) );
st = regionprops(be, 'PixelList'); % get the row-col indices of the boundary

Related

Contrast Stretching for colore images with MATLAB

i'm working in matlab and i wanted to apply the Contrast Stretching for grey scale image and also RGB image ,
so for the grey scale i've tried this one and it worked
clear all;
clc;
itemp = imread('cameraman.tif'); %read the image
i = itemp(:,:,1);
rtemp = min(i); % find the min. value of pixels in all the
columns (row vector)
rmin = min(rtemp); % find the min. value of pixel in the image
rtemp = max(i); % find the max. value of pixels in all the
columns (row vector)
rmax = max(rtemp); % find the max. value of pixel in the image
m = 255/(rmax - rmin); % find the slope of line joining point
(0,255) to (rmin,rmax)
c = 255 - m*rmax; % find the intercept of the straight line
with the axis
i_new = m*i + c; % transform the image according to new slope
figure,imshow(i); % display original image
figure,imshow(i_new); % display transformed image
this is for greyscale image ,
the problem is that that i don't know how to do for the RGB image
any idea? how to implement that?
thank you :)
Could the function stretchlim (reference) be useful for your purpose?
Find limits to contrast stretch image.
Low_High = stretchlim(RGB,Tol) returns Low_High, a two-element vector
of pixel values that specify lower and upper limits that can be used
for contrast stretching truecolor image RGB.
img = imread('myimg.png');
lohi = stretchlim(img,[0.2 0.8]);
If you write
rmin = min(i(:));
Then it computes the minimum over all values in i. This will work for RGB images also, which simply are 3D matrices with 3 values along the 3rd dimension.
The rest of your code also applies directly to such images.

Count circle objects in an image using matlab

How to count circle objects in a bright image using MATLAB?
The input image is:
imfindcircles function can't find any circle in this image.
Based on well known image processing techniques, you can write your own processing tool:
img = imread('Mlj6r.jpg'); % read the image
imgGray = rgb2gray(img); % convert to grayscale
sigma = 1;
imgGray = imgaussfilt(imgGray, sigma); % filter the image (we will take derivatives, which are sensitive to noise)
imshow(imgGray) % show the image
[gx, gy] = gradient(double(imgGray)); % take the first derivative
[gxx, gxy] = gradient(gx); % take the second derivatives
[gxy, gyy] = gradient(gy); % take the second derivatives
k = 0.04; %0.04-0.15 (see wikipedia)
blob = (gxx.*gyy - gxy.*gxy - k*(gxx + gyy).^2); % Harris corner detector (high second derivatives in two perpendicular directions)
blob = blob .* (gxx < 0 & gyy < 0); % select the top of the corner (i.e. positive second derivative)
figure
imshow(blob) % show the blobs
blobThresshold = 1;
circles = imregionalmax(blob) & blob > blobThresshold; % find local maxima and apply a thresshold
figure
imshow(imgGray) % show the original image
hold on
[X, Y] = find(circles); % find the position of the circles
plot(Y, X, 'w.'); % plot the circle positions on top of the original figure
nCircles = length(X)
This code counts 2710 circles, which is probably a slight (but not so bad) overestimation.
The following figure shows the original image with the circle positions indicated as white dots. Some wrong detections are made at the border of the object. You can try to make some adjustments to the constants sigma, k and blobThresshold to obtain better results. In particular, higher k may be beneficial. See wikipedia, for more information about the Harris corner detector.

Watershed Algorithm setting removing all connected components

I'm using the watershed algorithm to try and segment touching nuclei. A typical image may look like:
or this:
I'm trying to apply the watershed algorithm with this code:
show(RGB_img)
%Convert to grayscale image
I = rgb2gray(RGB_img);
%Take structuring element of a disk of size 10, for the morphological transformations
%Attempt to subtract the background from the image: top hat is the
%subtraction of the open image from the original
%Morphological transformation to subtract background noise from the image
%Tophat is the subtraction of an opened image from the original. Remove all
%images smaller than the structuring element of 10
I1 = imtophat(I, strel('disk', 10));
%Increases contrast
I2 = imadjust(I1);
%show(I2,'contrast')
%Assume we have background and foreground and assess thresh as such
level = graythresh(I2);
%Convert to binary image based on graythreshold
BW = im2bw(I2,level);
show(BW,'C');
BW = bwareaopen(BW,8);
show(BW,'C2');
BW = bwdist(BW) <= 1;
show(BW,'joined');
%Complement because we want image to be black and background white
C = ~BW;
%Use distance tranform to find nearest nonzero values from every pixel
D = -bwdist(C);
%Assign Minus infinity values to the values of C inside of the D image
% Modify the image so that the background pixels and the extended maxima
% pixels are forced to be the only local minima in the image (So you could
% hypothetically fill in water on the image
D(C) = -Inf;
%Gets 0 for all watershed lines and integers for each object (basins)
L = watershed(D);
show(L,'L');
%Takes the labels and converts to an RGB (Using hot colormap)
fin = label2rgb(L,'hot','w');
% show(fin,'fin');
im = I;
%Superimpose ridgelines,L has all of them as 0 -> so mark these as 0(black)
im(L==0)=0;
clean_img = L;
show(clean_img)
For whatever reason after C = ~BW; the whole image goes dark. This very same code block has worked on a handful of other images, all of which were more "solid" or not as grainy as these. However, I thought I compensated for this with BW = bwdist(BW) <= 1;. I've experimented a ton and I don't really know what's happening. Any help would be great!
Ps. this is the image after BW = bwareaopen(BW,8);
Before the top-hat, you should perform a closing and an opening in order to reduce the noise.
If you perform an area opening on a noisy image, you may end up with the result on your black and white image.
So it would be:
Closing and opening
Top-Hat
Area opening if still necessary
Thresholding
Erosion and dilation to find the inner and outer markers respectively
Watershed (never use a watershed without markers).

how to embed a watermark inside roi in matlab

the region of interest in the image are calculated. Now how to embed the watermark into the roi..i ve put the code for embedding it in the whole image in lsb. How can it modified for roi alone?
clear all;
file_name='pout.tif';
cover_object=imread(file_name);
file_name='cameraman.tif';
message=imread(file_name);
message=double(message);
message=round(message./256);
message=uint8(message);
Mc=size(cover_object,1);
Nc=size(cover_object,2);
Mm=size(message,1);
Nm=size(message,2);
for ii = 1:Mc
for jj = 1:Nc
watermark(ii,jj)=message(mod(ii,Mm)+1,mod(jj,Nm)+1);
end
end
watermarked_image=cover_object;
for ii = 1:Mc
for jj = 1:Nc
watermarked_image(ii,jj)=bitset(watermarked_image(ii,jj),1,watermark(ii,jj));
end
end
imwrite(watermarked_image,'watermarkedimage','bmp');
figure(1)
imshow(watermarked_image,[])
title('Watermarked Image')
If your roi is rectangular, just loop over the appropriate subsection of the image rather than the whole thing.
If not, and you can define the watermarking as some function:
imgout = watermark(img1, img2);
Then you can use roifilt2 to apply that function just in your roi.
In this simple example,mask is a BW matrix where 1 indicates part of our roi (a mask can be created several different ways including using some of the interactive roi functions, see bottom section). img1 and img2 have already been loaded:
f = #(x) watermark(x,img2); % our very basic function
imgout = roifilt2(img1,mask,f);
Complications may arise if your img2 is smaller than img1 (or if you want to resize it to just cover the roi area). In this case, do everything on a subsection of img1/mask and then assemble the final image:
img1_s = img1(a:b,c:d); % these return the same size as img2
mask_s = mask(a:b,c:d);
imgout_s = roifilt2(img1_s,mask1_s,f);
imgout = img1;
imgout(a:b,c:d) = imgout_s;
A mask can be created several ways, some using the interactive roi functions, some not. A lot depends on how you have your roi in the first place - do you have a centre/radius, or do you want to hand-pick the location interactively, etc. Here are a few examples making use of the Image Processing Tool Box:
Interactive ROI function and createMask.
This will work for any of the interactive roi functions (imellipse, imfreehand, etc). You can interactively adjust the mask between the second and third steps. Do not close the image window before calling createMask.
h = imshow(img); %display image
e = imellipse(gca,[50 50 100 100]); % select roi
mask = createMask(e,h); % return mask
List of x/y points and poly2mask
If you have a list of points defining the outer edge of your roi, a quick non-interactive way of producing a mask is to use poly2mask. The third and fourth values define the total size of the mask returned.
mask = poly2mask(x,y,size(img,1),size(img,2));
Using morphological operators
strel defines a structuring element, and imdilate performs a dilation using that structuring element. Given an image which contains a single point, what that does is replace the point with the structuring element - in this case disk which will produce a circle (or as close as you can get using pixels). Other shapes (e.g. diamond) can be used with strel
mask = zeros(size(img));
mask(a,b) = 1; % a,b is the centre point of the circle
se = strel(disk,r,0); %r is the radius of the circle
mask = imdilate(mask,se);

remove the holes in an image by average values of surrounding pixels

can any one please help me in filling these black holes by values taken from neighboring non-zero pixels.
thanks
One nice way to do this is to is to solve the linear heat equation. What you do is fix the "temperature" (intensity) of the pixels in the good area and let the heat flow into the bad pixels. A passable, but somewhat slow, was to do this is repeatedly average the image then set the good pixels back to their original value with newImage(~badPixels) = myData(~badPixels);.
I do the following steps:
Find the bad pixels where the image is zero, then dilate to be sure we get everything
Apply a big blur to get us started faster
Average the image, then set the good pixels back to their original
Repeat step 3
Display
You could repeat averaging until the image stops changing, and you could use a smaller averaging kernel for higher precision---but this gives good results:
The code is as follows:
numIterations = 30;
avgPrecisionSize = 16; % smaller is better, but takes longer
% Read in the image grayscale:
originalImage = double(rgb2gray(imread('c:\temp\testimage.jpg')));
% get the bad pixels where = 0 and dilate to make sure they get everything:
badPixels = (originalImage == 0);
badPixels = imdilate(badPixels, ones(12));
%# Create a big gaussian and an averaging kernel to use:
G = fspecial('gaussian',[1 1]*100,50);
H = fspecial('average', [1,1]*avgPrecisionSize);
%# User a big filter to get started:
newImage = imfilter(originalImage,G,'same');
newImage(~badPixels) = originalImage(~badPixels);
% Now average to
for count = 1:numIterations
newImage = imfilter(newImage, H, 'same');
newImage(~badPixels) = originalImage(~badPixels);
end
%% Plot the results
figure(123);
clf;
% Display the mask:
subplot(1,2,1);
imagesc(badPixels);
axis image
title('Region Of the Bad Pixels');
% Display the result:
subplot(1,2,2);
imagesc(newImage);
axis image
set(gca,'clim', [0 255])
title('Infilled Image');
colormap gray
But you can get a similar solution using roifill from the image processing toolbox like so:
newImage2 = roifill(originalImage, badPixels);
figure(44);
clf;
imagesc(newImage2);
colormap gray
notice I'm using the same badPixels defined from before.
There is a file on Matlab file exchange, - inpaint_nans that does exactly what you want. The author explains why and in which cases it is better than Delaunay triangulation.
To fill one black area, do the following:
1) Identify a sub-region containing the black area, the smaller the better. The best case is just the boundary points of the black hole.
2) Create a Delaunay triangulation of the non-black points in inside the sub-region by:
tri = DelaunayTri(x,y); %# x, y (column vectors) are coordinates of the non-black points.
3) Determine the black points in which Delaunay triangle by:
[t, bc] = pointLocation(tri, [x_b, y_b]); %# x_b, y_b (column vectors) are coordinates of the black points
tri = tri(t,:);
4) Interpolate:
v_b = sum(v(tri).*bc,2); %# v contains the pixel values at the non-black points, and v_b are the interpolated values at the black points.