espdev / scikit-mpe

Minimal path extraction using the fast marching method
https://scikit-mpe.readthedocs.io
MIT License
17 stars 1 forks source link

EndPointNotReachedError #8

Closed franva closed 2 years ago

franva commented 3 years ago

Hi @espdev ,

I hope you had a good weekend :)

I'm trying to use the mpe to find a path, but received an error message which I cannot understand why it happens. To my eyes, the entry and exist points have been provided and all edges are well sealed so leaky side, it should find the path, but the error happens. I did notice that the left bottom corner misses a bit black edge, so I have manually painted black edge on that part to "seal" the edge and still the error happens.

Could you please help?

Many thanks,

here is the image cv2

Here is the code

from skimage.io import imread
from skmpe import parameters, mpe, OdeSolverMethod
from skimage.exposure import rescale_intensity

start_p, end_p = [0, 126], [415, 0]
test_img = imread('cv2.jpg', as_gray=True)

speed_image = rescale_intensity(test_img, out_range=(0.005, 1.0))

with parameters(ode_solver_method=OdeSolverMethod.LSODA, integrate_max_step=1.0):
    path_info = mpe(speed_image, start_point, end_point)

path = path_info.path

I received this error message:

EndPointNotReachedError: The extracted path from the start point (0, 126) did not reach the end point (415, 0) in 1.2363352244019011e-05 time and 100 _step_count with distance 433.71 to the end point. Reason: the distance between old and current point stay too small for 100 _step_count

espdev commented 3 years ago

@franva hello!

You can try to increase the thickness of the walls, using dilation morphological operation.

See for example:

from skimage.io import imread
from skimage.util import invert
from skimage.morphology import dilation, square
from skimage.exposure import rescale_intensity

from skmpe import parameters, mpe, OdeSolverMethod, EndPointNotReachedError

import numpy as np
from matplotlib import pyplot as plt

start_point = [126, 0]
end_point = [0, 415]

image_fname = '117558049-dd6a3f00-b0bc-11eb-8f87-d0183019b523.png'

image = imread(image_fname, as_gray=True)

# Preprocessing
image = invert(dilation(invert(image), selem=square(5))).astype(np.float_)
image = rescale_intensity(image, out_range=(0.001, 1.0))

try:
    with parameters(ode_solver_method=OdeSolverMethod.RK23,
                    integrate_time_bound=10000,
                    ):
        path_info = mpe(image, start_point, end_point)
except EndPointNotReachedError as err:
    print(f'ERROR: {err}')
    path = np.array(err.extracted_points)
else:
    path = path_info.path

plt.imshow(image, cmap='gray')
plt.plot(path[:, 1], path[:, 0], '-r')
plt.plot(*start_point[::-1], 'oy')
plt.plot(*end_point[::-1], 'og')
plt.show()

2021-05-10_01-25-29

espdev commented 3 years ago

Also you can use additional preprocessing with noise and blur to make more natural speed image and smoothed path:

from skimage.io import imread
from skimage.exposure import rescale_intensity
from skimage.morphology import dilation, square
from skimage.util import invert, random_noise
from skimage.filters import gaussian

...

# Preprocessing
image = invert(dilation(invert(image), selem=square(9))).astype(np.float_)
image = rescale_intensity(image, out_range=(0.0, 1.0))
wall = image < 0.5
image = random_noise(image, var=0.08, clip=True, seed=12345)
image[wall] = 0.0
image = gaussian(image, sigma=1.0)
...

2021-05-10_01-54-30

Show the path on the original image:

2021-05-10_01-59-43

franva commented 3 years ago

Hi @espdev thank you very much for your help.

I followed your suggestions and did get the maze path eventually. Thanks.

I have a few questions, appreciated if you could answer:

  1. Why do I need to swap the x,y of start and end points? whereas I do not need to do the same on the path points
  2. Why did you change the LSODA to RK23? what are the rules to follow when you are picking up an algorithm for a maze?
  3. What does integrate_time_bound mean? I did read the document which says Integration time bound. But for a beginner, I do not really know what it means.
  4. What are the differences between using reconstruction from SK-Image to do erosion and dilation comparing to the cv2.erode() and cv2.dilate()? To me, it seems that reconstruction needs a seed and has better effect for extracting maze out of the original camera pictures, but I do not understand why it works better than cv2's methods.
  5. (Sorry man, I know Q5 should not be asked here, but I cannot find the answer anywhere else, so please ignore it if this is not what you are interested in) I have 4 photos to test my code which locates and extracts the maze from a camera photo and find a path. Every time, when I finally made the code work for one picture, then I will find that the exactly same piece of code does not work for another photos.....I have been tweaking parameters for at least 3 weeks without a luck of finding a particular set of parameters which work across all 4 photos. I am a bit disappointed(coz I thought Image Processing is enough powerful to deal with these particular use case) Thus, may I conclude that by only using Image Processing, it is not enough to do what I want to do? Or do I have to use AI to locate and extract a maze?

I guess you might be interested in how to find out the start and exit points on a maze, here is my SOF post which has the answer: https://stackoverflow.com/questions/67326524/how-to-find-out-the-locations-of-entry-and-exit-from-a-maze-picture#answer-67335914

For any chance, if you were interested, please see my 4 photos here.

hard maze middle simple