{"id":133,"date":"2007-04-26T11:11:20","date_gmt":"2007-04-26T15:11:20","guid":{"rendered":"https:\/\/blogs.mathworks.com\/steve\/2007\/04\/26\/upslope-area-part-2\/"},"modified":"2019-10-23T12:53:30","modified_gmt":"2019-10-23T16:53:30","slug":"upslope-area-part-2","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/steve\/2007\/04\/26\/upslope-area-part-2\/","title":{"rendered":"Upslope area &#8211; D-infinity flow"},"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\/2007\/03\/30\/upslope-area-part-1\/\">A few weeks ago<\/a> I promised a series on developing a MATLAB algorithm to compute upslope area. Now I'm ready to begin that project in earnest.\r\n   <\/p>\r\n   <p>First, though, I'd like to comment on the motivation for this series. Specifically, why look at a method from the area of\r\n      hydrology in a blog about image processing algorithms? There are two reasons:\r\n   <\/p>\r\n   <div>\r\n      <ul>\r\n         <li>MATLAB users are in all disciplines of engineering and science, and the ones who use image processing methods use them for\r\n            a variety of gridded data sets, not just for processing pictures.  Applying image processing techniques to digital elevation\r\n            models (DEMs), for example, is common.\r\n         <\/li>\r\n         <li>Several techniques originally developed for the computational analysis of DEMs have turned out to be broadly useful for processing\r\n            other kinds of image data.  Perhaps the most well-known example is the watershed transform.\r\n         <\/li>\r\n      <\/ul>\r\n   <\/div>\r\n   <p>The first thing we need to think about is computing the <i>flow direction<\/i> for a given pixel. That is, based on the height of a pixel and its neighbors, in which direction will water run off from\r\n      the center of that pixel?  The Tarboton 1997 paper says the earliest method is to say the flow direction is toward whichever of the eight neigbhors has the steepest downward\r\n      slope. Because the flow direction can take on one of 8 possible values, this is called the D8 method.\r\n   <\/p>\r\n   <p>Tarboton proposes a new flow direction method, called D-infinity because flow direction assigned to a pixel can take on any\r\n      value between 0 and 2*pi. The method examines eight triangular facets for each pixel.  Each facet has a vertex at the pixel\r\n      center and two vertices at the centers of neighboring pixels.\r\n   <\/p>\r\n   <p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2007\/upslope_area_part_2_fig_1.png\"> <\/p>\r\n   <p>The flow direction for a particular facet is the direction of the steepest downward slope on the facet.  The function <tt>facetFlow<\/tt> below computes this value for the east-northeast facet. Variable names in the code are based on this diagram:\r\n   <\/p>\r\n   <p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2007\/upslope_area_part_2_fig_2.png\"> <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">type <span style=\"color: #A020F0\">facetFlow<\/span><\/pre><pre style=\"font-style:oblique\">\r\nfunction [r,s] = facetFlow(e0, e1, e2, d1, d2)\r\n% facetFlow Facet flow direction.\r\n% [r, s] = facetFlow(e0, e1, e2, d1, d2) computes the facet flow direction\r\n% for an east-northeast pixel facet.  e0 is the height of the center pixel.\r\n% e1 is the height of the east neighbor.  e2 is the height of the northeast\r\n% neighbor.  d1 is the horizontal pixel center spacing.  d2 is the vertical\r\n% pixel center spacing.  d1 and d2 are optional; if omitted, a value of 1.0\r\n% is assumed.\r\n%\r\n% r is the facet flow direction in radians, and s is the magnitude of the\r\n% corresponding slope.\r\n\r\n% Steve Eddins\r\n% Copyright 2007 The MathWorks, Inc.\r\n\r\n% Reference: Tarboton, \"A new method for the determination of flow\r\n% directions and upslope areas in grid digital elevation models,\" Water\r\n% Resources Research, vol. 33, no. 2, pages 309-319, February 1997.\r\n\r\nif nargin &lt; 4\r\n    d1 = 1;\r\n    d2 = 1;\r\nend\r\n\r\ns1 = (e0 - e1)\/d1;             % eqn (1)\r\ns2 = (e1 - e2)\/d2;             % eqn (2)\r\n\r\nr = atan2(s2, s1);             % eqn (3)\r\ns = hypot(s1, s2);             % eqn (3)\r\n\r\ndiagonal_angle    = atan2(d2, d1);\r\ndiagonal_distance = hypot(d1, d2);\r\n\r\nif r &lt; 0\r\n    % eqn (4)\r\n    r = 0;\r\n    s = s1;\r\n\r\nelseif r &gt; diagonal_angle\r\n    % eqn (5)\r\n    r = diagonal_angle;\r\n    s = (e0 - e2)\/diagonal_distance;\r\nend\r\n\r\n\r\n<\/pre><p>This same computation can be applied to all the facets via rotations or flips. Tarboton provides a lookup table of facet transformations\r\n      that can be used directly in the implementation.  The function <tt>pixelFlow<\/tt> below uses <tt>facetFlow<\/tt> and the lookup table to find both the flow direction and flow magnitude for a given pixel inside a DEM matrix. The flow direction\r\n      for the pixel is the flow direction with the highest magnitude for each of the eight facets.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">type <span style=\"color: #A020F0\">pixelFlow<\/span><\/pre><pre style=\"font-style:oblique\">\r\nfunction [r, s] = pixelFlow(E, i, j, d1, d2)\r\n% pixelFlow Downslope flow direction from a pixel in a DEM.\r\n% [r, s] = pixelFlow(E, i, j, d1, d2) computes the flow direction for a\r\n% single DEM pixel E(i, j).  d1 is the horizontal pixel center spacing.  d2\r\n% is the vertical pixel center spacing.  d1 and d2 are optional; if\r\n% omitted, a value of 1.0 is assumed.\r\n%\r\n% r is the facet flow direction in radians, and s is the magnitude of the\r\n% corresponding slope.\r\n\r\n% Steve Eddins\r\n% Copyright 2007 The MathWorks, Inc.\r\n\r\n% Reference: Tarboton, \"A new method for the determination of flow\r\n% directions and upslope areas in grid digital elevation models,\" Water\r\n% Resources Research, vol. 33, no. 2, pages 309-319, February 1997.\r\n\r\nif nargin &lt; 4\r\n    d1 = 1;\r\n    d2 = 1;\r\nend\r\n\r\n% Table 1, page 311\r\ne0 = E(i, j);\r\ne1 = [E(i,j+1) E(i-1,j) E(i-1,j) E(i,j-1) ...\r\n      E(i,j-1) E(i+1,j) E(i+1,j) E(i,j+1)];\r\n\r\ne2 = [E(i-1,j+1) E(i-1,j+1) E(i-1,j-1) E(i-1,j-1) ...\r\n      E(i+1,j-1) E(i+1,j-1) E(i+1,j+1) E(i+1,j+1)];\r\n\r\nac = [0  1  1  2  2  3  3  4];\r\naf = [1 -1  1 -1  1 -1  1 -1];\r\n\r\nrp = zeros(1, 8);\r\nsp = zeros(1, 8);\r\n\r\nfor k = 1:8\r\n    [rp(k), sp(k)] = facetFlow(e0, e1(k), e2(k), d1, d2);\r\nend\r\n\r\n% Find the facet with the maximum down-slope.\r\n[s, k_max] = max(sp);\r\n\r\nif s &gt; 0\r\n    % Maximum down-slope is positive.\r\n    r = (af(k_max) * rp(k_max)) + (ac(k_max) * pi \/ 2);\r\nelse\r\n    % The pixel is in a flat area or is a pit.  Flow direction angle is\r\n    % unresolved.\r\n    r = NaN;\r\nend\r\n\r\n    \r\n<\/pre><p>Note: At this point in algorithm development, I am primarily concerned with getting a correct implementation of the method\r\n      described in the paper. It's way too early yet to be worrying about performance.  Also, note the cross-references in my code\r\n      to specific equation and page numbers.  This is a <b>really<\/b> good habit to get into.  (I learned that lesson the hard way.)\r\n   <\/p>\r\n   <p>Next up: Try this pixel flow computation on some simple test cases, and start to think about what to do for plateaus.<\/p><script language=\"JavaScript\">\r\n<!--\r\n\r\n    function grabCode_f1cea454f7e84ec9a93011d0808bc215() {\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='f1cea454f7e84ec9a93011d0808bc215 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' f1cea454f7e84ec9a93011d0808bc215';\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 2007 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_f1cea454f7e84ec9a93011d0808bc215()\"><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.4<br><\/p>\r\n<\/div>\r\n<!--\r\nf1cea454f7e84ec9a93011d0808bc215 ##### SOURCE BEGIN #####\r\n%% Upslope area - Part 2\r\n% <https:\/\/blogs.mathworks.com\/steve\/2007\/03\/30\/upslope-area-part-1\/ \r\n% A few weeks ago> I promised a series on developing a MATLAB algorithm to\r\n% compute upslope area. Now I'm ready to begin that project in earnest.\r\n%\r\n% First, though, I'd like to comment on the motivation for this series.  \r\n% Specifically, why look at a method from the area of hydrology in a blog\r\n% about image processing algorithms? There are two reasons:\r\n%\r\n% * MATLAB users are in all disciplines of engineering and science, and the\r\n% ones who use image processing methods use them for a variety of gridded\r\n% data sets, not just for processing pictures.  Applying image processing\r\n% techniques to digital elevation models (DEMs), for example, is common.\r\n% * Several techniques originally developed for the computational analysis\r\n% of DEMs have turned out to be broadly useful for processing other kinds\r\n% of image data.  Perhaps the most well-known example is the watershed\r\n% transform.\r\n%\r\n% The first thing we need to think about is computing the _flow direction_\r\n% for a given pixel. That is, based on the height of a pixel and its\r\n% neighbors, in which direction will water run off from the center of that\r\n% pixel?  The\r\n% <http:\/\/www.engineering.usu.edu\/cee\/faculty\/dtarb\/96wr03137.pdf Tarboton\r\n% 1997 paper> says the earliest method is to say the flow direction is\r\n% toward whichever of the eight neigbhors has the steepest downward slope.\r\n% Because the flow direction can take on one of 8 possible values, this is\r\n% called the D8 method.\r\n%\r\n% Tarboton proposes a new flow direction method, called D-infinity because \r\n% flow direction assigned to a pixel can take on any value between 0 and\r\n% 2*pi. The method examines eight triangular facets for each pixel.  Each\r\n% facet has a vertex at the pixel center and two vertices at the centers of\r\n% neighboring pixels.\r\n%\r\n% <<upslope_area_part_2_fig_1.png>>\r\n%\r\n% The flow direction for a particular facet is the direction of the\r\n% steepest downward slope on the facet.  The function |facetFlow| below\r\n% computes this value for the east-northeast facet. Variable names in the\r\n% code are based on this diagram:\r\n%\r\n% <<upslope_area_part_2_fig_2.png>>\r\n\r\ntype facetFlow\r\n\r\n%%\r\n% This same computation can be applied to all the facets via rotations or\r\n% flips. Tarboton provides a lookup table of facet transformations that can\r\n% be used directly in the implementation.  The function |pixelFlow| below\r\n% uses |facetFlow| and the lookup table to find both the flow direction and\r\n% flow magnitude for a given pixel inside a DEM matrix. The flow direction\r\n% for the pixel is the flow direction with the highest magnitude for each\r\n% of the eight facets.\r\n\r\ntype pixelFlow\r\n\r\n%%\r\n% Note: At this point in algorithm development, I am primarily concerned\r\n% with getting a correct implementation of the method described in the\r\n% paper. It's way to early yet to be worrying about performance.  Also,\r\n% note the cross-references in my code to specific equation and page\r\n% numbers.  This is a *really* good habit to get into.  (I learned that\r\n% lesson the hard way.)\r\n%\r\n% Next up: Try this pixel flow computation on some simple test cases, and\r\n% start to think about what to do for plateaus.\r\n##### SOURCE END ##### f1cea454f7e84ec9a93011d0808bc215\r\n-->","protected":false},"excerpt":{"rendered":"<p>\r\n   A few weeks ago I promised a series on developing a MATLAB algorithm to compute upslope area. Now I'm ready to begin that project in earnest.\r\n   \r\n   First, though, I'd like to comment on the... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/steve\/2007\/04\/26\/upslope-area-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":[9],"tags":[196,334,122,284,130],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/133"}],"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=133"}],"version-history":[{"count":1,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/133\/revisions"}],"predecessor-version":[{"id":2245,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/133\/revisions\/2245"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/media?parent=133"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/categories?post=133"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/tags?post=133"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}