I'm doing image processing and mathematical morphology using scipy.ndimage and really enjoy it. Our work involves simulating charges moving through various films, and we're trying to use image analysis tools to estimate why different morphologies work better than others.
I quickly was able to use ndimage.label and distance_transform_edt to find the connected components and get sizing on them. I also implemented a breadth-first search to find minimal paths between the components and the edges, which represent electrodes.
Now, I'd like to determine "bottleneck" or "narrow channel" regions. I'm not even sure if I'm searching for the right keywords, since my expertise isn't really in image processing. I've given two examples below.. I want to find features like the red circles and count them and determine their size distributions. (Consider that charges will move more easily through wider bottlenecks.)
The problem is that I can't label these, since they're not independent components. The distance transforms give me small numbers at the edges.. I want something like the smallest distance through these bottlenecks.
Any advice where to look or general strategies?
One could use the medial axis transform to calculate the radius of a ball fit at each point in the bacl set to obtain the nooks in the image. In the following example we use the watershed of the distance function weighted by the distance function itself to obtain contours which separate minimas(the white components in the image). This thus gives a path weighted by the maximum value of the distance function separating 2 white components. I have done this in matlab but i think its easy to replicate the same in Scikit image tool box.
Image1:
Filling the holes since they aren't paths:
Distance function: (heat map)
Watershed of distance function (paths):
Watershed weighted by Distance function (final paths):
Image 2:
Distance function:
Watershed of distance function (paths):
Watershed weighted by Distance function (final paths):
Thus as demonstrated we have calculated technical a skeleton by zone of influence(SKIZ) using the watershed of the distance function(cityblock used here). One has to also note that the holes on the borders are not filled since the imfill ignores holes on borders. If its to be filled one can add a frame around so that one can use imfill to fill these later.
Related
I want to separate a noiseless 1-bit (black and white) image with white circles based on the concave part of the outline.
Please refer to the picture below.
This is the white object to separate:
The target result is:
Here is my implementation with the watershed algorithm:
The above result is not what I want.
If the size of the separated objects is similar, my algorithm is fine, but if the size difference is large, a problem occurs as shown in the picture above.
I would like to implement an opencv algorithm that can segment a region like the second picture.
However, the input photo is not necessarily a perfect circle.
It can be oval like the picture below:
Or it can be squished:
However, I would like to separate it based on the concave part of the outline anyway.
I think it can be implemented by using the distanceTransform function well, but I'm not sure how to approach it.
Please let me know which way to refer.
Thank you.
Here is an algorithm which should give you a good start.
Compute all contours.
For each contour compute the convexity defects. If there is no defect the contour is an isolated circle and you can segment it out.
After you handled all the isolated circles, you can work out the remaining contours by counting the convexity defects: the number of circles N for each contour is the number of convexity defects divided by 2.
Use a clustering algorithm (https://scikit-learn.org/stable/modules/generated/sklearn.mixture.GaussianMixture.html should do well given the shapes you have) and cluster the "white" points using N as the number of clusters to be found.
If you want to find the minimal openings, you can use a medial axis based approach.
Pseudo code:
compute contours of bitmap
compute medial-axis of bitmap
for each point on medial-axis:
get minimal distance d from medial axis algorithm
for each local minimum of distance d:
get two points on bitmap contours with minimal distance that are at least d apart from each other
use these points for deviding line
If you need a working implementation in python, please let me know. I would use skimage lib. For other languages you might have to implement medial-axis on your own. But that shouldn't be a big deal.
I have vector graphics. (In my first case, it's the epigraph of a function whose formula is given. So it is a shape whose outline is given by a parametric curve.)
I want to rasterize this image with anti-aliasing. So I want raster graphics, i.e. a numpy array. I want to obtain this array in a low-level way, avoiding libraries that are meant for object-oriented interactive GUI visualizations with plot axes, etc.. I just want an array. The only problem with doing something like Y,X=np.ogrid(...) and then picture = Y>f(X) is that that's not anti-aliased. (Note that blurring that binary picture is worse than a good dedicated anti-aliasing algorithm.) How to rasterize with anti-aliasing in Python without any overkill GUI-centered libraries?
If the curve is given by an implicit equation F(x,y)=0, evaluate the value of the function at the four corners of every pixel. If the signs are the same, the pixel is wholly outside or inside. If the signs vary, the area inside the polygon formed by the corners and the points along the edges where the function vanishes (find these by a mere linear interpolation) tells you the mixture of background and foreground colors (alpha blending coefficient).
Tracing the polygon isn't that difficult: traverse the four edges of the square and keep the positive vertices and zero points in the order you meet them. You will get from a triangle to an hexagon. The area is obtained by the shoelace formula.
The case of a parametric function is a little harder. You need to find the intersections of the curve with the grid lines, and perform the area estimation in all cells that are traversed. For this, draw the curve as a polyline (this is called flattening), and slice the polyline with horizontals, then verticals.
Manim might be able to rasterize epigraphs and parametric curves well and fast. Its community edition seems actively maintained.
Edits/comments with details are welcome.
I have been trying to create custom regions for states. I want to fill the state map by using area of influence of points.
The below image represents what I have been trying. The left image shows the points and I just want to fill all the areas as in the right image. I have used Voronoi/Thiesen, but it leaves some points outside the area since it just takes the centroid to color the polygon.
Is there any algorithm or process to achieve that?, now I am using in Python.
You've identified your basic problem: you used a cluster-unit Voronoi algorithm, which is too simplistic for your application. You need to apply that same algebra to the points themselves, not to the region as a single-statistic entity.
To this end, I strongly recommend a multi-class SVM (Support Vector Machine) algorithm, which will identify the largest gaps between identified regions (classes) of points. Use a Gaussian kernel modification (of a very low degree) to handle non-linear boundaries. You will almost certainly get simple curves instead of lines.
I know how to do basic Canny edge detection using OpenCV. However I need to discard all edges that do not fall within 15 degrees of a predetermined angle.
Any help would be greatly appreciated.
Its an old question but here is the process you should use.
1]Start by filter your source image (back-ground subtract/color/etc)
2]Apply a generic Edge detector or a steerable filter or (if you want to get some really good result & are doing it for research purposes look for Phase Strectch Transform Algorithm
3]Save those line in a vector/whatever
4]Create a circle drawing algorithm (here is the main idea)
Your circle drawing algorithm (CDA further) will take every point returned by your edge filter.
For each point it will build circles of a variable diameter [Dmin;Dmax] based on the max/min distance you can accept for two points be considered on the same line.
If no next-pixel are present in the circle octant corresponding to your angle, simply dismiss it.
Once you have your lines that match your angle you can sort them by length to dismiss line probably due to noise.
You should also note that there is other methods, this method as some good aspect:
1- Its robust against noise & low quality images/video
2- Its CUDA compliant (i.e. easy to push in parallel processing).
3-Its fast and roughly more accurate than most basic line detectors.
Given a contour outlining the edge of the letter S (in comic sans for example), how can I get a series of points along the spine of this letter in order to later represent this shape using lines, cubic spline or other curve-representing technique? I want to process and represent the shape using 30-40 points in Python/OpenCV.
Morphological skeletonization could help with this but the operation always seems to produce erroneous branches. Is there a better way to collapse the contour into just the 'S' shape of the letter?
In the example below you can see the erroneous 'serpent's tongue' like branches that are produced by morphological skeletonization. I don't know if it's fair to say they are erroneous if that's what the algorithm is supposed to be doing, but for me I would not like them to be there.
Below is the comic sans alphabet:
Another problem with skeletonization is that it is computationally expensive, but if you know a way of making it robust to forming 'serpent's tongue' like branches then I will give it a try.
Actually vectorizing fonts isn't trivial problem and quite tricky. To properly vectorize fonts using bezier curve you'll need tracing. There are many library you can use for tracing image, for example Potrace. I'm not knowledgeable using python but based on my experience, I have done similar project using c++ described below:
A. Fit the contour using cubic bezier
This method is quite simple although a lot of work should be done. I believe this also works well if you want to fit skeletons obtained from thinning.
Find contour/edge of the object, you can use OpenCV function findContours()
The entire shape can't be represented using a single cubic bezier, so divide them to several segments using Ramer-Douglas-Peucker (RDP). The important thing in this step, don't delete any points, use RDP only to segment the points. See colored segments on image below.
For each segments, where S is a set of n points S = (s0, s1,...Sn), fit a cubic bezier using Least Square Fitting
Illustration of least square fitting:
B. Resolution Resolution Independent Curve Rendering
This method as described in this paper is quite complex but one of the best algorithms available to display vector fonts:
Find contour (the same with method A)
Use RDP, differently from method A, use RDP to remove points so the contour can be simplified.
Do delaunay triangulation.
Draw bezier curve on the outer edges using method described in the paper
The following simple idea might be usefull.
Calculate Medial axis of the outer contour. This would ensure connectivity of the curves.
Find out the branch points. Depending on its length you can delete them in order to eliminate "serpent's tongue" problem.
Hope it helps.