{"id":396,"date":"2011-11-26T16:25:29","date_gmt":"2011-11-26T21:25:29","guid":{"rendered":"https:\/\/blogs.mathworks.com\/steve\/2011\/11\/26\/exploring-shortest-paths-part-2\/"},"modified":"2019-10-29T17:00:11","modified_gmt":"2019-10-29T21:00:11","slug":"exploring-shortest-paths-part-2","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/steve\/2011\/11\/26\/exploring-shortest-paths-part-2\/","title":{"rendered":"Exploring shortest paths &#8211; part 2"},"content":{"rendered":"<div xmlns:mwsh=\"https:\/\/www.mathworks.com\/namespace\/mcode\/v1\/syntaxhighlight.dtd\" class=\"content\">\r\n   <p><a href=\"https:\/\/blogs.mathworks.com\/steve\/2011\/11\/01\/exploring-shortest-paths-part-1\/\">Earlier this month<\/a> I started exploring the question of computing the shortest path from one object in a binary image to another. I described\r\n      the following basic algorithm:\r\n   <\/p>\r\n   <div>\r\n      <ol>\r\n         <li>Compute the distance transform for just the upper left block of foreground pixels.<\/li>\r\n         <li>Compute the distance transform for just the lower right block of foreground pixels.<\/li>\r\n         <li>Add the two distance transforms together.<\/li>\r\n         <li>The pixels in the regional minimum of the result lie along one or more of the shortest paths from one block to the other.<\/li>\r\n      <\/ol>\r\n   <\/div>\r\n   <p>This algorithm only works for path-based approximations to the Euclidean distance transform; it doesn't work for the Euclidean\r\n      distance transform itself.\r\n   <\/p>\r\n   <p>The Image Processing Toolbox function supports three path-based approximations to the Euclidean distance transform: 'cityblock',\r\n      'chessboard', and 'quasi-euclidean'.\r\n   <\/p>\r\n   <p>Today I want to compare these three and discuss ambiguities associated with the idea of \"shortest path\" on an image.<\/p>\r\n   <p>Let's work with another small test image:<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">bw = logical([ <span style=\"color: #0000FF\">...<\/span>\r\n    0 0 0 0 0 0 0\r\n    0 1 0 0 0 0 0\r\n    0 0 0 0 0 0 0\r\n    0 0 0 0 0 0 0\r\n    0 0 0 0 0 0 0\r\n    0 0 0 0 0 0 0\r\n    0 0 0 0 0 0 0\r\n    0 0 0 0 0 0 0\r\n    0 0 0 0 0 0 0\r\n    0 0 0 0 0 1 0\r\n    0 0 0 0 0 0 0  ]);<\/pre><p>One way to get two binary images, each containing one object from the original, is to use a label matrix:<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">L = bwlabel(bw);\r\nbw1 = (L == 1)<\/pre><pre style=\"font-style:oblique\">\r\nbw1 =\r\n\r\n     0     0     0     0     0     0     0\r\n     0     1     0     0     0     0     0\r\n     0     0     0     0     0     0     0\r\n     0     0     0     0     0     0     0\r\n     0     0     0     0     0     0     0\r\n     0     0     0     0     0     0     0\r\n     0     0     0     0     0     0     0\r\n     0     0     0     0     0     0     0\r\n     0     0     0     0     0     0     0\r\n     0     0     0     0     0     0     0\r\n     0     0     0     0     0     0     0\r\n\r\n<\/pre><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">bw2 = (L == 2)<\/pre><pre style=\"font-style:oblique\">\r\nbw2 =\r\n\r\n     0     0     0     0     0     0     0\r\n     0     0     0     0     0     0     0\r\n     0     0     0     0     0     0     0\r\n     0     0     0     0     0     0     0\r\n     0     0     0     0     0     0     0\r\n     0     0     0     0     0     0     0\r\n     0     0     0     0     0     0     0\r\n     0     0     0     0     0     0     0\r\n     0     0     0     0     0     0     0\r\n     0     0     0     0     0     1     0\r\n     0     0     0     0     0     0     0\r\n\r\n<\/pre><p>Step 1 of the algorithm is to compute the distance transform for the first object. I'll use the 'cityblock' distance transform\r\n      approximation. In this approximation, only horizontal and vertical path segments are allowed. Diagonal segments are not allowed.\r\n      The distance between a pixel and any of its N, E, S, or W neighbors is 1.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">D1 = bwdist(bw1, <span style=\"color: #A020F0\">'cityblock'<\/span>)<\/pre><pre style=\"font-style:oblique\">\r\nD1 =\r\n\r\n     2     1     2     3     4     5     6\r\n     1     0     1     2     3     4     5\r\n     2     1     2     3     4     5     6\r\n     3     2     3     4     5     6     7\r\n     4     3     4     5     6     7     8\r\n     5     4     5     6     7     8     9\r\n     6     5     6     7     8     9    10\r\n     7     6     7     8     9    10    11\r\n     8     7     8     9    10    11    12\r\n     9     8     9    10    11    12    13\r\n    10     9    10    11    12    13    14\r\n\r\n<\/pre><p>Step 2 is to compute the distance transform for the second object.<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">D2 = bwdist(bw2, <span style=\"color: #A020F0\">'cityblock'<\/span>)<\/pre><pre style=\"font-style:oblique\">\r\nD2 =\r\n\r\n    14    13    12    11    10     9    10\r\n    13    12    11    10     9     8     9\r\n    12    11    10     9     8     7     8\r\n    11    10     9     8     7     6     7\r\n    10     9     8     7     6     5     6\r\n     9     8     7     6     5     4     5\r\n     8     7     6     5     4     3     4\r\n     7     6     5     4     3     2     3\r\n     6     5     4     3     2     1     2\r\n     5     4     3     2     1     0     1\r\n     6     5     4     3     2     1     2\r\n\r\n<\/pre><p>Step 3 is to add the distance transforms together.<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">D = D1 + D2<\/pre><pre style=\"font-style:oblique\">\r\nD =\r\n\r\n    16    14    14    14    14    14    16\r\n    14    12    12    12    12    12    14\r\n    14    12    12    12    12    12    14\r\n    14    12    12    12    12    12    14\r\n    14    12    12    12    12    12    14\r\n    14    12    12    12    12    12    14\r\n    14    12    12    12    12    12    14\r\n    14    12    12    12    12    12    14\r\n    14    12    12    12    12    12    14\r\n    14    12    12    12    12    12    14\r\n    16    14    14    14    14    14    16\r\n\r\n<\/pre><p>The smallest value of <tt>D<\/tt>, 12, is the minimum path length (for paths consisting only of horizontal and vertical segments) from one object to the other.\r\n   <\/p>\r\n   <p>Step 4 is to find the set of pixels in the regional minimum of <tt>D<\/tt>. This set represents the shortest path.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">paths = imregionalmin(D);<\/pre><p>To help visualize the path I'll use <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/10502-image-overlay\">imoverlay<\/a> from the MATLAB Central File Exchange. The code below will overlay the pixels on the shortest path in gray.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">P = false(size(bw));\r\nP = imoverlay(P, paths, [.5 .5 .5]);\r\nP = imoverlay(P, bw, [1 1 1]);\r\nimshow(P, <span style=\"color: #A020F0\">'InitialMagnification'<\/span>, <span style=\"color: #A020F0\">'fit'<\/span>)<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2011\/shortest_path_b_01.png\"> <p>Uh oh, why do we have a big rectangular block of gray instead of a single path? The answer is that there isn't a unique shortest\r\n      path. There are many paths you could travel to get from one object to the other that all have the same path length, 12. Here\r\n      are just a view of them:\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">subplot(2,2,1)\r\nimshow(P, <span style=\"color: #A020F0\">'InitialMagnification'<\/span>, <span style=\"color: #A020F0\">'fit'<\/span>)\r\nx = [2 6 6];\r\ny = [2 2 10];\r\nhold <span style=\"color: #A020F0\">on<\/span>\r\nplot(x, y, <span style=\"color: #A020F0\">'g'<\/span>, <span style=\"color: #A020F0\">'LineWidth'<\/span>, 2)\r\nhold <span style=\"color: #A020F0\">off<\/span>\r\n\r\nsubplot(2,2,2)\r\nimshow(P, <span style=\"color: #A020F0\">'InitialMagnification'<\/span>, <span style=\"color: #A020F0\">'fit'<\/span>)\r\nx = [2 2 6];\r\ny = [2 10 10];\r\nhold <span style=\"color: #A020F0\">on<\/span>\r\nplot(x, y, <span style=\"color: #A020F0\">'g'<\/span>, <span style=\"color: #A020F0\">'LineWidth'<\/span>, 2);\r\nhold <span style=\"color: #A020F0\">off<\/span>\r\n\r\nsubplot(2,2,3)\r\nimshow(P, <span style=\"color: #A020F0\">'InitialMagnification'<\/span>, <span style=\"color: #A020F0\">'fit'<\/span>)\r\nx = [2 3 3 4 4 5 5 6 6 6 6 6 6];\r\ny = [2 2 3 3 4 4 5 5 6 7 8 9 10];\r\nhold <span style=\"color: #A020F0\">on<\/span>\r\nplot(x, y, <span style=\"color: #A020F0\">'g'<\/span>, <span style=\"color: #A020F0\">'LineWidth'<\/span>, 2)\r\nhold <span style=\"color: #A020F0\">off<\/span>\r\n\r\nsubplot(2,2,4)\r\nimshow(P, <span style=\"color: #A020F0\">'InitialMagnification'<\/span>, <span style=\"color: #A020F0\">'fit'<\/span>)\r\nx = [2 2 2 2 2 2 3 3 4 4 5 5 6];\r\ny = [2 3 4 5 6 7 7 8 8 9 9 10 10];\r\nhold <span style=\"color: #A020F0\">on<\/span>\r\nplot(x, y, <span style=\"color: #A020F0\">'g'<\/span>, <span style=\"color: #A020F0\">'LineWidth'<\/span>, 2)\r\nhold <span style=\"color: #A020F0\">off<\/span><\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2011\/shortest_path_b_02.png\"> <p>Next, let's look at the 'chessboard' distance. In this distance transform approximation, a path can consist of horizontal,\r\n      vertical, and diagonal segments, and the path length between a pixel and any of its neighbors (N, NE, E, SE, S, SW, W, and\r\n      NW) is 1.0.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">D1 = bwdist(bw1, <span style=\"color: #A020F0\">'chessboard'<\/span>)\r\nD2 = bwdist(bw2, <span style=\"color: #A020F0\">'chessboard'<\/span>)\r\nD = D1 + D2<\/pre><pre style=\"font-style:oblique\">\r\nD1 =\r\n\r\n     1     1     1     2     3     4     5\r\n     1     0     1     2     3     4     5\r\n     1     1     1     2     3     4     5\r\n     2     2     2     2     3     4     5\r\n     3     3     3     3     3     4     5\r\n     4     4     4     4     4     4     5\r\n     5     5     5     5     5     5     5\r\n     6     6     6     6     6     6     6\r\n     7     7     7     7     7     7     7\r\n     8     8     8     8     8     8     8\r\n     9     9     9     9     9     9     9\r\n\r\n\r\nD2 =\r\n\r\n     9     9     9     9     9     9     9\r\n     8     8     8     8     8     8     8\r\n     7     7     7     7     7     7     7\r\n     6     6     6     6     6     6     6\r\n     5     5     5     5     5     5     5\r\n     5     4     4     4     4     4     4\r\n     5     4     3     3     3     3     3\r\n     5     4     3     2     2     2     2\r\n     5     4     3     2     1     1     1\r\n     5     4     3     2     1     0     1\r\n     5     4     3     2     1     1     1\r\n\r\n\r\nD =\r\n\r\n    10    10    10    11    12    13    14\r\n     9     8     9    10    11    12    13\r\n     8     8     8     9    10    11    12\r\n     8     8     8     8     9    10    11\r\n     8     8     8     8     8     9    10\r\n     9     8     8     8     8     8     9\r\n    10     9     8     8     8     8     8\r\n    11    10     9     8     8     8     8\r\n    12    11    10     9     8     8     8\r\n    13    12    11    10     9     8     9\r\n    14    13    12    11    10    10    10\r\n\r\n<\/pre><p>You can see that the shortest path length for the 'chessboard' distance is 8 instead of 12. Let's look at the pixels on the\r\n      various shortest paths.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">paths = imregionalmin(D)\r\n\r\nP = false(size(bw));\r\nP = imoverlay(P, paths, [.5 .5 .5]);\r\nP = imoverlay(P, bw, [1 1 1]);\r\nclf\r\nimshow(P, <span style=\"color: #A020F0\">'InitialMagnification'<\/span>, <span style=\"color: #A020F0\">'fit'<\/span>)<\/pre><pre style=\"font-style:oblique\">\r\npaths =\r\n\r\n     0     0     0     0     0     0     0\r\n     0     1     0     0     0     0     0\r\n     1     1     1     0     0     0     0\r\n     1     1     1     1     0     0     0\r\n     1     1     1     1     1     0     0\r\n     0     1     1     1     1     1     0\r\n     0     0     1     1     1     1     1\r\n     0     0     0     1     1     1     1\r\n     0     0     0     0     1     1     1\r\n     0     0     0     0     0     1     0\r\n     0     0     0     0     0     0     0\r\n\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2011\/shortest_path_b_03.png\"> <p>Now the set of gray pixels is not rectangular, but it still encompasses multiple possible shortest paths. And, surprisingly,\r\n      it seems to include some pixels on which the path actually moves temporarily away from its destination.\r\n   <\/p>\r\n   <p>Here are several possible paths, all of length 8 (according to the 'chessboard' distance transform).<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">subplot(2,2,1)\r\nimshow(P, <span style=\"color: #A020F0\">'InitialMagnification'<\/span>, <span style=\"color: #A020F0\">'fit'<\/span>)\r\nx = [2 3 4 5 6 6 6 6 6];\r\ny = [2 3 4 5 6 7 8 9 10];\r\nhold <span style=\"color: #A020F0\">on<\/span>\r\nplot(x, y, <span style=\"color: #A020F0\">'g'<\/span>, <span style=\"color: #A020F0\">'LineWidth'<\/span>, 2)\r\nhold <span style=\"color: #A020F0\">off<\/span>\r\n\r\nsubplot(2,2,2)\r\nimshow(P, <span style=\"color: #A020F0\">'InitialMagnification'<\/span>, <span style=\"color: #A020F0\">'fit'<\/span>)\r\nx = [2 2 2 2 2 3 4 5 6];\r\ny = [2 3 4 5 6 7 8 9 10];\r\nhold <span style=\"color: #A020F0\">on<\/span>\r\nplot(x, y, <span style=\"color: #A020F0\">'g'<\/span>, <span style=\"color: #A020F0\">'LineWidth'<\/span>, 2);\r\nhold <span style=\"color: #A020F0\">off<\/span>\r\n\r\nsubplot(2,2,3)\r\nimshow(P, <span style=\"color: #A020F0\">'InitialMagnification'<\/span>, <span style=\"color: #A020F0\">'fit'<\/span>)\r\nx = [2 1 2 1 2 3 4 5 6];\r\ny = [2 3 4 5 6 7 8 9 10];\r\nhold <span style=\"color: #A020F0\">on<\/span>\r\nplot(x, y, <span style=\"color: #A020F0\">'g'<\/span>, <span style=\"color: #A020F0\">'LineWidth'<\/span>, 2)\r\nhold <span style=\"color: #A020F0\">off<\/span>\r\n\r\nsubplot(2,2,4)\r\nimshow(P, <span style=\"color: #A020F0\">'InitialMagnification'<\/span>, <span style=\"color: #A020F0\">'fit'<\/span>)\r\nx = [2 3 4 3 2 3 4 5 6];\r\ny = [2 3 4 5 6 7 8 9 10];\r\nhold <span style=\"color: #A020F0\">on<\/span>\r\nplot(x, y, <span style=\"color: #A020F0\">'g'<\/span>, <span style=\"color: #A020F0\">'LineWidth'<\/span>, 2)\r\nhold <span style=\"color: #A020F0\">off<\/span><\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2011\/shortest_path_b_04.png\"> <p>Finally, let's look at the 'quasi-euclidean' distance transform. In this variation, paths from one pixel to another can consist\r\n      of horizontal, vertical, and diagonal segments. The distance from a pixel to one of its horizontal or vertical neighbors is\r\n      1, while the distance to one of its diagonal neighbors is sqrt(2).\r\n   <\/p>\r\n   <p>Here's the computation again, this time specifying 'quasi-euclidean':<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">D1 = bwdist(bw1, <span style=\"color: #A020F0\">'quasi-euclidean'<\/span>);\r\nD2 = bwdist(bw2, <span style=\"color: #A020F0\">'quasi-euclidean'<\/span>);\r\nD = D1 + D2<\/pre><pre style=\"font-style:oblique\">\r\nD =\r\n\r\n   12.4853   11.6569   11.6569   12.2426   12.8284   13.4142   14.8284\r\n   11.0711    9.6569   10.2426   10.8284   11.4142   12.0000   13.4142\r\n   10.4853    9.6569    9.6569   10.2426   10.8284   11.4142   12.8284\r\n   10.4853    9.6569    9.6569    9.6569   10.2426   10.8284   12.2426\r\n   10.4853    9.6569    9.6569    9.6569    9.6569   10.2426   11.6569\r\n   11.0711    9.6569    9.6569    9.6569    9.6569    9.6569   11.0711\r\n   11.6569   10.2426    9.6569    9.6569    9.6569    9.6569   10.4853\r\n   12.2426   10.8284   10.2426    9.6569    9.6569    9.6569   10.4853\r\n   12.8284   11.4142   10.8284   10.2426    9.6569    9.6569   10.4853\r\n   13.4142   12.0000   11.4142   10.8284   10.2426    9.6569   11.0711\r\n   14.8284   13.4142   12.8284   12.2426   11.6569   11.6569   12.4853\r\n\r\n<\/pre><p>You can see that the shortest path length is approximately 9.6569.<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">min(D(:))<\/pre><pre style=\"font-style:oblique\">\r\nans =\r\n\r\n    9.6569\r\n\r\n<\/pre><p>As before, let's find the set of pixels that belong to a shortest path.<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">paths = imregionalmin(D)<\/pre><pre style=\"font-style:oblique\">\r\npaths =\r\n\r\n     0     0     0     0     0     0     0\r\n     0     1     0     0     0     0     0\r\n     0     1     1     0     0     0     0\r\n     0     0     0     0     0     0     0\r\n     0     0     0     0     0     0     0\r\n     0     0     0     0     0     0     0\r\n     0     0     0     0     0     0     0\r\n     0     0     0     0     0     0     0\r\n     0     0     0     0     1     1     0\r\n     0     0     0     0     0     1     0\r\n     0     0     0     0     0     0     0\r\n\r\n<\/pre><p>That looks like trouble! The shortest-path pixels don't actually connect the two objects, as you can see below:<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">P = false(size(bw));\r\nP = imoverlay(P, paths, [.5 .5 .5]);\r\nP = imoverlay(P, bw, [1 1 1]);\r\nclf\r\nimshow(P, <span style=\"color: #A020F0\">'InitialMagnification'<\/span>, <span style=\"color: #A020F0\">'fit'<\/span>)<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2011\/shortest_path_b_05.png\"> <p>Where has our algorithm gone astray? That's the question I'll tackle next time.<\/p>\r\n\r\n<h4>All the posts in this series<\/h4>\r\n      <ul>\r\n         <li>the basic idea of finding shortest paths by adding two distance transforms together (<a href=\"https:\/\/blogs.mathworks.com\/steve\/2011\/11\/01\/exploring-shortest-paths-part-1\/\">part 1<\/a>)\r\n         <\/li>\r\n         <li>the nonuniqueness of the shortest paths (<a href=\"https:\/\/blogs.mathworks.com\/steve\/2011\/11\/26\/exploring-shortest-paths-part-2\/\">part 2<\/a>)\r\n         <\/li>\r\n         <li>handling floating-point round-off effects (<a href=\"https:\/\/blogs.mathworks.com\/steve\/2011\/12\/02\/exploring-shortest-paths-part-3\/\">part 3<\/a>)\r\n         <\/li>\r\n         <li>using thinning to pick out a single path (<a href=\"https:\/\/blogs.mathworks.com\/steve\/2011\/12\/06\/exploring-shortest-paths-part-4\/\">part 4<\/a>)\r\n         <\/li>\r\n         <li>using <tt>bwdistgeodesic<\/tt> to find shortest paths subject to constraint (<a href=\"https:\/\/blogs.mathworks.com\/steve\/2011\/12\/13\/exploring-shortest-paths-part-5\/\">part 5<\/a>)\r\n         <\/li>\r\n      <\/ul>\r\n\r\n<script language=\"JavaScript\">\r\n<!--\r\n\r\n    function grabCode_946c809711164b029425175f6b7bb91a() {\r\n        \/\/ Remember the title so we can use it in the new page\r\n        title = document.title;\r\n\r\n        \/\/ Break up these strings so that their presence\r\n        \/\/ in the Javascript doesn't mess up the search for\r\n        \/\/ the MATLAB code.\r\n        t1='946c809711164b029425175f6b7bb91a ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 946c809711164b029425175f6b7bb91a';\r\n    \r\n        b=document.getElementsByTagName('body')[0];\r\n        i1=b.innerHTML.indexOf(t1)+t1.length;\r\n        i2=b.innerHTML.indexOf(t2);\r\n \r\n        code_string = b.innerHTML.substring(i1, i2);\r\n        code_string = code_string.replace(\/REPLACE_WITH_DASH_DASH\/g,'--');\r\n\r\n        \/\/ Use \/x3C\/g instead of the less-than character to avoid errors \r\n        \/\/ in the XML parser.\r\n        \/\/ Use '\\x26#60;' instead of '<' so that the XML parser\r\n        \/\/ doesn't go ahead and substitute the less-than character. \r\n        code_string = code_string.replace(\/\\x3C\/g, '\\x26#60;');\r\n\r\n        author = 'Steve Eddins';\r\n        copyright = 'Copyright 2011 The MathWorks, Inc.';\r\n\r\n        w = window.open();\r\n        d = w.document;\r\n        d.write('<pre>\\n');\r\n        d.write(code_string);\r\n\r\n        \/\/ Add author and copyright lines at the bottom if specified.\r\n        if ((author.length > 0) || (copyright.length > 0)) {\r\n            d.writeln('');\r\n            d.writeln('%%');\r\n            if (author.length > 0) {\r\n                d.writeln('% _' + author + '_');\r\n            }\r\n            if (copyright.length > 0) {\r\n                d.writeln('% _' + copyright + '_');\r\n            }\r\n        }\r\n\r\n        d.write('<\/pre>\\n');\r\n      \r\n      d.title = title + ' (MATLAB code)';\r\n      d.close();\r\n      }   \r\n      \r\n-->\r\n<\/script><p style=\"text-align: right; font-size: xx-small; font-weight:lighter;   font-style: italic; color: gray\"><br><a href=\"javascript:grabCode_946c809711164b029425175f6b7bb91a()\"><span style=\"font-size: x-small;        font-style: italic;\">Get \r\n            the MATLAB code \r\n            <noscript>(requires JavaScript)<\/noscript><\/span><\/a><br><br>\r\n      Published with MATLAB&reg; 7.13<br><\/p>\r\n<\/div>\r\n<!--\r\n946c809711164b029425175f6b7bb91a ##### SOURCE BEGIN #####\r\n%%\r\n% <https:\/\/blogs.mathworks.com\/steve\/2011\/11\/01\/exploring-shortest-paths-part-1\/\r\n% Earlier this month> I started exploring the question of computing the\r\n% shortest path from one object in a binary image to another. I described\r\n% the following basic algorithm:\r\n%\r\n% # Compute the distance transform for just the upper left block of\r\n% foreground pixels.\r\n% # Compute the distance transform for just the lower right block of\r\n% foreground pixels.\r\n% # Add the two distance transforms together.\r\n% # The pixels in the regional minimum of the result lie along one or more\r\n% of the shortest paths from one block to the other.\r\n%\r\n% This algorithm only works for path-based approximations to the Euclidean\r\n% distance transform; it doesn't work for the Euclidean distance transform\r\n% itself.\r\n%\r\n% The Image Processing Toolbox function supports three path-based\r\n% approximations to the Euclidean distance transform: 'cityblock',\r\n% 'chessboard', and 'quasi-euclidean'.\r\n%\r\n% Today I want to compare these three and discuss ambiguities associated\r\n% with the idea of \"shortest path\" on an image.\r\n%\r\n% Let's work with another small test image:\r\n\r\nbw = logical([ ...\r\n    0 0 0 0 0 0 0\r\n    0 1 0 0 0 0 0\r\n    0 0 0 0 0 0 0\r\n    0 0 0 0 0 0 0\r\n    0 0 0 0 0 0 0\r\n    0 0 0 0 0 0 0\r\n    0 0 0 0 0 0 0\r\n    0 0 0 0 0 0 0\r\n    0 0 0 0 0 0 0\r\n    0 0 0 0 0 1 0 \r\n    0 0 0 0 0 0 0  ]);\r\n\r\n%%\r\n% One way to get two binary images, each containing one object from the\r\n% original, is to use a label matrix:\r\nL = bwlabel(bw);\r\nbw1 = (L == 1)\r\n\r\n%%\r\nbw2 = (L == 2)\r\n\r\n%%\r\n% Step 1 of the algorithm is to compute the distance transform for the\r\n% first object. I'll use the 'cityblock' distance transform approximation.\r\n% In this approximation, only horizontal and vertical path segments are\r\n% allowed. Diagonal segments are not allowed. The distance between a pixel\r\n% and any of its N, E, S, or W neighbors is 1. \r\n\r\nD1 = bwdist(bw1, 'cityblock')\r\n\r\n%%\r\n% Step 2 is to compute the distance transform for the second object.\r\nD2 = bwdist(bw2, 'cityblock')\r\n\r\n%%\r\n% Step 3 is to add the distance transforms together.\r\nD = D1 + D2\r\n\r\n%%\r\n% The smallest value of |D|, 12, is the minimum path length (for paths\r\n% consisting only of horizontal and vertical segments) from one object to\r\n% the other.\r\n\r\n%%\r\n% Step 4 is to find the set of pixels in the regional minimum of |D|. This\r\n% set represents the shortest path.\r\n\r\npaths = imregionalmin(D);\r\n\r\n%%\r\n% To help visualize the path I'll use\r\n% <https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/10502-image-overlay\r\n% imoverlay> from the MATLAB Central File Exchange. The code below will\r\n% overlay the pixels on the shortest path in gray.\r\n\r\n%%\r\nP = false(size(bw));\r\nP = imoverlay(P, paths, [.5 .5 .5]);\r\nP = imoverlay(P, bw, [1 1 1]);\r\nimshow(P, 'InitialMagnification', 'fit')\r\n\r\n%%\r\n% Uh oh, why do we have a big rectangular block of gray instead of a single\r\n% path? The answer is that there isn't a unique shortest path. There are\r\n% many paths you could travel to get from one object to the other that all\r\n% have the same path length, 12. Here are just a view of them:\r\n\r\n%%\r\nsubplot(2,2,1)\r\nimshow(P, 'InitialMagnification', 'fit')\r\nx = [2 6 6];\r\ny = [2 2 10];\r\nhold on\r\nplot(x, y, 'g', 'LineWidth', 2)\r\nhold off\r\n\r\nsubplot(2,2,2)\r\nimshow(P, 'InitialMagnification', 'fit')\r\nx = [2 2 6];\r\ny = [2 10 10];\r\nhold on\r\nplot(x, y, 'g', 'LineWidth', 2);\r\nhold off\r\n\r\nsubplot(2,2,3)\r\nimshow(P, 'InitialMagnification', 'fit')\r\nx = [2 3 3 4 4 5 5 6 6 6 6 6 6];\r\ny = [2 2 3 3 4 4 5 5 6 7 8 9 10];\r\nhold on\r\nplot(x, y, 'g', 'LineWidth', 2)\r\nhold off\r\n\r\nsubplot(2,2,4)\r\nimshow(P, 'InitialMagnification', 'fit')\r\nx = [2 2 2 2 2 2 3 3 4 4 5 5 6];\r\ny = [2 3 4 5 6 7 7 8 8 9 9 10 10];\r\nhold on\r\nplot(x, y, 'g', 'LineWidth', 2)\r\nhold off\r\n    \r\n%%\r\n% Next, let's look at the 'chessboard' distance. In this distance transform\r\n% approximation, a path can consist of horizontal, vertical, and diagonal\r\n% segments, and the path length between a pixel and any of its neighbors\r\n% (N, NE, E, SE, S, SW, W, and NW) is 1.0.\r\n\r\nD1 = bwdist(bw1, 'chessboard')\r\nD2 = bwdist(bw2, 'chessboard')\r\nD = D1 + D2\r\n\r\n%%\r\n% You can see that the shortest path length for the 'chessboard' distance\r\n% is 8 instead of 12. Let's look at the pixels on the various shortest\r\n% paths.\r\n\r\npaths = imregionalmin(D)\r\n\r\nP = false(size(bw));\r\nP = imoverlay(P, paths, [.5 .5 .5]);\r\nP = imoverlay(P, bw, [1 1 1]);\r\nclf\r\nimshow(P, 'InitialMagnification', 'fit')\r\n\r\n%%\r\n% Now the set of gray pixels is not rectangular, but it still encompasses\r\n% multiple possible shortest paths. And, surprisingly, it seems to include\r\n% some pixels on which the path actually moves temporarily away from its\r\n% destination.\r\n%\r\n% Here are several possible paths, all of length 8 (according to the\r\n% 'chessboard' distance transform).\r\n\r\n%%\r\nsubplot(2,2,1)\r\nimshow(P, 'InitialMagnification', 'fit')\r\nx = [2 3 4 5 6 6 6 6 6];\r\ny = [2 3 4 5 6 7 8 9 10];\r\nhold on\r\nplot(x, y, 'g', 'LineWidth', 2)\r\nhold off\r\n\r\nsubplot(2,2,2)\r\nimshow(P, 'InitialMagnification', 'fit')\r\nx = [2 2 2 2 2 3 4 5 6];\r\ny = [2 3 4 5 6 7 8 9 10];\r\nhold on\r\nplot(x, y, 'g', 'LineWidth', 2);\r\nhold off\r\n\r\nsubplot(2,2,3)\r\nimshow(P, 'InitialMagnification', 'fit')\r\nx = [2 1 2 1 2 3 4 5 6];\r\ny = [2 3 4 5 6 7 8 9 10];\r\nhold on\r\nplot(x, y, 'g', 'LineWidth', 2)\r\nhold off\r\n\r\nsubplot(2,2,4)\r\nimshow(P, 'InitialMagnification', 'fit')\r\nx = [2 3 4 3 2 3 4 5 6];\r\ny = [2 3 4 5 6 7 8 9 10];\r\nhold on\r\nplot(x, y, 'g', 'LineWidth', 2)\r\nhold off\r\n\r\n%%\r\n% Finally, let's look at the 'quasi-euclidean' distance transform. In this\r\n% variation, paths from one pixel to another can consist of horizontal,\r\n% vertical, and diagonal segments. The distance from a pixel to one of its\r\n% horizontal or vertical neighbors is 1, while the distance to one of its\r\n% diagonal neighbors is sqrt(2).\r\n%\r\n% Here's the computation again, this time specifying 'quasi-euclidean':\r\n\r\nD1 = bwdist(bw1, 'quasi-euclidean');\r\nD2 = bwdist(bw2, 'quasi-euclidean');\r\nD = D1 + D2\r\n\r\n%%\r\n% You can see that the shortest path length is approximately 9.6569.\r\n\r\nmin(D(:))\r\n\r\n%%\r\n% As before, let's find the set of pixels that belong to a shortest path.\r\n\r\npaths = imregionalmin(D)\r\n\r\n%%\r\n% That looks like trouble! The shortest-path pixels don't actually connect\r\n% the two objects, as you can see below:\r\n\r\n%%\r\nP = false(size(bw));\r\nP = imoverlay(P, paths, [.5 .5 .5]);\r\nP = imoverlay(P, bw, [1 1 1]);\r\nclf\r\nimshow(P, 'InitialMagnification', 'fit')\r\n\r\n%%\r\n% Where has our algorithm gone astray? That's the question I'll tackle next\r\n% time.\r\n##### SOURCE END ##### 946c809711164b029425175f6b7bb91a\r\n-->","protected":false},"excerpt":{"rendered":"<p>\r\n   Earlier this month I started exploring the question of computing the shortest path from one object in a binary image to another. I described\r\n      the following basic algorithm:\r\n   \r\n   \r\n    ... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/steve\/2011\/11\/26\/exploring-shortest-paths-part-2\/\">read more >><\/a><\/p>","protected":false},"author":42,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[456,166,178,102,90,737,366,36,330,380,68,190,72],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/396"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/users\/42"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/comments?post=396"}],"version-history":[{"count":3,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/396\/revisions"}],"predecessor-version":[{"id":3767,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/396\/revisions\/3767"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/media?parent=396"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/categories?post=396"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/tags?post=396"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}