Hello I'm going to do text detection on circular images.
After some preprocessing I do polar to cartesian transformation on images
this is example of my real image
after doing p2c transformation my images become like
but since my images come in a different angles sometimes p2c transformation cut out my characters
I think I need to do proper rotation before p2c transformation.
my question is what kind of rotation method is proper for this situation? or should I start p2c transformation based on histogram values ? or what kind of other ways would you guys suggest me?
thanks
I suggest you do your polar to cartesian transformation and analyse your resulting image X. You can find you letters by summing all values along the x dimension and using a threshold to detect if there is a letter or not:
y = sum(X,1);
th = (max(y) + min(y)) / 2;
letters = y < th;
Now you can find out if there is a letter at the border of the image and shift the image if this is the case.
if sum(letters([1:10,end-10:end]))
X = circshift(X,[0,10]);
end
Of course you can't be sure that there is no letter at the border now, so better loop this procedure until no letter is found at the border.
Related
I was wondering if anyone knows which kind of filter is applied by SPCImage from the Becker & Hickl system.
I am taking some FLIM data with my system and I want to create the lifetime images. For doing so I want to bin my images in the same way as it does SPCImage, so I can increase my SN ratio. The binning goes like 1x1, 3x3, 5x5, etc. I have created the function for doing a 3x3 binning, but each time it gets more complicated...
I want to do it in MATLAB, and maybe there is already a function that can help me with this.
Many thanks for your help.
This question is old, but for anyone else wondering: You want to sum the pixels in an (2M+1) x (2M+1) neighborhood for each plane (M integer). So I am pretty sure you can go about the problem by treating it like a convolution.
#This is your original 3D SDT image
#I assume that you have ordered the image with spatial dimensions along the
#first and second and the time channels are the third dimension.
img = ... #<- your 3D image goes here
#This describes your filter. M=1 means take 1 a one pixel rect around your
#center pixel and add the values to your center, etc... (i.e. M=1 equals a
#total of 3x3 pixels accumulated)
M=2
#this is the (2D) filter for your convolution
filtr = ones(2*M+1, 2*M+1);
#the resulting binned image (3D)
img_binned = convn(img, filtr, 'same');
You should definitely check the result against your calculation, but it should do the trick.
I think that you need to test/investigate image filter functions to apply to this king of images Fluorescence-lifetime imaging microscopy.
A median filter as showing here is good for smoothering things. Or a weihgted moving average filter where applied to the image erase de bright spots and only are maintained the broad features
So you need to review of the digital image processing in matlab
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.
What we want is to draw several solid circles at random locations, with random gray scale colors, on a dark gray background. How can we do this? Also, if the circles overlap, we need them to change color in the overlapping part.
Since this is an assignment for school, we are not looking for ready-made answers, but for a guide which tools to use in MATLAB!
Here's a checklist of things I would investigate if you want to do this properly:
Figure out how to draw circles in MATLAB. Because you don't have the Image Processing Toolbox (see comments), you will probably have to make a function yourself. I'll give you some starter code:
function [xout, yout] = circle(x,y,r,rows,cols)
[X,Y] = meshgrid(x-r:x+r, y-r:y+r);
ind = find(X.^2 + Y.^2 <= r^2 & X >= 1 & X <= cols & Y >= 1 & Y <= rows);
xout = X(ind);
yout = Y(ind);
end
What the above function does is that it takes in an (x,y) co-ordinate as well as the radius of
the circle. You also will need to specify how many rows and how many columns you want in your image. The reason why is because this function will prevent giving you co-ordinates that are out of bounds in the image that you can't draw. The final output of this will give you co-ordinates of all values inside and along the boundary of the circle. These co-ordinates will already be in integer so there's no need for any rounding and such things. In addition, these will perfectly fit when you're assigning these co-ordinates to locations in your image. One caveat to note is that the co-ordinates assume an inverted Cartesian. This means that the top left corner is the origin (0,0). x values increase from left to right, and y values increase from top to bottom. You'll need to keep this convention in mind when drawing circles in your image.
Take a look at the rand class of functions. rand will generate random values for you and so you can use these to generate a random set of co-ordinates - each of these co-ordinates can thus serve as your centre. In addition, you can use this class of functions to help you figure out how big you want your circles and also what shade of gray you want your circles to be.
Take a look at set operations (logical AND, logical OR) etc. You can use a logical AND to find any circles that are intersecting with each other. When you find these areas, you can fill each of these areas with a different shade of gray. Again, the rand functions will also be of use here.
As such, here is a (possible) algorithm to help you do this:
Take a matrix of whatever size you want, and initialize all of the elements to dark gray. Perhaps an intensity of 32 may work.
Generate a random set of (x,y) co-ordinates, a random set of radii and a random set of intensity values for each circle.
For each pair of circles, check to see if there are any co-ordinates that intersect with each other. If there are such co-ordinates, generate a random shade of gray and fill in these co-ordinates with this new shade of gray. A possible way to do this would be to take each set of co-ordinates of the two circles and draw them on separate temporary images. You would then use the logical AND operator to find where the circles intersect.
Now that you have your circles, you can plot them all. Take a look at how plot works with plotting matrices. That way you don't have to loop through all of the circles as it'll be inefficient.
Good luck!
Let's get you home, shall we? Now this stays away from the Image Processing Toolbox functions, so hopefully these must work for you too.
Code
%%// Paramters
numc = 5;
graph_size = [300 300];
max_r = 100;
r_arr = randperm(max_r/2,numc)+max_r/2
cpts = [randperm(graph_size(1)-max_r,numc)' randperm(graph_size(2)-max_r,numc)']
color1 = randperm(155,numc)+100
prev = zeros(graph_size(1),graph_size(2));
for k = 1:numc
r = r_arr(k);
curr = zeros(graph_size(1),graph_size(2));
curr(cpts(k,1):cpts(k,1)+r-1,cpts(k,2):cpts(k,2)+r-1)= color1(k)*imcircle(r);
common_blob = prev & curr;
curr = prev + curr;
curr(common_blob) = min(color1(1),color1(2))-50;
prev = curr;
end
figure,imagesc(curr), colormap gray
%// Please note that the code uses a MATLAB file-exchange tool called
%// imcircle, which is available at -
%// http://www.mathworks.com/matlabcentral/fileexchange/128-imcircle
Screenshot of a sample run
As you said that your problem is an assignment for school I will therefore not tell you exactly how to do it but what you should look at.
you should be familiar how 2d arrays (matrices) work and how to plot them using image/imagesc/imshow ;
you should look at the strel function ;
you should look at the rand/randn function;
such concepts should be enough for the assignment.
I want an approach and method to separate the connected lines. Here is my image
and here is the result I would like
How do I solve that problem? Thank you in advance!
Sincerely
The watershed would be a problem as you have shown it produces multiple segmentations of the original line. Originally the watershed works for grains due to their convex shapes, while here in the case of lines there is no global convex shape to cause a good fragmentation, it would be good to use the watershed with some constraints.
It would be good to try solving a simpler version of the problem. Imagine that there are only horizontal and vertical lines possible. So in this case it would mean separating the horizontal long lines by cutting the short vertical lines (length measured by projecting on the x-y gradient). The basic hint is to use the gradient/slope of these lines to help decide where to cut - orthogonal line. In the more general case the problem requires a measure of local curvature or geodesic distance.
A simpler solution(in edit) is just removing the junction points in the skeleton you have.
This would cause some of your lines which are connected horizontally to be segmented but i guess this can be fixed with some end point filtering. A simple try here:
J = imread('input.png');
B = bwmorph(J,'branchpoints');
L = bwlabel((J>0).*(~B),8); %removing the branch points from the skeleton
Label = label2rgb(bwlabel((J>0).*(~B),8),'jet',[0 0 0]);
Final labeled line components. This requires further end point prefiltering, direction based filtering.
The parts of the contour that should be separated are basically the sections that are not in the same direction as most of the rest of the contour.
I can only give you a basic way to do this without specific code or functions and I doubt it is the most efficient, but since there are not too many answers here...also this is using the knowledge of the problem and the solution...
Find the connected contour with all its branches as a set of pixel coordinates (which represent the line as a single pixel wide contour)
Convert the contour list to a set of angles between each adjacent pixel coordinate
Optional: Filter out the high frequency components with an averaging filter
Histogram the angles to find the angle most of the contour lines lay on (call it the common angle)
Search the contour looking for sections that go from +/-common angle (tolerance of +/-30 degrees) to the negative of that (-/+ common angle with similar tolerance).
For each section delete the pixels associated with angles between the two thresholds above (i.e. common angle + 30 deg to -common angle - 30 degrees.
Repeat for each connected contour
Hope this helps some
I have a set of points which I want to propagate on to the edge of shape boundary defined by a binary image. The shape boundary is defined by a 1px wide white edge.
I have the coordinates of these points stored in a 2 row by n column matrix. The shape forms a concave boundary with no holes within itself made of around 2500 points. I have approximately 80 to 150 points that I wish to propagate on the shape boundary.
I want to cast a ray from each point from the set of points in an orthogonal direction and detect at which point it intersects the shape boundary at. The orthogonal direction has already been determined. For the required purposes it is calculated taking the normal of the contour calculated for point, using point-1 and point+1.
What would be the best method to do this?
Are there some sort of ray tracing algorithms that could be used?
Thank you very much in advance for any help!
EDIT: I have tried to make the question much clearer and added a image describing the problem. In the image the grey line represents the shape contour, the red dots the points
I want to propagate and the green line an imaginary orthongally cast ray.
alt text http://img504.imageshack.us/img504/3107/orth.png
ANOTHER EDIT: For clarification I have posted the code used to calculate the normals for each point. Where the xt and yt are vectors storing the coordinates for each point. After calculating the normal value it can be propagated by using the linspace function and the requested length of the orthogonal line.
%#derivaties of contour
dx=[xt(2)-xt(1) (xt(3:end)-xt(1:end-2))/2 xt(end)-xt(end-1)];
dy=[yt(2)-yt(1) (yt(3:end)-yt(1:end-2))/2 yt(end)-yt(end-1)];
%#normals of contourpoints
l=sqrt(dx.^2+dy.^2);
nx = -dy./l;
ny = dx./l;
normals = [nx,ny];
It depends on how many unit vectors you want to test against one shape. If you have one shape and many tests, the easiest thing to do is probably to convert your shape coordinates to polar coordinates which implicitly represent your solution already. This may not be a very effective solution however if you have different shapes and only a few tests for every shape.
Update based on the edited question:
If the rays can start from arbitrary points, not only from the origin, you have to test against all the points. This can be done easily by transforming your shape boundary such that your ray to test starts in the origin in either coordinate direction (positive x in my example code)
% vector of shape boundary points (assumed to be image coordinates, i.e. integers)
shapeBoundary = [xs, ys];
% define the start point and direction you want to test
startPoint = [xsp, ysp];
testVector = unit([xv, yv]);
% now transform the shape boundary
shapeBoundaryTrans(:,1) = shapeBoundary(:,1)-startPoint(1);
shapeBoundaryTrans(:,2) = shapeBoundary(:,2)-startPoint(2);
rotMatrix = [testVector(2), testVector(1); ...
testVector(-1), testVector(2)];
% somewhat strange transformation to keep it vectorized
shapeBoundaryTrans = shapeBoundaryTrans * rotMatrix';
% now the test is easy: find the points close to the positive x-axis
selector = (abs(shapeBoundaryTrans(:,2)) < 0.5) & (shapeBoundaryTrans(:,1) > 0);
shapeBoundaryTrans(:,2) = 1:size(shapeBoundaryTrans, 1)';
shapeBoundaryReduced = shapeBoundaryTrans(selector, :);
if (isempty(shapeBoundaryReduced))
[dummy, idx] = min(shapeBoundaryReduced(:, 1));
collIdx = shapeBoundaryReduced(idx, 2);
% you have a collision with point collIdx of your shapeBoundary
else
% no collision
end
This could be done in a nicer way probably, but you get the idea...
If I understand your problem correctly (project each point onto the closest point of the shape boundary), you can
use sub2ind to convert the "2 row by n column matrix" description to a BW image with white pixels, something like
myimage=zeros(imagesize);
myimage(imagesize, x_coords, y_coords) = 1
use imfill to fill the outside of the boundary
run [D,L] = bwdist(BW) on the resulting image, and just read the answers from L.
Should be fairly straightforward.