简体   繁体   中英

Fit a smooth curve in binary image

I want to fit a smooth line in a binary image.

This image is the result of preprocessing using contrast, contour, skeleton, nearest neighbor, contour separation, etc. Initial image

I thought fitting a curve will be very easier once I will get an array(x,y) of white dots. But when I try to fit a curve in this image, a zigzag line appears due to the multiple values at a certain x. I need a generalized solution to my problem. My image can vary (I am making an app). It can have 4-5 values for a particular x or vice-versa.

Methods I tried:

  1. ConvexHull image by convex hull(image is not smooth)

  1. Nearest neighbor connection. (image is not smooth)

  2. scipy interpolate (zig-zag line appear due to multiple y @x)

  3. matplotlib spline curve

Suggest me how to fit a smooth curve in such images.

I understand the question to mean that you want to find the curve through the data as a list of x and y coordinates.

Pick a point to start, for example, where there is a high density of points at along side or edge of the graph.

Find the median to one side or the other, exclude fliers and find the mean. Move over, and do it again.

For a region with two lines, you might limit the range of points considered in the median to those within some range of the current or previous point.

The median will avoid overweighting for distant points, and will tend to pull strongly towards the center of the data at that point in x (or y, if you like).

The mean often has a stronger relationship to a physical theory or model that you might be examining.

You can repeat this for different clusters of data points, to find all of the lines.

Finally compare over all of the curves and prune the duplicates, as detected for example by sum of square differences.

This might be of some use, I cannot say for sure because I do not know characteristics of all your target images.

  1. Convert image to grayscale
  2. Apply erosion to your image for some number of steps based on a stopping criteria that you define (based on some metric like connected components, may be)

Check OpenCV library for relevant API calls in the morphological transformation section.

Here is a sample of applying erosion on your image for a few steps.

在此输入图像描述

This can be solved by using following steps and code is provided below:

  1. First connect all the nearest neighbour points. This will provide array in the way curve or graph is progressing.

  2. Then use univariateSpline smoothing to make your curve smooth.

Problem Resolved - The zigzag line will become smooth according to the curve.

Code to connect all the nearest neighbour:

def distance(P1, P2):
    return ((P1[0] - P2[0])**2 + (P1[1] - P2[1])**2) ** 0.5

def optimized_path(coords, start=None):
    if start is None:
        start = coords[0]
    pass_by = coords
    path_connected = [start]
    pass_by.remove(start)
    while pass_by:
        nearest = min(pass_by, key=lambda x: distance(path_connected[-1], x))
        path_connected.append(nearest)
        pass_by.remove(nearest)
    return path_connected

start = None
    points=[[i,j] for i,j in zip(x_data,y_data)]
    points = optimized_path(points,start)

Code to smooth the nearest neighbour points:

# Smoothing
distance_smooth = np.cumsum( np.sqrt(np.sum( np.diff(points, axis=0)**2, axis=1 )) )
distance_smooth = np.insert(distance_smooth, 0, 0)/distance_smooth[-1]
splines = [UnivariateSpline(distance_smooth, coords, k=5, s=None) for coords in points.T]
alpha = np.linspace(0, 1, 75)
points_fitted = np.vstack( spl(alpha) for spl in splines ).T

This is the final image- Smooth Image

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM