Find tunnel 'center line'?

前端 未结 3 1148
轻奢々
轻奢々 2020-12-23 23:40

I have some map files consisting of \'polylines\' (each line is just a list of vertices) representing tunnels, and I want to try and find the tunnel \'center line\' (shown,

相关标签:
3条回答
  • 2020-12-24 00:11

    This is a pretty classic skeletonization problem; there are lots of algorithms available. Some algorithms work in principle on outline contours, but since almost everyone uses them on images, I'm not sure how available such things will be. Anyway, if you can just plot and fill the sewer outlines and then use a skeletonization algorithm, you could get something close to the midline (within pixel resolution).

    Then you could walk along those lines and do a binary search with circles until you hit at least two separate line segments (three if you're at a branch point). The midpoint of the two spots you first hit, or the center of a circle touching the three points you first hit, is a good estimate of the center.

    0 讨论(0)
  • 2020-12-24 00:19

    An "algorithm" that works well with localized data changes.


    The critic's view

    The Good

    The nice part is that it uses a mixture of image processing and graph operations available in most libraries, may be parallelized easily, is reasonable fast, may be tuned to use a relatively small memory footprint and doesn't have to be recalculated outside the modified area if you store the intermediate results.

    The Bad

    I wrote "algorithm", in quotes, just because I developed it and surely is not robust enough to cope with pathological cases. If your graph has a lot of cycles you may end up with some phantom lines. More on this and examples later.

    And The Ugly

    The ugly part is that you need to be able to flood fill the map, which is not always possible. I posted a comment a few days ago asking if your graphs can be flood filled, but didn't receive an answer. So I decided to post it anyway.


    The Sketch

    The idea is:

    1. Use image processing to get a fine line of pixels representing the center path
    2. Partition the image in chunks commensurated to the tunnel thinnest passages
    3. At each partition, represent a point at the "center of mass" of the contained pixels
    4. Use those pixels to represent the Vertices of a Graph
    5. Add Edges to the Graph based on a "near neighbour" policy
    6. Remove spurious small cycles in the induced Graph
    7. End- The remaining Edges represent your desired path

    The parallelization opportunity arises from the fact that the partitions may be computed in standalone processes, and the resulting graph may be partitioned to find the small cycles that need to be removed. These factors also allow to reduce the memory needed by serializing instead of doing calcs in parallel, but I didn't go trough this.


    The Plot

    I'll no provide pseudocode, as the difficult part is just that not covered by your libraries. Instead of pseudocode I'll post the images resulting from the successive steps. I wrote the program in Mathematica, and I can post it if is of some service to you.

    A- Start with a nice flood filled tunnel image

    alt text

    B- Apply a Distance Transformation

    The Distance Transformation gives the distance transform of image, where the value of each pixel is replaced by its distance to the nearest background pixel.
    You can see that our desired path is the Local Maxima within the tunnel

    alt text

    C- Convolve the image with an appropriate kernel

    The selected kernel is a Laplacian-of-Gaussian kernel of pixel radius 2. It has the magic property of enhancing the gray level edges, as you can see below.

    alt text

    D- Cutoff gray levels and Binarize the image

    To get a nice view of the center line!

    alt text

    Comment

    Perhaps that is enough for you, as you ay know how to transform a thin line to an approximate piecewise segments sequence. As that is not the case for me, I continued this path to get the desired segments.

    E- Image Partition

    Here is when some advantages of the algorithm show up: you may start using parallel processing or decide to process each segment at a time. You may also compare the resulting segments with the previous run and re-use the previous results

    alt text

    F- Center of Mass detection

    All the white points in each sub-image are replaced by only one point at the center of mass
    XCM = (Σ i∈Points Xi)/NumPoints

    YCM = (Σ i∈Points Yi)/NumPoints

    The white pixels are difficult to see (asymptotically difficult with param "a" age), but there they are.

    alt text

    G- Graph setup from Vertices

    Form a Graph using the selected points as Vertex. Still no Edges.

    alt text

    H- select Candidate Edges

    Using the Euclidean Distance between points, select candidate edges. A cutoff is used to select an appropriate set of Edges. Here we are using 1.5 the subimagesize.

    As you can see the resulting Graph have a few small cycles that we are going to remove in the next step.

    alt text

    H- Remove Small Cycles

    Using a Cycle detection routine we remove the small cycles up to a certain length. The cutoff length depends on a few parms and you should figure it empirically for your graphs family

    alt text

    I- That's it!

    You can see that the resulting center line is shifted a little bit upwards. The reason is that I'm superimposing images of different type in Mathematica ... and I gave up trying to convince the program to do what I want :)

    alt text


    A Few Shots

    As I did the testing, I collected a few images. They are probably the most un-tunnelish things in the world, but my Tunnels-101 went astray.

    Anyway, here they are. Remember that I have a displacement of a few pixels upwards ...

    alt text

    HTH !

    .

    Update

    Just in case you have access to Mathematica 8 (I got it today) there is a new function Thinning. Just look:

    alt text

    0 讨论(0)
  • 2020-12-24 00:22

    Well in Python using package skimage it is an easy task as follows.

    import pylab as pl
    from skimage import morphology as mp
    
    tun = 1-pl.imread('tunnel.png')[...,0]        #your tunnel image
    skl = mp.medial_axis(tun)                     #skeleton
    
    pl.subplot(121)
    pl.imshow(tun,cmap=pl.cm.gray)
    pl.subplot(122)
    pl.imshow(skl,cmap=pl.cm.gray)
    pl.show()
    

    enter image description here

    0 讨论(0)
提交回复
热议问题