{"id":258,"date":"2009-05-01T07:00:42","date_gmt":"2009-05-01T11:00:42","guid":{"rendered":"https:\/\/blogs.mathworks.com\/steve\/2009\/05\/01\/continental-divide-2-watershed\/"},"modified":"2019-10-28T15:30:58","modified_gmt":"2019-10-28T19:30:58","slug":"continental-divide-2-watershed","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/steve\/2009\/05\/01\/continental-divide-2-watershed\/","title":{"rendered":"Locating the US continental divide, part 2 &#8211; Watershed transform"},"content":{"rendered":"<div xmlns:mwsh=\"https:\/\/www.mathworks.com\/namespace\/mcode\/v1\/syntaxhighlight.dtd\" class=\"content\">\r\n   <introduction><\/introduction>\r\n   <p>This post is the second in my <a href=\"<https:\/\/blogs.mathworks.com\/steve\/category\/continental-divide\/\">series<\/a> on computing the location of the US continental divide.  Today I'm going to look at the <i>watershed transform<\/i>, including how to compute and visualize it using the Image Processing Toolbox functions <tt>watershed<\/tt> and <tt>label2rgb<\/tt>.\r\n   <\/p>\r\n   <p>The watershed transform of an image treats image pixel values as surface heights. It divides image pixels into <i>catchment basins<\/i>, a term borrowed from geography. A catchment basin is the geographical area draining into a river or reservoir. A watershed\r\n      <i>ridge<\/i> divides catchment basins.\r\n   <\/p>\r\n   <p>The function <tt>watershed<\/tt> identifies catchment basins and ridge pixels in an image.  Let me illustrate with a one-dimensional example.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">H = [4 3 2 3 6 7 5 4 3 3]<\/pre><pre style=\"font-style:oblique\">\r\nH =\r\n\r\n     4     3     2     3     6     7     5     4     3     3\r\n\r\n<\/pre><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">L = watershed(H)<\/pre><pre style=\"font-style:oblique\">\r\nL =\r\n\r\n     1     1     1     1     1     0     2     2     2     2\r\n\r\n<\/pre><p>The output of <tt>watershed<\/tt> is telling us that there are two catchment basins in <tt>H<\/tt>, corresponding to the elements of <tt>L<\/tt> equal to 1 and 2.  The element of <tt>L<\/tt> equal to 0 corresponds to the element of <tt>H<\/tt> equal to 7; this element is a local maximum that sits between two catchment basins. It is called a <i>ridge pixel<\/i>. We call <tt>L<\/tt> a <i>label matrix<\/i>. The toolbox functions <tt>watershed<\/tt>, <tt>bwlabel<\/tt>, and <tt>bwdist<\/tt> all produce output in this form.\r\n   <\/p>\r\n   <p>Normally in image processing, the watershed transform is used in situations where the pixel values do not literally represent\r\n      height values.  (See my MATLAB News &amp; Notes article on using the watershed transform for image segmentation.)\r\n   <\/p>\r\n   <p>For this series, though, we really do have an image whose pixel values represent height, and the watershed transform is what\r\n      we want to use to compute the continental divide. Essentially, we're looking for the Pacific Ocean and Atlantic Ocean catchment\r\n      basins for the continental US.\r\n   <\/p>\r\n   <p>So let's try computing the watershed transform of our DEM (digital elevation model). I saved the DEM to a MAT-file in my previous\r\n      post in this series.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">s = load(<span style=\"color: #A020F0\">'continental_divide'<\/span>);\r\ndem = s.dem_cropped;\r\ndisplay_range = [-500 3000];\r\nimshow(dem, display_range, <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\/2009\/continental_divide_part_2_watershed_01.jpg\"> <pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">L = watershed(dem);<\/pre><p>The toolbox function <tt>label2rgb<\/tt> is useful for visualizing label matrices. It converts a label matrix to an image, with different colors assigned to the different\r\n      catchment basins.  I'll use <tt>label2rgb<\/tt> to visualize <tt>L<\/tt> using the <tt>jet<\/tt> colormap, with ridge pixels displayed as white and catchment basin colors assigned randomly.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">rgb = label2rgb(L, <span style=\"color: #A020F0\">'jet'<\/span>, <span style=\"color: #A020F0\">'w'<\/span>, <span style=\"color: #A020F0\">'shuffle'<\/span>);\r\nimshow(rgb, <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\/2009\/continental_divide_part_2_watershed_02.jpg\"> <p>Oh boy, what a mess! What does that even mean? Let's zoom in much closer to see what's really going on.<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">axis([5580 5670 2060 2100])<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2009\/continental_divide_part_2_watershed_03.jpg\"> <p>It looks we have a very large number of catchment basins, most of which contain only a few pixels.  How many catchment basins\r\n      are there? Just look at the maximum value of <tt>L<\/tt>.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">max(L(:))<\/pre><pre style=\"font-style:oblique\">\r\nans =\r\n\r\n      540976\r\n\r\n<\/pre><p>So there are more than half a million distinct catchment basins detected by <tt>watershed<\/tt>.\r\n   <\/p>\r\n   <p>The next posts in this series will examine why there are so many, and how to get down to just two.<\/p>\r\n   <p><i>About this Series<\/i><\/p>\r\n   <p><a href=\"https:\/\/blogs.mathworks.com\/steve\/category\/continental-divide\/\">This series<\/a> explores the problem of computing the location of the continental divide for the United States.  The divide separates the\r\n      Atlantic and Pacific Ocean catchment basins for the North American continent.\r\n   <\/p>\r\n   <p>As an algorithm development problem, computing the divide lets us explore aspects of data import and visualization, manipulating\r\n      binary image masks, label matrices, regional minima, and the watershed transform.\r\n   <\/p>\r\n   <div>\r\n      <ul>\r\n         <li><a href=\"https:\/\/blogs.mathworks.com\/steve\/2009\/04\/24\/continental-divide-1-intro\/\">Part 1<\/a> - Introduction. Data import and display. <tt>multibandread<\/tt>, <tt>imshow<\/tt>.\r\n         <\/li>\r\n      <\/ul>\r\n   <\/div>\r\n   <div>\r\n      <ul>\r\n         <li><a href=\"https:\/\/blogs.mathworks.com\/steve\/2009\/05\/01\/continental-divide-2-watershed\/\">Part 2<\/a> - Watershed transform. <tt>watershed<\/tt>, <tt>label2rgb<\/tt>.\r\n         <\/li>\r\n      <\/ul>\r\n   <\/div>\r\n   <div>\r\n      <ul>\r\n         <li><a href=\"https:\/\/blogs.mathworks.com\/steve\/2009\/05\/08\/continental-divide-3-regmin\/\">Part 3<\/a> - Regional minima. <tt>imerode<\/tt>, <tt>imregionalmin<\/tt>.\r\n         <\/li>\r\n      <\/ul>\r\n   <\/div>\r\n   <div>\r\n      <ul>\r\n         <li><a href=\"https:\/\/blogs.mathworks.com\/steve\/2009\/05\/15\/continental-divide-4-oceans\/\">Part 4<\/a> - Ocean masks. binary image manipulation, <tt>bwselect<\/tt>.\r\n         <\/li>\r\n      <\/ul>\r\n   <\/div>\r\n   <div>\r\n      <ul>\r\n         <li><a href=\"https:\/\/blogs.mathworks.com\/steve\/2009\/05\/22\/continental-divide-5-imposemin\/\">Part 5<\/a> - Minima imposition. <tt>imimposemin<\/tt>.\r\n         <\/li>\r\n      <\/ul>\r\n   <\/div>\r\n   <div>\r\n      <ul>\r\n         <li><a href=\"https:\/\/blogs.mathworks.com\/steve\/2009\/05\/29\/continental-divide-6-watershed\/\">Part 6<\/a> - Computing and visualizing the divide. <tt>watershed<\/tt>, <tt>label2rgb<\/tt>, <tt>bwboundaries<\/tt>.\r\n         <\/li>\r\n      <\/ul>\r\n   <\/div>\r\n   <div>\r\n      <ul>\r\n         <li><a href=\"https:\/\/blogs.mathworks.com\/steve\/2009\/06\/05\/continental-divide-7-all-steps\/\">Part 7<\/a> - Putting it all together. One script that does everything, from data import through computation and visualization\r\n            of the divide.\r\n         <\/li>\r\n      <\/ul>\r\n   <\/div>\r\n   <p>Data credit: <i>GLOBE Task Team and others (Hastings, David A., Paula K. Dunbar, Gerald M. Elphingstone, Mark Bootz, Hiroshi Murakami, Hiroshi\r\n         Maruyama, Hiroshi Masaharu, Peter Holland, John Payne, Nevin A. Bryant, Thomas L. Logan, J.-P. Muller, Gunter Schreier, and\r\n         John S. MacDonald), eds., 1999. The Global Land One-kilometer Base Elevation (GLOBE) Digital Elevation Model, Version 1.0.\r\n         National Oceanic and Atmospheric Administration, National Geophysical Data Center, 325 Broadway, Boulder, Colorado 80305-3328,\r\n         U.S.A. Digital data base on the World Wide Web (URL: <a href=\"http:\/\/www.ngdc.noaa.gov\/mgg\/topo\/globe.html\">http:\/\/www.ngdc.noaa.gov\/mgg\/topo\/globe.html<\/a>) and CD-ROMs.<\/i><\/p><script language=\"JavaScript\">\r\n<!--\r\n\r\n    function grabCode_cf03a6fa9bce4cb59e675a7e12a71101() {\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='cf03a6fa9bce4cb59e675a7e12a71101 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' cf03a6fa9bce4cb59e675a7e12a71101';\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 2009 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_cf03a6fa9bce4cb59e675a7e12a71101()\"><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.8<br><\/p>\r\n<\/div>\r\n<!--\r\ncf03a6fa9bce4cb59e675a7e12a71101 ##### SOURCE BEGIN #####\r\n\r\n%%\r\n% This post is the second in my \r\n% <<https:\/\/blogs.mathworks.com\/steve\/category\/continental-divide\/ series>\r\n% on computing the location of the US continental divide.  Today I'm going\r\n% to look at the _watershed transform_, including how to compute and\r\n% visualize it using the Image Processing Toolbox functions |watershed| and\r\n% |label2rgb|.\r\n%\r\n% The watershed transform of an image treats image pixel values as surface\r\n% heights. It divides image pixels into _catchment basins_, a term borrowed\r\n% from geography. A catchment basin is the geographical area draining into\r\n% a river or reservoir. A watershed _ridge_ divides catchment basins.\r\n%\r\n% The function |watershed| identifies catchment basins and ridge pixels\r\n% in an image.  Let me illustrate with a one-dimensional example.\r\n\r\nH = [4 3 2 3 6 7 5 4 3 3]\r\n\r\n%%\r\n\r\nL = watershed(H)\r\n\r\n%%\r\n% The output of |watershed| is telling us that there are two catchment basins\r\n% in |H|, corresponding to the elements of |L| equal to 1 and 2.  The\r\n% element of |L| equal to 0 corresponds to the element of |H| equal to 7;\r\n% this element is a local maximum that sits between two catchment basins.\r\n% It is called a _ridge pixel_. We call |L| a _label matrix_. The toolbox\r\n% functions |watershed|, |bwlabel|, and |bwdist| all produce output in this\r\n% form.\r\n%\r\n% Normally in image processing, the watershed transform is used in\r\n% situations where the pixel values do not literally represent height\r\n% values.  (See my\r\n% <https:\/\/www.mathworks.com\/company\/newsletters.htmlnews_notes\/win02\/watershed.html\r\n% MATLAB News & Notes article> on using the watershed transform for\r\n% image segmentation.)\r\n%\r\n% For this series, though, we really do have an image whose pixel values\r\n% represent height, and the watershed transform is what we want to use to\r\n% compute the continental divide. Essentially, we're looking for the\r\n% Pacific Ocean and Atlantic Ocean catchment basins for the continental US.\r\n% \r\n% So let's try computing the watershed transform of our DEM (digital\r\n% elevation model). I saved the DEM to a MAT-file in my previous post in\r\n% this series.\r\n\r\ns = load('continental_divide');\r\ndem = s.dem_cropped;\r\ndisplay_range = [-500 3000];\r\nimshow(dem, display_range, 'InitialMagnification', 'fit');\r\n\r\n%%\r\n\r\nL = watershed(dem);\r\n\r\n%%\r\n% The toolbox function |label2rgb| is useful for visualizing label\r\n% matrices. It converts a label matrix to an image, with different colors\r\n% assigned to the different catchment basins.  I'll use |label2rgb| to\r\n% visualize |L| using the |jet| colormap, with ridge pixels displayed as\r\n% white and catchment basin colors assigned randomly.\r\n\r\nrgb = label2rgb(L, 'jet', 'w', 'shuffle');\r\nimshow(rgb, 'InitialMagnification', 'fit')\r\n\r\n%%\r\n% Oh boy, what a mess! What does that even mean? Let's zoom in much closer\r\n% to see what's really going on.\r\n\r\naxis([5580 5670 2060 2100])\r\n\r\n%%\r\n% It looks we have a very large number of catchment basins, most of which\r\n% contain only a few pixels.  How many catchment basins are there? Just\r\n% look at the maximum value of |L|.\r\n\r\nmax(L(:))\r\n\r\n%%\r\n% So there are more than half a million distinct catchment basins detected\r\n% by |watershed|.\r\n%\r\n% The next posts in this series will examine why there are so many, and how\r\n% to get down to just two.\r\n\r\n%%\r\n% _About this Series_ \r\n%\r\n% <https:\/\/blogs.mathworks.com\/steve\/category\/continental-divide\/ This\r\n% series> explores the problem of computing the location of the \r\n% continental divide for the United States.  The divide separates the\r\n% Atlantic and Pacific Ocean catchment basins for the North American\r\n% continent.\r\n%\r\n% As an algorithm development problem, computing the divide lets us\r\n% explore aspects of data import and visualization, manipulating binary\r\n% image masks, label matrices, regional minima, and the watershed\r\n% transform.\r\n%\r\n% * Part 1 - Introduction. Data import and display. |multibandread|,\r\n% |imshow|. \r\n%\r\n% * Part 2 - Watershed transform. |watershed|, |label2rgb|.\r\n%\r\n% * Part 3 - Regional minima. |imerode|, |imregionalmin|.\r\n%\r\n% * Part 4 - Ocean masks. binary image manipulation, |bwselect|.\r\n%\r\n% * Part 5 - Minima imposition. |imimposemin|.\r\n%\r\n% * Part 6 - Computing and visualizing the divide. |watershed|,\r\n% |label2rgb|, |bwboundaries|. \r\n%\r\n% * Part 7 - Putting it all together. One script that does everything, from\r\n% data import through computation and visualization of the divide.\r\n%\r\n% Data credit: _GLOBE Task Team and others (Hastings, David A., Paula K.\r\n% Dunbar, Gerald M. Elphingstone, Mark Bootz, Hiroshi Murakami, Hiroshi\r\n% Maruyama, Hiroshi Masaharu, Peter Holland, John Payne, Nevin A. Bryant,\r\n% Thomas L. Logan, J.-P. Muller, Gunter Schreier, and John S. MacDonald),\r\n% eds., 1999. The Global Land One-kilometer Base Elevation (GLOBE) Digital\r\n% Elevation Model, Version 1.0. National Oceanic and Atmospheric\r\n% Administration, National Geophysical Data Center, 325 Broadway, Boulder,\r\n% Colorado 80305-3328, U.S.A. Digital data base on the World Wide Web (URL:\r\n% http:\/\/www.ngdc.noaa.gov\/mgg\/topo\/globe.html) and CD-ROMs._\r\n##### SOURCE END ##### cf03a6fa9bce4cb59e675a7e12a71101\r\n-->","protected":false},"excerpt":{"rendered":"<p>\r\n   \r\n   This post is the second in my series on computing the location of the US continental divide.  Today I'm going to look at the watershed transform, including how to compute and visualize it... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/steve\/2009\/05\/01\/continental-divide-2-watershed\/\">read more >><\/a><\/p>","protected":false},"author":42,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[19],"tags":[50,36,152,362,122,150],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/258"}],"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=258"}],"version-history":[{"count":1,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/258\/revisions"}],"predecessor-version":[{"id":2275,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/258\/revisions\/2275"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/media?parent=258"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/categories?post=258"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/tags?post=258"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}