Difference between revisions of "Land usage"

From Geohashing
imported>Relet
m (How it works)
imported>AudiblySilenced
m (Fixed some links and capitalization, prettied up the code)
Line 2: Line 2:
  
 
=== Usage ===
 
=== Usage ===
# Highlight your graticule in the [http://irc.peeron.com/xkcd/map/map.html peeron map].
+
# Highlight your graticule in the [http://carabiner.peeron.com/xkcd/map/map.html peeron map].
 
# Make a screenshot (moar zoom = moar better).
 
# Make a screenshot (moar zoom = moar better).
 
# Save it in your preferred lossless image format (png is fine).
 
# Save it in your preferred lossless image format (png is fine).
# Run this script with the image file as a parameter.  
+
# Run the script below with the image file as a parameter.  
 
Note: You may have to adapt the color values - read the next section. This may be the problem if you are getting no output.
 
Note: You may have to adapt the color values - read the next section. This may be the problem if you are getting no output.
  
Note on versions: As of 17 June, 2009, the module [python-image http://www.pythonware.com/products/pil/] which is required by this script only works with python 2.6.
+
Note on versions: As of 17 June, 2009, the module [http://www.pythonware.com/products/pil/ python-image] which is required by this script only works with Python 2.6.
  
 
=== How it works ===
 
=== How it works ===
Line 43: Line 43:
  
 
=== Code ===
 
=== Code ===
''it's python. ready for take-off.''  
+
''It's Python. Ready for take-off.''  
 
<pre>
 
<pre>
 
#!/usr/bin/env python
 
#!/usr/bin/env python
import Image, sys
+
import Image
 +
import sys
  
 
colors = {
 
colors = {
          (183,205,161):"Natural reserves",
+
    (183, 205, 161): "Natural reserves",
          (183,205,162):"Natural reserves",
+
    (183, 205, 162): "Natural reserves",
          (184,206,162):"Natural reserves",
+
    (184, 206, 162): "Natural reserves",
          (185,207,163):"Natural reserves",
+
    (185, 207, 163): "Natural reserves",
          (211,215,198):"Forests",
+
    (211, 215, 198): "Forests",
          (211,215,199):"Forests",
+
    (211, 215, 199): "Forests",
          (212,215,199):"Forests",
+
    (212, 215, 199): "Forests",
          (212,216,199):"Forests",
+
    (212, 216, 199): "Forests",
          (213,217,200):"Forests",
+
    (213, 217, 200): "Forests",
          (216,208,206):"Industrial",
+
    (216, 208, 206): "Industrial",
          (216,208,207):"Industrial",
+
    (216, 208, 207): "Industrial",
          (216,210,210):"Industrial",
+
    (216, 210, 210): "Industrial",
          (218,210,218):"Industrial",
+
    (218, 210, 218): "Industrial",
          (235,224,214):"Settlements",
+
    (235, 224, 214): "Settlements",
          (235,224,215):"Settlements",
+
    (235, 224, 215): "Settlements",
          (235,224,216):"Settlements",
+
    (235, 224, 216): "Settlements",
          (235,225,216):"Settlements",
+
    (235, 225, 216): "Settlements",
          (236,225,216):"Settlements",  
+
    (236, 225, 216): "Settlements",
          (237,226,217):"Settlements",
+
    (237, 226, 217): "Settlements",
          (242,195, 72):"Highways",
+
    (242, 195, 72): "Highways",
          (243,195, 72):"Highways",
+
    (243, 195, 72): "Highways",
          (243,196, 72):"Highways",
+
    (243, 196, 72): "Highways",
          (243,196, 73):"Highways",
+
    (243, 196, 73): "Highways",
          (243,197, 71):"Highways",
+
    (243, 197, 71): "Highways",
          (244,196, 73):"Highways",
+
    (244, 196, 73): "Highways",
          (245,197,73 ):"Highways",
+
    (245, 197, 73): "Highways",
          (242,233,227):"Fields",  
+
    (242, 233, 227): "Fields",
          (243,233,228):"Fields",
+
    (243, 233, 228): "Fields",
          (243,233,229):"Fields",
+
    (243, 233, 229): "Fields",
          (243,234,229):"Fields",
+
    (243, 234, 229): "Fields",
          (243,235,229):"Fields",
+
    (243, 235, 229): "Fields",
          (245,235,230):"Fields",
+
    (245, 235, 230): "Fields",
          (252,241,134):"Roads",
+
    (252, 241, 134): "Roads",
          (252,241,135):"Roads",
+
    (252, 241, 135): "Roads",
          (252,242,135):"Roads",
+
    (252, 242, 135): "Roads",
          (253,242,135):"Roads",
+
    (253, 242, 135): "Roads",
          (253,243,135):"Roads",
+
    (253, 243, 135): "Roads",
          (254,243,135):"Roads",
+
    (254, 243, 135): "Roads",
          (254,244,134):"Roads",
+
    (254, 244, 134): "Roads",
          (255,244,136):"Roads",
+
    (255, 244, 136): "Roads",
          (171,185,205):"Water",
+
    (171, 185, 205): "Water",
          (171,186,206):"Water",
+
    (171, 186, 206): "Water",
          (172,185,205):"Water",
+
    (172, 185, 205): "Water",
          (172,186,205):"Water",
+
    (172, 186, 205): "Water",
          (172,186,206):"Water",
+
    (172, 186, 206): "Water",
          (173,187,207):"Water",
+
    (173, 187, 207): "Water",
          (254,132, 93):"Intracity Highways",
+
    (254, 132, 93): "Intracity Highways",
        }
+
}
  
 
stats = {}
 
stats = {}
Line 105: Line 106:
 
image = Image.open(sys.argv[1])
 
image = Image.open(sys.argv[1])
 
for pixel in image.getdata():
 
for pixel in image.getdata():
  stats[pixel] = (pixel in stats) and stats[pixel]+1 or 1
+
    stats[pixel] = (pixel in stats) and stats[pixel] + 1 or 1
  
 
for pixel, count in stats.iteritems():
 
for pixel, count in stats.iteritems():
  if pixel[:3] in colors:
+
    if pixel[:3] in colors:
    counts[colors[pixel]] = colors[pixel] in counts and counts[colors[pixel]]+count or count
+
        counts[colors[pixel]] = colors[pixel] in counts and counts[colors[pixel]] + count or count
  
 
for label, count in counts.iteritems():
 
for label, count in counts.iteritems():
  total = total + count
+
    total = total + count
 
for label, count in counts.iteritems():
 
for label, count in counts.iteritems():
  results.append((count*100.0/total, label))
+
    results.append((count * 100.0 / total, label))
results.sort(reverse=True)
+
results.sort(reverse = True)
 
for result in results:
 
for result in results:
  print("%.2f%%\t%s" % result)
+
    print("%.2f%%\t%s" % result)
 
</pre>
 
</pre>

Revision as of 00:10, 20 July 2013

Here's a small piece of code that allows you to calculate the land usage distribution in your graticule. It's a hack, and you should know how to interpret the results.

Usage

  1. Highlight your graticule in the peeron map.
  2. Make a screenshot (moar zoom = moar better).
  3. Save it in your preferred lossless image format (png is fine).
  4. Run the script below with the image file as a parameter.

Note: You may have to adapt the color values - read the next section. This may be the problem if you are getting no output.

Note on versions: As of 17 June, 2009, the module python-image which is required by this script only works with Python 2.6.

How it works

The script basically counts pixels on your screenshot. It has a list of colours which are used on the map for certain areas.

On the screenshot of your graticule, all pixels within the graticule highlight are slightly rosé, compared to everything else. Forests are green-rosé, Natural reserves are dark-green-rosé, bodies of water are blue-rosé, and so on. The script counts all pixels for which a meaning is given, and ignores everything else. Finally, it compares the count of each colour with the total count of identified pixels.

Note that Google uses antialiasing. Hence, the script will only recognize large areas of uniform colour, but not anything in-between. Also, due to some shading effects, several colours are used for the same type of area across the graticule. The colours given are some few examples for the rendering used in Germany - if for example your highways are rendered in a different colour, you may have to adapt it. You may also want to add your own. To do so, use the pipette tool in your favourite image editor and select a pixel in a large field of uniform colour. Copy the colour values for R(ed), G(reen), B(lue) . I have tried to compile a first list of used colours in the source code, please update this as needed.

As the maps overemphasize roads on smaller scales, their results will likewise be exaggerated. You may want to ignore them alltogether, or interpret the value as "being rather close to a road/highway".

Basically, the script currently differentiates between:

  • Everything pale white: Uncharted land - usually: agriculture, wilderness, ...
  • Everything light grey: Settled land - larger cities
  • Everything dark grey: Restricted areas - Industrial, Military, Airports, ...
  • Everything pale green: Forests
  • Everything dark green: Natural reserves, parks, and golf courses.
  • Everything blue: Water.
  • Everything yellow: Larger roads, which you can still see on the smaller scales.
  • Everything orange: Highways, motorways.

Depending on your graticule, the description you would want to use may differ. But it's usually easier to fix that after the calculation.

Example

./graticount.py berlin.png
37.03%	Forests
29.14%	Fields
11.23%	Natural reserves
9.19%	Roads
6.84%	Settlements
3.84%	Highways
2.12%	Water
0.62%	Industrial

Code

It's Python. Ready for take-off.

#!/usr/bin/env python
import Image
import sys

colors = {
    (183, 205, 161): "Natural reserves",
    (183, 205, 162): "Natural reserves",
    (184, 206, 162): "Natural reserves",
    (185, 207, 163): "Natural reserves",
    (211, 215, 198): "Forests",
    (211, 215, 199): "Forests",
    (212, 215, 199): "Forests",
    (212, 216, 199): "Forests",
    (213, 217, 200): "Forests",
    (216, 208, 206): "Industrial",
    (216, 208, 207): "Industrial",
    (216, 210, 210): "Industrial",
    (218, 210, 218): "Industrial",
    (235, 224, 214): "Settlements",
    (235, 224, 215): "Settlements",
    (235, 224, 216): "Settlements",
    (235, 225, 216): "Settlements",
    (236, 225, 216): "Settlements",
    (237, 226, 217): "Settlements",
    (242, 195,  72): "Highways",
    (243, 195,  72): "Highways",
    (243, 196,  72): "Highways",
    (243, 196,  73): "Highways",
    (243, 197,  71): "Highways",
    (244, 196,  73): "Highways",
    (245, 197,  73): "Highways",
    (242, 233, 227): "Fields",
    (243, 233, 228): "Fields",
    (243, 233, 229): "Fields",
    (243, 234, 229): "Fields",
    (243, 235, 229): "Fields",
    (245, 235, 230): "Fields",
    (252, 241, 134): "Roads",
    (252, 241, 135): "Roads",
    (252, 242, 135): "Roads",
    (253, 242, 135): "Roads",
    (253, 243, 135): "Roads",
    (254, 243, 135): "Roads",
    (254, 244, 134): "Roads",
    (255, 244, 136): "Roads",
    (171, 185, 205): "Water",
    (171, 186, 206): "Water",
    (172, 185, 205): "Water",
    (172, 186, 205): "Water",
    (172, 186, 206): "Water",
    (173, 187, 207): "Water",
    (254, 132,  93): "Intracity Highways",
}

stats = {}
counts = {}
total = 0
results = []

image = Image.open(sys.argv[1])
for pixel in image.getdata():
    stats[pixel] = (pixel in stats) and stats[pixel] + 1 or 1

for pixel, count in stats.iteritems():
    if pixel[:3] in colors:
        counts[colors[pixel]] = colors[pixel] in counts and counts[colors[pixel]] + count or count

for label, count in counts.iteritems():
    total = total + count
for label, count in counts.iteritems():
    results.append((count * 100.0 / total, label))
results.sort(reverse = True)
for result in results:
    print("%.2f%%\t%s" % result)