Search code examples
pythonimageopencvimage-processingscikit-image

How to convert curves in images to lines in Python?


I am new to image processing and am working with images like these:

Curved image

In these pictures, there will be more than one curves that I need to straighten out for them to look like a straight line.


Solution

  • Here's a quick solution. It can be improved by doing a spline fit to the features rather than just fitting the parabola. The algorithm shifts each row in the image individually according to the fitted parabola:

    from skimage import io, measure, morphology
    from matplotlib import pyplot as plt
    from scipy.optimize import curve_fit
    
    image = io.imread('curves.png', as_gray=True)
    # need a binary mask of features
    mask = image == image.min()
    # close holes in features
    mask = morphology.binary_closing(mask, morphology.square(3))
    
    plt.matshow(mask, cmap='gray')
    
    # need to get the coordinates of each feature
    rp = measure.regionprops(measure.label(mask))
    
    # going to fit a parabola to the features
    def parabola(x, x0, A, y0):
        return A*(x-x0)**2 + y0
    
    # get coords of one of the features
    coords = rp[0].coords
    # do parabola fit
    pop, pcov = curve_fit(parabola, coords[:,0], coords[:,1])
    # generate fit
    fit = parabola(np.arange(mask.shape[0]), *pop)
    # plot fit
    plt.plot(fit, np.arange(mask.shape[0])) # invert axes
    
    # generate new image to shift
    out = np.empty_like(image)
    # shift each row individually and add to out array
    for i, row in enumerate(image):
        out[i] = np.roll(row, -int(round(fit[i] - pop[-1])))
    
    plt.matshow(out, cmap='gray')
    

    Original mask and fitted parabola:

    mask and fit

    Result:

    result