Matlab - Indexes of image pixels in bwconncomp function - matlab

I've been writing a text detection code and I'm working with a binary map as a mask to work on the image. After I get the candidate text regions I apply the bwconncomp function on the image after applying the mask on it to get the position of those regions.
Now I've created a loop to discard the regions that don't satisfy some "clauses". When it doesn't, I put all the pixels in that region to 0 (image(cc.PixelIdxList{region})=0) and the same thing with the binary map (map(cc.PixelIdxList{region})=0).
When I plot the map and the image before getting in the loop they tally, but after it they don't. When I plot the image after the loop it shows that it erased the region perfectly, but that's not the case with the map. Sometimes there are left some pixels that are within the region.
So my guess is: the pixel indexes that bwconncomp gives to the pixels in the image are not exactly the same as those in the map, that's why some pixels in the map aren't erased when they should be. Am I right? Or should I be looking somewhere else?

I was using the grayscale image to compute the connected components and not the binary map, so when some of those regions had pixels with value 0, the bwconncomp function computed them as they weren't part of the region. So then when I erased a region those pixels stayed at value 0 while the pixels on the map weren't erased.

Related

Selecting Overlapping / Touching regions (Binary Images, Matlab)

I'm trying to select overlapping/ touching images from 2 binary images. The first image (blue circles) has the main body and I want to find any green triangles attached to it.
1st Binary Image here (colored for identification)
2nd Binary Image here
FinalImage = BinaryImage1 | BinaryImage2;
**Apply Filter**
Expected result:
Note how the unattached Green triangles are removed, & all blue circles are retained.
Is there a way to do this trick?
This calls for a morphological reconstruction! In morphological reconstruction, you specify a marker and start reconstructing the original image from that marker point using a morphological dilation.
Luckily for us, MATLAB already has a function for that, called imreconstruct in the Image Processing Toolbox, which is called by imreconstruct(marker,image)
To recognize touching, but non-overlapping figures, we can just do a dilation on one of the input image to make touching figures overlap. As structuring element we can e.g. use a 3x3 square, so we also recognize 8-connected figures. After that we use the overlapping points as markers and do the morphological reconstruction using the combined image.
dilatedImage1 = imdilate(binaryImage1, strel('square',3));
finalImage = imreconstruct(dilatedImage1&binaryImage2, dilatedImage1|binaryImage2);
As you write that all circles, i.e. all parts from binaryImage1 should be retained, we can just add binaryImage1 to the result using
finalImage = finalImage | binaryImage1;
For your two example images, this results in:
The circle on the upper right is not connected to any triangle. I don't know how that triangle appeared in your expected result image, but I suppose this is only for demonstration purposes.
Note: I imported the .jpg example images in MATLAB, which lead to ugly borders, so I did a morphological opening on the images first. The borders are still not optimal, but it doesn't look that bad.

Creating intensity band across image border using matlab

I have this image (8 bit, pseudo-colored, gray-scale):
And I want to create an intensity band of a specific measure around it's border.
I tried erosion and other mathematical operations, including filtering to achieve the desired band but the actual image intensity changes as soon as I use erosion to cut part of the border.
My code so far looks like:
clear all
clc
x=imread('8-BIT COPY OF EGFP001.tif');
imshow(x);
y = imerode(x,strel('disk',2));
y1=imerode(y,strel('disk',7));
z=y-y1;
figure
z(z<30)=0
imshow(z)
The main problem I am encountering using this is that it somewhat changes the intensity of the original images as follows:
So my question is, how do I create such a band across image border without changing any other attribute of the original image?
Going with what beaker was talking about and what you would like done, I would personally convert your image into binary where false represents the background and true represents the foreground. When you're done, you then erode this image using a good structuring element that preserves the roundness of the contours of your objects (disk in your example).
The output of this would be the interior of the large object that is in the image. What you can do is use this mask and set these locations in the image to black so that you can preserve the outer band. As such, try doing something like this:
%// Read in image (directly from StackOverflow) and pseudo-colour the image
[im,map] = imread('http://i.stack.imgur.com/OxFwB.png');
out = ind2rgb(im, map);
%// Threshold the grayscale version
im_b = im > 10;
%// Create structuring element that removes border
se = strel('disk',7);
%// Erode thresholded image to get final mask
erode_b = imerode(im_b, se);
%// Duplicate mask in 3D
mask_3D = cat(3, erode_b, erode_b, erode_b);
%// Find indices that are true and black out result
final = out;
final(mask_3D) = 0;
figure;
imshow(final);
Let's go through the code slowly. The first two lines take your PNG image, which contains a grayscale image and a colour map and we read both of these into MATLAB. Next, we use ind2rgb to convert the image into its pseudo-coloured version. Once we do this, we use the grayscale image and threshold the image so that we capture all of the object pixels. I threshold the image with a value of 10 to escape some quantization noise that is seen in the image. This binary image is what we will operate on to determine those pixels we want to set to 0 to get the outer border.
Next, we declare a structuring element that is a disk of a radius of 7, then erode the mask. Once I'm done, I duplicate this mask in 3D so that it has the same number of channels as the pseudo-coloured image, then use the locations of the mask to set the values that are internal to the object to 0. The result would be the original image, but having the outer contours of all of the objects remain.
The result I get is:

Matlab: separate connected components

I was working on my image processing problem with detecting coins.
I have some images like this one here:
and wanted to separate the falsely connected coins.
We already tried the watershed method as stated on the MATLAB-Homepage:
the-watershed-transform-strategies-for-image-segmentation.html
especially since the first example is exactly our problem.
But instead we get a somehow very messed up separation as you can see here:
We already extracted the area of the coin using the regionprops Extrema parameter and casting the watershed only on the needed area.
I'd appreciate any help with the problem or even another method of getting it separated.
If you have the Image Processing Toolbox, I can also suggest the Circular Hough Transform through imfindcircles. However, this requires at least version R2012a, so if you don't have it, this won't work.
For the sake of completeness, I'll assume you have it. This is a good method if you want to leave the image untouched. If you don't know what the Hough Transform is, it is a method for finding straight lines in an image. The circular Hough Transform is a special case that aims to find circles in the image.
The added advantage of the circular Hough Transform is that it is able to detect partial circles in an image. This means that those regions in your image that are connected, we can detect them as separate circles. How you'd call imfindcircles is in the following fashion:
[centers,radii] = imfindcircles(A, radiusRange);
A would be your binary image of objects, and radiusRange is a two-element array that specifies the minimum and maximum radii of the circles you want to detect in your image. The outputs are:
centers: A N x 2 array that tells you the (x,y) co-ordinates of each centre of a circle that is detected in the image - x being the column and y being the row.
radii: For each corresponding centre detected, this also gives the radius of each circle detected. This is a N x 1 array.
There are additional parameters to imfindcircles that you may find useful, such as the Sensitivity. A higher sensitivity means that it is able to detect circular shapes that are more non-uniform, such as what you are showing in your image. They aren't perfect circles, but they are round shapes. The default sensitivity is 0.85. I set it to 0.9 to get good results. Also, playing around with your image, I found that the radii ranged from 50 pixels to 150 pixels. Therefore, I did this:
im = im2bw(imread('http://dennlinger.bplaced.net/t06-4.jpg'));
[centers,radii] = imfindcircles(im, [50 150], 'Sensitivity', 0.9);
The first line of code reads in your image directly from StackOverflow. I also convert this to logical or true black and white as the image you uploaded is of type uint8. This image is stored in im. Next, we call imfindcircles in the method that we described.
Now, if we want to visualize the detected circles, simply use imshow to show your image, then use the viscircles to draw the circles in the image.
imshow(im);
viscircles(centers, radii, 'DrawBackgroundCircle', false);
viscircles by default draws the circles with a white background over the contour. I want to disable this because your image has white circles and I don't want to show false contouring. This is what I get with the above code:
Therefore, what you can take away from this is the centers and radii variables. centers will give you the centre of each detected circle while radii will tell you what the radii is for each circle.
Now, if you want to simulate what regionprops is doing, we can iterate through all of the detected circles and physically draw them onto a 2D map where each circle would be labeled by an ID number. As such, we can do something like this:
[X,Y] = meshgrid(1:size(im,2), 1:size(im,1));
IDs = zeros(size(im));
for idx = 1 : numel(radii)
r = radii(idx);
cen = centers(idx,:);
loc = (X - cen(1)).^2 + (Y - cen(2)).^2 <= r^2;
IDs(loc) = idx;
end
We first define a rectangular grid of points using meshgrid and initialize an IDs array of all zeroes that is the same size as the image. Next, for each pair of radii and centres for each circle, we define a circle that is centered at this point that extends out for the given radius. We then use these as locations into the IDs array and set it to a unique ID for that particular circle. The result of IDs will be that which resembles the output of bwlabel. As such, if you want to extract the locations of where the idx circle is, you would do:
cir = IDs == idx;
For demonstration purposes, this is what the IDs array looks like once we scale the IDs such that it fits within a [0-255] range for visibility:
imshow(IDs, []);
Therefore, each shaded circle of a different shade of gray denotes a unique circle that was detected with imfindcircles.
However, the shades of gray are probably a bit ambiguous for certain coins as this blends into the background. Another way that we could visualize this is to apply a different colour map to the IDs array. We can try using the cool colour map, with the total number of colours to be the number of unique circles + 1 for the background. Therefore, we can do something like this:
cmap = cool(numel(radii) + 1);
RGB = ind2rgb(IDs, cmap);
imshow(RGB);
The above code will create a colour map such that each circle gets mapped to a unique colour in the cool colour map. The next line applies a mapping where each ID gets associated with a colour with ind2rgb and we finally show the image.
This is what we get:
Edit: the following solution is more adequate to scenarios where one does not require fitting the exact circumferences, although simple heuristics could be used to approximate the radii of the coins in the original image based on the centers found in the eroded one.
Assuming you have access to the Image Processing toolbox, try imerode on your original black and white image. It will apply an erosion morphological operator to your image. In fact, the Matlab webpage with the documentation of that function has an example strikingly similar to your problem/image and they use a disk structure.
Run the following code (based on the example linked above) assuming the image you submitted is called ima.jpg and is local to the code:
ima=imread('ima.jpg');
se = strel('disk',50);
eroded = imerode(ima,se);
imshow(eroded)
and you will see the image that follows as output. After you do this, you can use bwlabel to label the connected components and compute whatever properties you may want, for example, count the number of coins or detect their centers.

transformed image should always visible

I am trying to transform an image using Bi-linear interpolation, my input image is I, I have my affine matrix [A], which will give me transformed image I', according to bi-linear interpolation I am taking inverse of affine matrix inv([A]) and applying that to every point of output image(which is all zero at initial level), as we cant guarantee that output image size can be of any size, so first I found the bounds so I can get the size of the output image,
Now I have input image, Affine matrix, and output image which have atleast that size in which transformed image can be saved easily, But If I apply backward backward method of warping, according to that I have to iterate through every pixel of output image(which is zero right now), I want my transformed image at the center so my transformed image should always be visible, any idea how can I do that ?
Note I don't want to use matlab's built in function.
EDIT
If I transformed my A Image I got B, but You see corner of the image got cropped, I want those to be shown as well.
When rotating a rectangle from the upright position to a diagonal one, the vertical distance between the highest and lowest point will increase.
Now there are two approaches you can take:
Put the new picture in a bigger environment
OR
Rescale the rotated picture to make it fit in the original sized environment.

Efficient segment boundary marking after segmentation of an image

One can mark the boundary of a binary image by bwboundaries function of MATLAB.
What should be done for obtaining boundaries of all segments as a binary image?
I have segmented an image and want to know if there is a way to mark boundaries between each neighbouring segment without applying morphological operations on each segment.
I have added images to illustrate what i want to do. Actually i want to obtain a binary image that keeps pink boundary marker pixels between all segments. Thus, I can overlay them with original image by the help of imoverlay function of Steve Eddins.
Random colored labeling of segmentation result:
Roughly-marked pink boundaries between segments:
You can find the region boundaries using a range filter, which finds the intensity range within each pixel's neighborhood. This takes advantage of the fact that the label matrix only has non-zero range at the region boundaries.
im = imread('http://i.stack.imgur.com/qPiA3.png');
boundaries = rangefilt(im,ones(3)) > 0;
imoverlay(label2rgb(im),boundaries,[0 0 0]);
These edges are also two pixels wide. Actually, I think the edges have to be two pixels wide; otherwise the regions will "lose" pixels to the border non-uniformly.
Since erosion and dilation work on non-binary images as well, you can write
img = imread('http://i.stack.imgur.com/qPiA3.png');
ei = imerode(img,ones(3));
di = imdilate(img,ones(3));
boundaries = ei~=img | di~=img;
This results in a bw image that has a boundary at the edge of each colored region (thus, the boundary line will be two pixels wide).
Note that this will not return an ordered list of pixels as bwboundaries, but rather a logical mask like bwperim, which is what imoverlay needs as input.
As a round-about way, I thought of making use of edge function of MATLAB.
First, I need to apply something like a label2gray operation. labels is the segmentation output (first image provided in the question) in the code below.
grayLabels = mat2gray(255* double(labels) ./ double(max(labels(:)))); %label2gray
bw_boundaries = edge(grayLabels,0.001);