8
$\begingroup$

I want to find the area covered by the reservoir of a dam using a satellite image.

This is what I have so far.

DamPosition = DamData[Entity["Dam", "TehriDam::q2zsw"], "Position"]

Which returns the coordinates. And then, I use some image manipulation to isolate the dam from geoImage.

geoImage = 
 DeleteSmallComponents[
  Dilation[
   Graphics[
    Select[Cases[
      GeoGraphics[
       GeoBoundingBox[GeoPosition[{30.377778`, 78.480556`}]], 
       GeoBackground -> 
        "VectorMinimal"], {Directive[{___, 
         RGBColor[0.6, 0.807843137254902`, 1.], ___}], ___}, 
      Infinity], Not@*FreeQ[Polygon]]], 0]]

This is the image that I get after image manipulation

Now, all I want to do is find the area of the blue - shaded region.

I know I can do this manually using the getcoordinates tool, but that seems too unreliable and tedious to do. I'm looking for an automated way to do it.

PS : Using GetCoordinates, we can use the following code

    damContour = {{36.14216500804076`, -98.66601000992658`},
   {36.15131161335255`, -98.6549477815357`},
   {36.1501032100147`, -98.62214348441108`},
   {36.15000037203102`, -98.60908533742007`},
   {36.13193732747872`, -98.58352140011719`},
   {36.10128112030604`, -98.57004960135653`},
   {36.08009879008038`, -98.6043835918035`},
   {36.1172565230945`, -98.61315564049649`},
   {36.12831708030723`, -98.62663775701455`},
   {36.13202116684048`, -98.64507269213401`},
   {36.13870030579935`, -98.6454368865287`},
   {36.13708633726377`, -98.6568745786338`}};
GeoGraphics[{White, Thick, Line[GeoPosition[damContour]]}, 
 GeoRange -> {{36.05, 36.17}, {-98.7, -98.52}}, 
 GeoRangePadding -> Scaled[0.1], GeoBackground -> "Satellite"];
GeoArea[Polygon[GeoPosition[damContour]]]
$\endgroup$
5
  • $\begingroup$ "Area of a dam"? Not of a lake?? $\endgroup$ Commented Sep 26, 2023 at 23:23
  • $\begingroup$ Oops - I meant the area covered by the reservoir of the dam $\endgroup$
    – Navvye
    Commented Sep 27, 2023 at 0:25
  • $\begingroup$ Might be worth working with an equal-area projection. The available projections in WL can be found via GeoProjectionData["EqualArea"]. $\endgroup$
    – Greg Hurst
    Commented Sep 27, 2023 at 1:54
  • $\begingroup$ @GregHurst could you elaborate on this please? $\endgroup$
    – Navvye
    Commented Sep 28, 2023 at 16:51
  • $\begingroup$ Never mind, I didn't see you were using GeoArea. If you weren't, then the area would depend on the projection. $\endgroup$
    – Greg Hurst
    Commented Sep 28, 2023 at 19:59

2 Answers 2

4
$\begingroup$

First I get just the image of the area with a 10 km scale bar:

DamPosition = DamData[Entity["Dam", "TehriDam::q2zsw"], "Position"];

l = 10;
geoImage = 
 GeoGraphics[GeoBoundingBox[DamPosition], 
  GeoBackground -> "StreetMapNoLabels", 
  GeoScaleBar -> Placed[Quantity[{0, l}, "Kilometers"], {Right, Top}]]

Mathematica graphics

Then I find the areas that have the color of water, and Binarize:


waterColor = RGBColor[0.6, 0.807843137254902, 1.];
lake = ColorDetect[geoImage, ColorsNear[waterColor, 0]] // Binarize

Mathematica graphics

I get just the part that looks like the reservoir by taking the largest component of lake:

res = SelectComponents[lake, "Count", -1]

Mathematica graphics

Now I get the scale bar by finding the black parts of geoImage:

bar = Binarize@ColorDetect[geoImage, RGBColor[0, 0, 0]]

Mathematica graphics

To get the scale bar without the labels, I select the longest length component of bar:

bar = SelectComponents[bar, "Length", -1]

Mathematica graphics

Then I get the pixel length of the scale bar by grabbing the largest side length of its BoundingBox, and calculate the scale by dividing l by the pixel length of the scale bar

v = First@Values@ComponentMeasurements[bar, "BoundingBox"];
len = Max[Abs[First[v] - Last[v]]];
scale = Quantity[l, "km"]/len
(*Quantity[0.04329, "Kilometers"] *)

The area of each pixel is just scale^2:

pixelArea=scale^2;

The total area of res is now just the total of the image (since it's binarized) times `pixelArea

Total@Flatten[ImageData[res]]*pixelArea

(*Quantity[20.5019, ("Kilometers")^2]*)

So the area of the reservoir is $\approx 20.5 \mathrm{km}^2$

$\endgroup$
2
  • $\begingroup$ Thank you so much for your answer. Just a small question - shouldn't the scale be 5KM instead of 0.5KM? The answer is skewed by a factor of 10. Also, is there a way to find the scale/unitpixel programmatically? $\endgroup$
    – Navvye
    Commented Sep 27, 2023 at 17:47
  • 1
    $\begingroup$ Thanks. I guess I need to get my vision checked. Added an automated way to get scale. $\endgroup$
    – ydd
    Commented Sep 27, 2023 at 18:58
1
$\begingroup$

Alternate answer that I have received

DamPosition = DamData[Entity["Dam", "TehriDam::q2zsw"], "Position"];

l = 10;
geoImage = 
 GeoGraphics[GeoBoundingBox[DamPosition], 
  GeoBackground -> "StreetMapNoLabels", 
  GeoScaleBar -> Placed[Quantity[{0, l}, "Kilometers"], {Right, Top}]]
waterColor = RGBColor[0.6, 0.807843137254902, 1.];
geoImage = ColorDetect[geoImage, ColorsNear[waterColor, 0]] // 
Binarize
 ImageResize[geoImage, {128,128}]
 Area[ImageMesh[geoImage]]

This becomes useful when we resize all images to a standard size and then compare the area of different dams.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.