Consider that I have a colored image like this in which the outline is not complete (There are gaps between lines). I want to be able to fill the area between the lines with one color or another. This actually is a binary image which I got after applying canny edge detector on a corresponding gray scale image.
I tried first dilating the image and then eroding it, but the result is not good enough. I want to be able to preserve the thickness of the root
Any help would be greatly appreciated
Original Image
Image after edge detection and some manual removal of pixels
Using the information in the edge image, I thought I would try to extract pixels from the original image of a certain color. For every white pixel in the edited image, I used a search space in the original image along the same horizontal line. I used different thresholds for R, G and B and I ended up with this
I'm not sure what your original image looks like. It would be helpful to see.
You have gaps between the lines because a line in your original image has two edges, one on each side. The canny algorithm is detecting them both. The Canny edge detection algorithm has at its heart the application of two Sobel kernels to calculate the gradient, one for detecting horizontal edges and one for detection vertical edges.
-1 0 +1
-2 0 +2
-1 0 +1
and
+1 +2 +1
0 0 0
-1 -2 -1
These kernels will present peaks for both sides of the line. One peak positive and one negative. You can exclude one side of the line by excluding the corresponding peak. After taking the gradient of each direction truncate any values below zero (set the values to zero) to remove the second peak. Then continue with the Canny edge detection as usual. This will result in the detection of only a single edge for each line instead of the two that you are seeing now.
I'll add a third approach now that I have seen the image. It looks like most of the information is in the green channel.
Green channel image
This image gives you a decent result if you simply apply a threshold.
Thresholded image with a somewhat arbitrary threshold
You can then either clean this image up by itself or use your edge image. To clean it up with the edge image you produced remove any white pixels that are more than a certain distance from one of your detected edges (create a Euclidean distance map from your edge image and use that to set any white pixels greater than a certain distance from an edge to black).
If you are still collecting images you may want to try to position the camera in a way to avoid the bottom of the jar (or whatever this is).
You could attempt to use a line scanning methodology. Start at the side and scan horizontally. When you hit an edge you assume you are in a root and you start setting the voxels to white. When you hit another edge you assume you are leaving a root and you start. There will be some fringe cases and you may want to add additional checks, such as limiting the allowed thickness of a root.
You could also do a flood fill style algorithm where you take a seed point in a root and travel up the root filling it in.
Not sure how well these would work as it depends on the image and I did not test it.
Related
My image is something like below:
I want to be able to draw 2 layers: (1) red line on top of 1st layer, but (2) blue line in the middle of 2nd layer
I am using OpenCV. but any languages/advice are welcomed.
You can do the following:
Small closing in order to reconnect the small separated components/patterns.
Small opening in order to remove the small isolated components/patterns.
Skeletonize (or median axis)
Pruning in order to remove the small branches.
You will then get a skeleton for each pattern. It will be close to the lines you want to draw. But it will be a little bit irregular, so you can interpolate it.
[EDIT] if you need the red line on top of the edge, a solution is to:
Extract the pattern contour
Keep only the pixel on top.
Algorithmically, it can be achieved doing this: for each X coordinate on the top border, go down the image vertically until you meet the first non-null pixel. If your image is NxM, you must have N pixels in your solution.
If you want to regularize/smooth the result, you have two solutions:
Transform the contour as a parametric function and smooth it.
Do an interpolation (spline?)
I have a small problem in smoothing a line surface.
The image is a result of edge detection after sobel processing.
It has an uneven surface, and the unit of bulges is one pixel.
Red circle parts are the bulges.
http://www.mathworks.com/help/matlab/creating_plots/smooth-contour-data-with-convolution-filter.html
The link I have tried, but the line width was increased too more.
I have to get a straight line with one pixel width.
How to clear up these bulges?
Many Thanks.
7/21 update:
Canny method can generate a detected image with one pixel.
The result of Canny edge detection:
The line was segmented 2 parts, the under part was shifted by one pixel.
I hope the line that can be considered a straight line rather than 2 lines when the line width is within 2~3 pixel.
With Dilate and Erosion, I tried to smooth the line that become a straight line
Canny > Dilate:
Canny > Dilate > Erosion:
The result of before and after are the same...
Could anyone give me an idea?
Many Thanks again.
If you are working with a simple 2-D, black-and-white image, stored as a 0/1 array, and you guarantee there will always be a straight line all the way from top to bottom, then this may help -
% recreate scenario
A = zeros(100,50);
A(:,25) = 1;
A([30:40,80:85],24)=1;
A([20:35,70:90],26)=1;
% a rude way
S = sum(A,1);
B = repmat(S==max(S),100,1);
imshow(B)
Maybe an approach similar to Canny edge detection could be the solution you are searching for. The Canny edge detector uses non maximum suppression, meaning that the edges are formed only by pixels that have the maximum gradient between their neighbours, resulting in many occasions in one-pixel-width edges.
I'm working on a fingerprint recognition project but I need to pre-process the image. I go through the following process.
1) Binarization
2) Filtering to removing the "stair-step" effect; i.e smoothing
3) Thin the lines
I'm adding in a step that I'm trying to develop that will fill in any holes that are left after thinning. I'm trying to accomplish this as follows.
4a) Use bwlabel to find regions (I might consider using bwmorp(...,'shrink') to just leave the "blobs" but doing this reduces the size of the blob a little).
4b) Find all regions that do not have the maximum area
4c) Use the location of these regions to shrink these "blobs" to points.
But how can I apply shrink at specified locations?
Binarization
Filtering
Thinning
Hole filling
I am Not sure if I understood the question correctly. But can you take complement of the thinned image and then use bwlabel. After that, count the number of pixels belonging to each label. Apply your criteria to select labels and get their locations. After that, you can use imfill(bw,locations) command.
If you have a region you want to shrink to a point then calculate the center of mass for the region. Do this by just averaging the x and y coordinates of each point in the blob. Set the region pixels to black and the center of mass to white.
The problem that I am having is trimming off the ridges to just leave the filled areas while avoiding erosion of the filled areas (if I were to use erode the ridges would disappear but also reduce the size of the area).
You don't really have to worry about erosion of the small regions as it will have little impact on the center of mass, and you point will still end up going to an appropriate location.
I have a image which looks like this:
The (blue) background have the value zero, the the (red) ring has a "large" value (compared to the rest of the image). I want to plot only the orange part of the sample. However, due to the finite resolution of the image the edges still appear as show here:
As you can see specially the white regions (yes there are a few) above are hard to see due to all the noise from edges.
Is there a good algorithm (preferable in matlab) which can help me clean up these images?
Find the binary mask for the ring
Dilate the mask a bit using imdilate and strel
Use the inverted mask to 'and out' the ring and the region around it
I want to detect the edge only in the red marked region as shown in the image below:
A few suggestions. I assume that the red region is input by mouse and that you now have a mask of the region that you want to include in the edge search.
My proposed algorithm
1. Do Edge detection
2. Write your own Hough routine but only count edges if they should be included according to the mask.
3. Pick the edge with the best score in the Hough space.
Of course you don't need to run the edge detection on the complete image but if you don't make sure that you handle the border of your search area (so you don't get edges there). Simply mirroring the area might work.
Update
Okay, different approach:
Use the hough routines in matlab. houghlines, hough, houghpeaks are the relevant functions. If only one line intersects your region of interest, you are done. The line is the result you want.
If more than one line intersect the region of interest, you need to do a bit more. I'd suggest counting the number of pixels along the line that are within the ROI. So, if the line intersects the ROI for 10 pixels, that line's score is 10. Do this for all lines and then pick the line with the highest score.
Note that none of the approaches are optimized for speed. However, they are easy to understand.