Page 1 of 2 (27 posts)

  • talks about »
  • grass

Tags

Last update:
Tue Apr 21 08:05:06 2015

A Django site.

QGIS Planet

Routing in polygon layers? Yes we can!

A few weeks ago, the city of Vienna released a great dataset: the so-called “Flächen-Mehrzweckkarte” (FMZK) is a polygon vector layer with an amazing level of detail which contains roads, buildings, sidewalk, parking lots and much more detail:

preview of the Flächen-Mehrzweckkarte

preview of the Flächen-Mehrzweckkarte

Now, of course we can use this dataset to create gorgeous maps but wouldn’t it be great to use it for analysis? One thing that has been bugging me for a while is routing for pedestrians and how it’s still pretty bad in many situations. For example, if I’d be looking for a route from the northern to the southern side of the square in the previous screenshot, the suggestions would look something like this:

Pedestrian routing in Google Maps

Pedestrian routing in Google Maps

… Great! Google wants me to walk around it …

Pedestrian routing on openstreetmap.org

Pedestrian routing on openstreetmap.org

… Openstreetmap too – but on the other side :P

Wouldn’t it be nice if we could just cross the square? There’s no reason not to. The routing graphs of OSM and Google just don’t contain a connection. Polygon datasets like the FMZK could be a solution to the issue of routing pedestrians over squares. Here’s my first attempt using GRASS r.walk:

Routing with GRASS r.walk

Routing with GRASS r.walk (Green areas are walk-friendly, yellow/orange areas are harder to cross, and red buildings are basically impassable.)

… The route crosses the square – like any sane pedestrian would.

The key steps are:

  1. Assigning pedestrian costs to different polygon classes
  2. Rasterizing the polygons
  3. Computing a cost raster for moving using r.walk
  4. Computing the route using r.drain

I’ve been using GRASS 7 for this example. GRASS 7 is not yet compatible with QGIS but it would certainly be great to have access to this functionality from within QGIS. You can help make this happen by supporting the crowdfunding initiative for the GRASS plugin update.


Fun with docker and GRASS GIS software

GRASS GIS and dockerSometimes, we developers get reports via mailing list that this & that would not work on whatever operating system. Now what? Should we be so kind and install the operating system in question in order to reproduce the problem? Too much work… but nowadays it has become much easier to perform such tests without having the need to install a full virtual machine – thanks to docker.

Disclaimer: I don’t know much about docker yet, so take the code below with a grain of salt!

In my case I usually work on Fedora or Scientific Linux based systems. In order to quickly (i.e. roughly 10 min of automated installation on my slow laptop) try out issues of GRASS GIS 7 on e.g., Ubuntu, I can run all my tests in docker installed on my Fedora box:

# we need to run stuff as root user
su
# install docker on Fedora
yum -y docker-io
systemctl start docker
systemctl enable docker

Now we have a running docker environment. Since we want to exchange data (e.g. GIS data) with the docker container later, we prepare a shared directory beforehand:

# we'll later map /home/neteler/data/docker_tmp to /tmp within the docker container
mkdir /home/neteler/data/docker_tmp

Now we can start to install a Ubuntu docker image (may be “any” image, here we use “Ubuntu trusty” in our example). We will share the X11 display in order to be able to use the GUI as well:

# enable X11 forwarding
xhost +local:docker

# search for available docker images
docker search trusty

# fetch docker image from internet, establish shared directory and display redirect
# and launch the container along with a shell
docker run -v /data/docker_tmp:/tmp:rw -v /tmp/.X11-unix:/tmp/.X11-unix \
       -e uid=$(id -u) -e gid=$(id -g) -e DISPLAY=unix$DISPLAY \
       --name grass70trusty -i -t corbinu/docker-trusty /bin/bash

In almost no time we reach the command line of this minimalistic Ubuntu container which will carry the name “grass70trusty” in our case (btw: read more about Working with Docker Images):

root@8e0f233c3d68:/# 
# now we register the Ubuntu-GIS repos and get GRASS GIS 7.0
add-apt-repository ppa:ubuntugis/ubuntugis-unstable
add-apt-repository ppa:grass/grass-stable
apt-get update
apt-get install grass7

This will take a while (the remaining 9 minutes or so of the overall 10 minutes).

Since I like cursor support on the command line, I launch (again?) the bash in the container session:

root@8e0f233c3d68:/# bash
# yes, we are in Ubuntu here
root@8e0f233c3d68:/# cat /etc/issue

Now we can start to use GRASS GIS 7, even with its graphical user interface from inside the docker container:

# create a directory for our data, it is mapped to /home/neteler/data/docker_tmp/
# on the host machine 
root@8e0f233c3d68:/# mkdir /tmp/grassdata
# create a new LatLong location from EPSG code
# (or copy a location into /home/neteler/data/docker_tmp/)
root@8e0f233c3d68:/# grass70 -c epsg:4326 ~/grassdata/latlong_wgs84
# generate some data to play with
root@8e0f233c3d68:/# v.random n=30 output=random30
# start the GUI manually (since we didn't start GRASS GIS right away with it before)
root@8e0f233c3d68:/# g.gui

Indeed, the GUI comes up as expected!

GRASS GIS 7 GUI in docker container

GRASS GIS 7 GUI in docker container

You may now perform all tests, bugfixes, whatever you like and leave the GRASS GIS session as usual.
To get out of the docker session:

root@8e0f233c3d68:/# exit    # leave the extra bash shell
root@8e0f233c3d68:/# exit    # leave docker session

# disable docker connections to the X server
[root@oboe neteler]# xhost -local:docker

To restart this session later again, you will call it with the name which we have earlier assigned:

[root@oboe neteler]# docker ps -a
# ... you should see "grass70trusty" in the output in the right column

# we are lazy and automate the start a bit
[root@oboe neteler]# GRASSDOCKER_ID=`docker ps -a | grep grass70trusty | cut -d' ' -f1`
[root@oboe neteler]# echo $GRASSDOCKER_ID 
[root@oboe neteler]# xhost +local:docker
[root@oboe neteler]# docker start -a -i $GRASSDOCKER_ID

### ... and so on as described above.

Enjoy.

The post Fun with docker and GRASS GIS software appeared first on GFOSS Blog | GRASS GIS Courses.

GRASS GIS 6.4.5RC1 released

GRASS GIS logoAfter months of development a first release candidate of GRASS GIS 6.4.5 is now available. This is a stability release of the GRASS GIS 6 line.

Source code download:
http://grass.osgeo.org/grass64/source/
http://grass.osgeo.org/grass64/source/grass-6.4.5RC1.tar.gz

Binaries download:
http://grass.osgeo.org/download/software/#g64x

To get the GRASS GIS 6.4.5RC1 source code directly from SVN:
svn checkout http://svn.osgeo.org/grass/grass/tags/release_20150406_grass_6_4_5RC1

Key improvements:
Key improvements of the GRASS GIS 6.4.5RC1 release include stability fixes (esp. vector library), some fixes for wxPython3 support, some module fixes, and more message translations.

See also our detailed announcement:
http://trac.osgeo.org/grass/wiki/Release/6.4.5RC1-News

First time users should explore the first steps tutorial after installation:
http://grasswiki.osgeo.org/wiki/Quick_wxGUI_tutorial

Release candidate management at
http://trac.osgeo.org/grass/wiki/Grass6Planning

Please join us in testing this release candidate for the final release.

Consider to donate pizza or beer for the next GRASS GIS Community Sprint (following the FOSS4G Europe 2015 in Como):
http://grass.osgeo.org/donations/

Thanks to all contributors!

About GRASS GIS

The Geographic Resources Analysis Support System (http://grass.osgeo.org), commonly referred to as GRASS GIS, is an Open Source Geographic Information System providing powerful raster, vector and geospatial processing capabilities in a single integrated software suite. GRASS GIS includes tools for spatial modeling, visualization of raster and vector data, management and analysis of geospatial data, and the processing of satellite and aerial imagery. It also provides the capability to produce sophisticated presentation graphics and hardcopy maps. GRASS GIS has been translated into about twenty languages and supports a huge array of data formats. It can be used either as a stand-alone application or as backend for other software packages such as QGIS and R geostatistics. It is distributed freely under the terms of the GNU General Public License (GPL). GRASS GIS is a founding member of the Open Source Geospatial Foundation (OSGeo).

The GRASS Development Team, April 2015

The post GRASS GIS 6.4.5RC1 released appeared first on GFOSS Blog | GRASS GIS Courses.

Computing network centers

How do you objectively define and compute which parts of a network are in the center? One approach is to use the concept of centrality.

Centrality refers to indicators which identify the most important vertices within a graph. Applications include identifying the most influential person(s) in a social network, key infrastructure nodes in the Internet or urban networks, and super spreaders of disease. (Source: http://en.wikipedia.org/wiki/Centrality)

Researching this topic, it turns out that some centrality measures have already been implemented in GRASS GIS. thumbs up!

v.net.centrality computes degree, betweeness, closeness and eigenvector centrality.

As a test, I’ve loaded the OSM street network of Vienna and run

v.net.centrality -a input=streets@anita_000 output=centrality degree=degree closeness=closeness betweenness=betweenness eigenvector=eigenvector

grass_centrality

The computations take a while.

In my opinion, the most interesting centrality measures for this street network are closeness and betweenness:

Closeness “measures to which extent a node i is near to all the other nodes along the shortest paths”. Closeness values are lowest in the center of the network and higher in the outskirts.

Betweenness “is based on the idea that a node is central if it lies between many other nodes, in the sense that it is traversed by many of the shortest paths connecting couples of nodes.” Betweenness values are highest on bridges and other important arterials while they are lowest for dead-end streets.

(Definitions as described in more detail in Crucitti, Paolo, Vito Latora, and Sergio Porta. “Centrality measures in spatial networks of urban streets.” Physical Review E 73.3 (2006): 036125.)

Centrality: low values in pink, high values in green

Centrality: low values in pink, high values in green

Works great! Unfortunately, v.net.centrality is not yet part of the QGIS Processing GRASS toolbox. It would certainly be a great addition.


New stable release of GRASS GIS 7.0.0!

The GRASS GIS Development team has announced the release of the new major version GRASS GIS 7.0.0. This version provides many new functionalities including spatio-temporal database support, image segmentation, estimation of evapotranspiration and emissivity from satellite imagery, automatic line vertex densification during reprojection, more LIDAR support and a strongly improved graphical user interface experience. GRASS GIS 7.0.0 also offers significantly improved performance for many raster and vector modules: “Many processes that would take hours now take less than a minute, even on my small laptop!” explains Markus Neteler, the coordinator of the development team composed of academics and GIS professionals from around the world. The software is available for Linux, MS-Windows, Mac OSX and other operating systems.

Detailed announcement and software download:
http://grass.osgeo.org/news/42/15/GRASS-GIS-7-0-0/

About GRASS GIS
The Geographic Resources Analysis Support System (http://grass.osgeo.org/), commonly referred to as GRASS GIS, is an open source Geographic Information System providing powerful raster, vector and geospatial processing capabilities in a single integrated software suite. GRASS GIS includes tools for spatial modeling, visualization of raster and vector data, management and analysis of geospatial data, and the processing of satellite and aerial imagery. It also provides the capability to produce sophisticated presentation graphics and hardcopy maps. GRASS GIS has been translated into about twenty languages and supports a huge array of data formats. It can be used either as a stand-alone application or as backend for other software packages such as QGIS and R geostatistics. It is distributed freely under the terms of the GNU General Public License (GPL). GRASS GIS is a founding member of the Open Source Geospatial Foundation (OSGeo).

The post New stable release of GRASS GIS 7.0.0! appeared first on GFOSS Blog | GRASS GIS Courses.

GRASS GIS 7: Vector data reprojection with automated vertex densification

GRASS GIS 7 just got better: When reprojecting vector data, now automated vertex densification is applied. This reduces the reprojection error for long lines (or polygon boundaries). The needed improvement has been kindly added in v.proj by Markus Metz.

1. Example

As an (extreme?) example, we generate a box in LatLong/WGS84 (EPSG: 4326) which is of 10 degree side length (see below for screenshot and at bottom for SHAPE file download of this “box” map):

[neteler@oboe ~]$ grass70 ~/grassdata/latlong/grass7/
# for the ease of generating the box, set computational region:
g.region n=60 s=40 w=0 e=30 res=10 -p
projection: 3 (Latitude-Longitude)
zone:       0
datum:      wgs84
ellipsoid:  wgs84
north:      60N
south:      40N
west:       0
east:       30E
nsres:      10
ewres:      10
rows:       2
cols:       3
cells:      6
# generate the box according to current computational region:
v.in.region box_latlong_10deg
exit

Next we start GRASS GIS in a metric projection, here the EU LAEA:

# EPSG 3035, metric EU LAEA:
grass70 ~/grassdata/europe_laea/user1/
GRASS 7.0.0svn (europe_laea): >

Now we first reproject the map the “traditional way” (no vertex densification as in most GIS, here enforced by smax=0):

v.proj box_latlong_10deg out=box_latlong_10deg_no_densification
location=latlong mapset=grass7 smax=0

Then we do a second reprojection with new automated vertex densification (here we use the default values for smax which is a 10km vertex distance in the reprojected map by default):

v.proj box_latlong_10deg out=box_latlong_10deg_yes_densification
location=latlong mapset=grass7

Eventually we can compare both reprojected maps:

g.region vect=box_latlong_10deg_no_densification

# compare:
d.mon wx0
d.vect box_latlong_10deg_no_densification color=red
d.vect box_latlong_10deg_yes_densification color=green fill_color=none
Comparison of the reprojection of a 10 degree large LatLong box to the metric EU LAEA (EPSG 3035): before in red and new in green. The grid is based on WGS84 at 5 degree spacing.

Comparison of the reprojection of a 10 degree large LatLong box to the metric EU LAEA (EPSG 3035): before in red and new in green. The grid is based on WGS84 at 5 degree spacing.

The result shows how nicely the projection is now performed in GRASS GIS 7: the red line output is old, the green color line is the new output (its area filling is not shown).

Consider to benchmark this with other GIS… the reprojected map should not become a simple trapezoid.

2. Sample dataset download

Download of box_latlong_10deg.shp for own tests (1kB).

The post GRASS GIS 7: Vector data reprojection with automated vertex densification appeared first on GFOSS Blog | GRASS GIS Courses.

Landsat 8 captures Trentino in November 2014

The beautiful days in early November 2014 allowed to get some nice views of the Trentino (Northern Italy) – thanks to Landsat 8 and NASA’s open data policy:

Landsat 8: Northern Italy 1 Nov 2014
Landsat 8: Northern Italy 1 Nov 2014

Trento captured by Landsat8
Trento captured by Landsat8

Landsat 8: San Michele - 1 Nov 2014
Landsat 8: San Michele – 1 Nov 2014

The beauty of the landscape but also the human impact (landscape and condensation trails of airplanes) are clearly visible.

All data were processed in GRASS GIS 7 and pansharpened with i.fusion.hpf written by Nikos Alexandris.

The post Landsat 8 captures Trentino in November 2014 appeared first on GFOSS Blog | GRASS GIS Courses.

Selective data removal in an elevation map by means of floodfilling

Do you also sometimes get maps which contain zero (0) rather than NULL (no data) in some parts of the map? This can be easily solved with “floodfilling”, even in a GIS.

My original map looks like this (here, Trentino elevation model):

The light blue parts should be no data (NULL) rather than zero (0)...

Now what? In a paint software we would simply use bucket fill but what about GIS data? Well, we can do something similar using “clumping”. It requires a bit of computational time but works perfectly, even for large DEMs, e.g., all Italy at 20m resolution. Using the open source software GRASS GIS 7, we can compute all “clumps” (that are many for a floating point DEM!):

# first we set the computational region to the raster map:
g.region rast=pat_DTM_2008_derived_2m -p
r.clump pat_DTM_2008_derived_2m out=pat_DTM_2008_derived_2m_clump

The resulting clump map produced by r.clump is nicely colorized:

Clumped map derived from DEM (generated with r.clump)

As we can see, the area of interest (province) is now surrounded by three clumps. With a simple map algebra statement (r.mapcalc or GUI calculator) we can create a MASK by assigning these outer boundary clumps to NULL and the other “good” clumps to 1:

r.mapcalc "no_data_mask = if(pat_DTM_2008_derived_2m_clump == 264485050 || \
   pat_DTM_2008_derived_2m_clump == 197926480 || \
   pat_DTM_2008_derived_2m_clump == 3, null(), 1)"

This mask map looks like this:

Mask map from all clumps except for the large outer clumps

We now activate this MASK and generate a copy of the original map into a new map name by using map algebra again (this just keeps the data matched by the MASK). Eventually we remove the MASK and verify the result:

# apply the mask
r.mask no_data_mask
# generate a copy of the DEM, filter on the fly
r.mapcalc "pat_DTM_2008_derived_2m_fixed = pat_DTM_2008_derived_2m"
# assign a nice color table
r.colors pat_DTM_2008_derived_2m_fixed color=srtmplus
# remove the MASK
r.mask -r

And the final DEM is now properly cleaned up in terms of NULL values (no data):

DEM cleaned up for no data

Enjoy.

The post Selective data removal in an elevation map by means of floodfilling appeared first on GFOSS Blog | GRASS GIS Courses.

Rendering a brain CT scan in 3D with GRASS GIS 7

brainscan1Last year (2013) I “enjoyed” a brain CT scan in order to identify a post-surgery issue – luckily nothing found. Being in Italy, like all patients I received a CD-ROM with the scan data on it: so, something to play with! In this article I’ll show how to easily turn 2D scan data into a volumetric (voxel) visualization.

The CT scan data come in a DICOM format which ImageMagick is able to read and convert. Knowing that, we furthermore need the open source software packages GRASS GIS 7 and Paraview to get the job done.

First of all, we create a new XY (unprojected) GRASS location to import the data into:

# create a new, empty location (or use the Location wizard):
grass70 -c ~/grassdata/brain_ct

We now start GRASS GIS 7 with that location. After mounting the CD-ROM we navigate into the image directory therein. The directory name depends on the type of CT scanner which was used in the hospital. The file name suffix may be .IMA.

Now we count the number of images, convert and import them into GRASS GIS:

# list and count
LIST=`ls -1 *.IMA`
MAX=`echo $LIST | wc -w`

# import into XY location:
curr=1
for i in $LIST ; do

# pretty print the numbers to 000X for easier looping:
curr=`echo $curr | awk ‘{printf “%04d\n”, $1}’`
convert “$i” brain.$curr.png
r.in.gdal in=brain.$curr.png out=brain.$curr
r.null brain.$curr setnull=0
rm -f brain.$curr.png
curr=`expr $curr + 1`

done

At this point all CT slices are imported in an ordered way. For extra fun, we can animate the 2D slices in g.gui.animation:

Animation of brain scan slices
(click to enlarge)

# enter in one line:
g.gui.animation rast=`g.mlist -e rast separator=comma pattern=”brain*”`

The tool allows to export as animated GIF or AVI:

Animation of brain scan slices (click to enlarge)

Now it is time to generate a volume:

# first count number of available layers
g.mlist rast pat=”brain*” | wc -l

# now set 3D region to number of available layers (as number of depths)
g.region rast=brain.0003 b=1 t=$MAX -p3

At this point the computational region is properly defined to our 3D raster space. Time to convert the 2D slices into voxels by stacking them on top of each other:

# convert 2D slices to 3D slices:
r.to.rast3 `g.mlist rast pat=”brain*” sep=,` out=brain_vol

We can now look at the volume with GRASS GIS’ wxNVIZ or preferably the extremely powerful Paraview. The latter requires an export of the volume to VTK format:

# fetch some environment variables
eval `g.gisenv -s`
# export GRASS voxels to VTK 3D as 3D points, with scaled z values:
SCALE=2
g.message “Exporting to VTK format, scale factor: $SCALE”
r3.out.vtk brain_vol dp=2 elevscale=$SCALE \
output=${PREFIX}_${MAPSET}_brain_vol_scaled${SCALE}.vtk -p

Eventually we can open this new VTK file in Paraview for visual exploration:

# show as volume
# In Paraview: Properties: Apply; Display Repres: volume; etc.
paraview –data=brain_s1_vol_scaled2.vtk

markus_brain_ct_scan3 markus_brain_ct_scan4 markus_brain_ct_scan2

 

 

 

 

 

 

 

 

 

 

 

 

Fairly easy!

BTW: I have a scan of my non-smoker lungs as well :-)

The post Rendering a brain CT scan in 3D with GRASS GIS 7 appeared first on GFOSS Blog | GRASS GIS Courses.

Workshop at FOSS4G 2014: Spatio-temporal data handling and visualization in GRASS GIS 7

Drowning in too many maps? Have some fun exploring fascinating geometries of changing landscapes in Space Time Cube and creating 2D and 3D animations from time series of geospatial data. Learn about the new capabilities for spatio-temporal data handling in GRASS GIS 7 (http://grass.osgeo.org/grass7/) and explore various techniques for dynamic visualizations.

First, we will introduce you to GRASS GIS 7, including its spatio-temporal capabilities and you will learn how to manage and analyze geospatial data time series. Then, we will explore new tools for visualization of spatio-temporal data. You will create both 2D and 3D dynamic visualizations directly in GRASS GIS 7. Additionally, we will explain the Space Time Cube concept using various applications based on raster and vector data time series. You will learn to manage and visualize data in space time cubes (voxel models). No prior knowledge of GRASS GIS is necessary, we will cover the basics needed for the workshop. All relevant material including an overview of the tools and hands-on practical instructions along with the sample data sets will be available on-line. And, by the way, GRASS GIS is a free and open source geographic information system (GIS) used for geospatial data management, analysis, modeling, image processing, and visualization which runs on Linux, MS Windows, Mac OS X and other systems.

Presenters: Vaclav Petras, Anna Petrasova, Helena Mitasova, Markus Neteler

When:  FOSS4G 2014, Sept 8th-13th 2014, Portland, OR, USA

Register at: https://2014.foss4g.org/schedule/workshops/#wshop-526

The post Workshop at FOSS4G 2014: Spatio-temporal data handling and visualization in GRASS GIS 7 appeared first on GFOSS Blog | GRASS GIS Courses.

OSGeo Code Sprint, Vienna

This is how OSGeo happens.  These are the folk who bring us a lot of that open-source geo-spatial goodness. You can follow the code sprint on Twitter using the hashtags #csprint and #viennacodesprint14

 


Will the sun shine on us?

Recently, in order to nicely plan ahead for a birthday lunch at the agritur Malga Brigolina (a farm-restaurant near Sopramonte di Trento, Italy, at 1,000m a.s.l. in the Southern Alps), friends of mine asked me the day before:

Will the place be sunny at lunch time for a nice walk?

[well, the weather was close to clear sky conditions but mountains are high here and casting long shadows in the winter time].

paganella_rotaliana

A rather easy task I thought, so I got my tools ready since that was an occasion to verify the predictions with some photos! Thanks to the new EU-DEM at 25m I was able to perform the computations right away in a metric system rather than dealing with degree in LatLong.

Direct sunlight can be assessed from the beam radiation map of GRASS GIS’ r.sun when running it for a specific day and time. But even easier, there is a new Addon for GRASS GIS 7 which calculates right away time series of insolation maps given start/stop timestamps and a time step: r.sun.hourly. This shrinks the overall effort to almost nothing.

1. Creating the direct sunlight maps

The first step is to calculate where direct sunlight reaches the ground. Here the input elevation map is the European “eu_dem_25″, while the output is the beam radiation for a certain day (15 Dec 2013 is DOY 349).

Important hint: the computational region must be large enough to east/south/west to capure the cast shadow effects of all relevant surrounding mountains.

I let calculations start at 8am and finish at 5pm which an hourly time step. The authors have kindly parallelized r.sun.hourly, so I let it run on four processors simultaneously to speed up:

# calculate DOY (day-of-year) from given date:
date -d 2013-12-15 +%j
349

# calculate beam radiation maps for a given time period
# (note: minutes are to be given in decimal time: 30min = 0.5)
r.sun.hourly elev_in=eu_dem_25 beam_rad=trento_beam_doy349 \
      start_time=8 end_time=17 time_step=1 day=349 year=2013 \
      nprocs=4

The ten resulting maps contain the beam radiation for each pixel considering the cast shadow effects of the pixel-surrounding mountains. However, the question was not to calculate irradiance raster maps in Wh/m^2 but simply “sun-yes” or “sun-no”. So a subsequent filtering had to be applied. Each beam radiation map was filtered: if pixel value equal to 0 then “sun-no”, otherwise “sun-yes” (what my friends wanted to achieve; effectively a conversion into a binary map).
Best done in a simple shell script loop:

[Edit 30 Dec 2013: thanks to Anna you can simplify below loop to the r.colors call thanks to the new -b flag for binary output in r.sun.hourly!]

for map in `g.mlist rast pattern="trento_beam_doy349*"` ; do
    # rename current map to tmp
    g.rename rast=$map,$map.tmp
    # filter and save with original name
    r.mapcalc "$map = if($map.tmp == 0, null(), 1)"
    # colorize the binary map
    echo "1 yellow" | r.colors $map rules=-
    # remove cruft
    g.remove rast=$map.tmp
done

As a result we got ten binary maps, ideal for using them as overlay with shaded DEMs or OpenStreetMap layers. The areas exposed to direct sunlight are shown in yellow.

Trento direct sunlight 15 Dec 2013 Animation

Trento, direct sunlight, 15 Dec 2013 between 10am and 5pm (See here for creating an animated GIF). Quality reduced for this blog.

2. Time to look at some details: So, is Malga Brigolina in sunlight at lunch time?

Situation at 12pm (noon): predicted that the restaurant is still in shadow – confirmed in the photo:

malga_brigolina_direct_sunlight_15dec2013_12pm_foto

(click to enlarge)

Situation at 1:30/2:00pm: sun is getting closer to the Malga, as confirmed in photo (note that the left photo is 20min ahead of the map). The small street in the right photo is still in the shadow as predicted in the map):

malga_brigolina_direct_sunlight_15dec2013_14pm_foto(click to enlarge)

Situation at 3:00pm: sun here and there at Malga Brigolina:

malga_brigolina_direct_sunlight_15dec2013_15pm_3DSunlight map blended with OpenStreetmap layer (r.blend + r.composite) and draped over DEM in wxNVIZ of GRASS GIS 7 (click to enlarge). The sunday walk path around Malga Brigolina is the blue/red vector line shown in the view center.

Situation at 4:00pm: we are close to sunset in Trentino… view towards the Rotaliana (Mezzocorona, S. Michele all’Adige), last sunlit summits also seen in photo:

rotaliana_direct_sunlight_15dec2013_16pm_foto(click to enlarge)

3. Outcome

The resulting sunlight/shadow map appear to match nicely realty. Perhaps r.sun.hourly should get an additional flag to generate the binary “sun-yes” – “sun-no” maps directly.

trento_direct_sunlight_15dec2013_15pm_3DDirect sunlight zones (yellow, 15 Dec 2013, 3pm): Trento with Monte Bondone, Paganella, Marzolan, Lago di Caldonazzo, Lago di Levico and surroundings (click to enlarge)

4. GRASS GIS usage note

The wxGUI settings were as simple as this (note the transparency values for the various layers):

trento_direct_sunlight_wxGUI

Data sources:

The post Will the sun shine on us? appeared first on GFOSS Blog | GRASS GIS Courses.

Video: GRASS GIS development visualization from 1999 to 2013

Watch how the community based GRASS GIS 6.4 software development evolved! You can see how the individual contributors modify and expand the source code:

  • Dec 29, 1999: GRASS GIS 5.0 is being stored in an online source code repository in December 1999…
  • Dec 02, 2000: The developers work on all parts of the code…
  • Jan 15, 2002: Working on the future GRASS GIS 5.1 release
  • Nov 25, 2002: Starting GRASS 5.1 development with code restructuring
  • Jun 14, 2004: GRASS GIS 5.7 released in June 2004
  • Nov 09, 2004: Source code restructuring to get a better directory layout (all other developers waiting…)
  • Nov 09, 2004: … thousands of files are modified in this operation …
  • Nov 10, 2004: All developers resume their activities after the restructuring
  • Jan 10, 2005: Preparing the GRASS GIS 6.0.0 release…
  • Apr 09, 2005: GRASS GIS 6.0.0 published, release branch being split off from trunk for easier maintenance
  • Feb 22, 2006: Release of GRASS GIS 6.0.2 and new source code refactoring startedApr 05, 2006: Heavy development activity in trunk (development branch) …
  • Oct 25, 2006: GRASS GIS 6.2.0 released in October 2006
  • Apr 10, 2007: Preparing the GRASS GIS 6.2.2 release…
  • Jun 16, 2007: GRASS GIS 6.2.2 released in June 2007
  • Nov 01, 2007: Raster and vector modules being actively maintained…
  • Apr 02, 2007: New graphical user interface development speeding up (wxGUI)
  • Feb 20, 2008: Copyright statements prettified in many files
  • May 31, 2008: New GRASS 6 development branch being split off from trunk (which becomes GRASS 7)
  • Jun 10, 2008: Developers moving over to new branch
  • Feb 23, 2009: GRASS 6.4 release branch split off from GRASS 6 development branch
  • Apr 03, 2009: GRASS GIS 6.4 preparations starting…
  • Feb 24, 2010: Intense maintenance in GRASS 6.4 release branch
  • Sep 15, 2010: GRASS GIS 6.4.0 released in September 2010
  • Apr 12, 2011: GRASS GIS 6.4.1 released in April 2011
  • Jun 27, 2011: GRASS GIS 6.4.svn matures for the upcoming 6.4.2 release
  • Aug 16, 2011: Intense maintenance in GRASS 6.4 release branch (GRASS GIS 7 development not shown here)…
  • Feb 19, 2012: GRASS GIS 6.4.2 released in February 2012
  • Nov 13, 2012: Backporting graphical user interface bugfixes from GRASS GIS 7 to GRASS GIS 6.4
  • Apr 17, 2013: Further maintenance in GRASS 6.4 release branch
  • Jul 10, 2013: Fixing odds ‘n ends for the new stable release
  • Jul 27, 2013: GRASS GIS 6.4.3 released in July 2013

The corresponding timeline is also available at
http://grass.osgeo.org/home/history/releases/

THANKS TO ALL CONTRIBUTORS!
http://grass.osgeo.org/development/

Rendering: Markus Neteler
Audio track editing: Duccio Rocchini & Antonio Galea

Music:
Le bruit peut rendre sourd – Track 6/18 Album “Sensation electronique” by Saelynh (CC-BY-NC-ND) http://www.jamendo.com/en/track/1236/le-bruit-peut-rendre-sourd

Software used:
Gource software: http://code.google.com/p/gource/ (GPL)
OpenShot video editor: http://www.openshotvideo.com/ (GPL

The post Video: GRASS GIS development visualization from 1999 to 2013 appeared first on GFOSS Blog | GRASS GIS Courses.

Using the 25m EU-DEM for shading OpenStreetMap layers

Inspired by Václav Petráš posting about “Did you know that you can see streets of downtown Raleigh in elevation data from NC sample dataset?” I wanted to try the new GRASS GIS 7 Addon r.shaded.pca which creates shades from various directions and combines then into RGB composites just to see what happens when using the new EU-DEM at 25m.

To warm up, I registered the “normally” shaded DEM (previously generated with gdaldem) with r.external in a GRASS GIS 7 location (EPSG 3035, LAEA) and overlayed the OpenStreetMap layer using WMS with GRASS 7′s r.in.wms. An easy task thanks to University of Heidelberg’s www.osm-wms.de. Indeed, they offer a similar shading via WMS, however, in the screenshot below you see the new EU data being used for controlling the light on our own:

OpenStreetMap shaded with EU DEM 25m

OpenStreetMap shaded with EU DEM 25m (click to enlarge)

Next item: trying r.shaded.pca… It supports multi-core calculation and the possibility to strengthen the effects through z-rescaling. In my example, I used:

r.shaded.pca input=eu_dem_25 output=eu_dem_25_shaded_pca nproc=3 zmult=50

The leads to a colorized hillshading map, again with the OSM data on top (50% transparency):

eu_dem_25m_PCA_shaded_OSM_trento_rovereto_garda_lake

OpenStreetMap shaded with r.shaded.pca using EU DEM 25m (click to enlarge)

Yes, fun – I like it :-)

Data sources:

The post Using the 25m EU-DEM for shading OpenStreetMap layers appeared first on GFOSS Blog | GRASS GIS Courses.

News in GRASS GIS 7

GRASS GIS, commonly referred to as GRASS (Geographic Resources Analysis Support System), is the free Geographic Information System (GIS) software with the longest record of development as FOSS4G community project. The increasing demand for a robust and modern analytical free GIS led to the start of GRASS GIS 7 development in April 2008. Since GRASS 6 more than 10,000 changes have been implemented with a series of new modules for vector network analysis, image processing, voxel analysis, time series management and improved graphical user interface. The core system offers a new Python API and large file support for massive data analysis. Many modules have been undergone major optimization also in terms of speed. The presentation will highlight the advantages for users to migrate to the upcoming GRASS GIS 7 release.

The post News in GRASS GIS 7 appeared first on GFOSS Blog | GRASS GIS Courses.

50th ICA-OSGeo Lab established at Fondazione Edmund Mach (FEM)

We are pleased to announce that the 50th ICA-OSGeo Lab has been established at the GIS and Remote Sensing Unit (Piattaforma GIS & Remote Sensing, PGIS), Research and Innovation Centre (CRI), Fondazione Edmund Mach (FEM), Italy. CRI is a multifaceted research organization established in 2008 under the umbrella of FEM, a private research foundation funded by the government of Autonomous Province of Trento. CRI focuses on studies and innovations in the fields of agriculture, nutrition, and environment, with the aim to generate new sharing knowledge and to contribute to economic growth, social development and the overall improvement of quality of life.

The mission of the PGIS unit is to develop and provide multi-scale approaches for the description of 2-, 3- and 4-dimensional biological systems and processes. Core activities of the unit include acquisition, processing and validation of geo-physical, ecological and spatial datasets collected within various research projects and monitoring activities, along with advanced scientific analysis and data management. These studies involve multi-decadal change analysis of various ecological and physical parameters from continental to landscape level using satellite imagery and other climatic layers. The lab focuses on the geostatistical analysis of such information layers, the creation and processing of indicators, and the production of ecological, landscape genetics, eco-epidemiological and physiological models. The team pursues actively the development of innovative methods and their implementation in a GIS framework including the time series analysis of proximal and remote sensing data.

The GIS and Remote Sensing Unit (PGIS) members strongly support the peer reviewed approach of Free and Open Source software development which is perfectly in line with academic research. PGIS contributes extensively to the open source software development in geospatial (main contributors to GRASS GIS), often collaborating with various other developers and researchers around the globe. In the new ICA-OSGeo lab at FEM international PhD students, university students and trainees are present.

PGIS is focused on knowledge dissemination of open source tools through a series of courses designed for specific user requirement (schools, universities, research institutes), blogs, workshops and conferences. Their recent publication in Trends in Ecology and Evolution underlines the need on using Free and Open Source Software (FOSS) for completely open science. Dr. Markus Neteler, who is leading the group since its formation, has two decades of experience in developing and promoting open source GIS software. Being founding member of the Open Source Geospatial Foundation (OSGeo.org, USA), he served on its board of directors from 2006-2011. Luca Delucchi, focal point and responsible person for the new ICA-OSGeo Lab is member of the board of directors of the Associazione Italiana per l’Informazione Geografica Libera (GFOSS.it, the Italian Local Chapter of OSGeo). He contributes to several Free and Open Source software and open data projects as developer and trainer.

Details about the GIS and Remote Sensing Unit at http://gis.cri.fmach.it/

Open Source Geospatial Foundation (OSGeo) is a not-for-profit organisation founded in 2006 whose mission is to support and promote the collaborative development of open source geospatial technologies and data.

International Cartographic Association (ICA) is the world authoritative body for cartography and GIScience. See also the new ICA-OSGeo Labs website.

Processing Landsat 8 data in GRASS GIS 7: RGB composites and pan sharpening

banner_pansharpening

In our first posting (“Processing Landsat 8 data in GRASS GIS 7: Import and visualization“) we imported a Landsat 8 scene (covering Raleigh, NC, USA). In this exercise we use Landsat data converted to reflectance with i.landsat.toar as shown in the first posting.

Here we will try color balancing and pan-sharpening, i.e. applying the higher resolution panchromatic channel to the color channels, using i.landsat.rgb.

1. Landsat 8 – RGB color balancing: natural color composites

After import, the RGB (bands 4,3,2 for Landsat 8) may look initially less exciting than expected.This is easy to fix by a histogram based auto-balancing of the RGB color tables.

landsat8_rgb_composite_unbalanced

To brighten up the RGB composite, we can use the color balancing tool of GRASS GIS 7:

grass7_landsat_rgb0

As input, we specify the bands 4, 3, and 2:

grass7_landsat_rgb1

Using a “Cropping intensity (upper brightness level)” of 99 (percent), the result look as follows:

landsat10_rgb_composite_autobalance_99percent_crop

For special purposes or under certain atmospheric/ground conditions it may be useful to make use of the functions “Preserve relative colors, adjust brightness only” or “Extend colors to full range of data on each channel” in the “Optional” tab of i.landsat.rgb.

landsat9_rgb_composite_preserve_relative_colors

You will need to experiment since the results depend directly on the image data.

2. Landsat 8 pansharpening

Pansharpening is a technique to merge the higher geometrical pixel resolution of the panchromatic band (Band 8) with the lower resolution color bands (Bands 4, 3, 2).

GRASS GIS 7 offers several methods through the command i.pansharpen.

1) Brovey transform:

landsat8_pansharpen_brovey1

This module runs in multi-core mode parallelized. The management of the resolution (i.e., apply the higher resolution of the panchromatic band) is performed automatically.

landsat8_pansharpen_brovey2

2. IHS transform

Here we select as above the bands in the i.pansharpen interface but use the “ihs” method.

landsat8_pansharpen_ihs1

HINT: If the colors should look odd, then apply i.landsat.rgb to the pan-sharpened bands (see above).

Color-adjusted IHS pansharpening (with “Cropping intensity: strength=99″):

landsat8_pansharpen_ihs_color_adjusted

Comparison of Landsat 8 RGB composite (39m) and IHS pansharpened RGB composite (15m):

landsat8_rgb432_color_adjusted_zoom landsat8_rgb432_pansharpen_ihs_color_adjusted_zoom

3. PCA transform

Here we select as above the bands in the i.pansharpen interface but use the “pca” method.

landsat8_pansharpen_pca1

Likewise other channels may be merged with i.pansharpen, even when originating from different sensors.

3. Conclusions

Overall, the IHS pansharpening method along with auto-balancing of colors appears to perform very well with Landsat 8.

Processing Landsat 8 data in GRASS GIS 7: Import and visualization

banner_landsat_rgb

For our analysis example, we’ll obtain (freely – thanks, NASA and USGS!) a Landsat 8 scene from http://earthexplorer.usgs.gov/

First of all, you should register.

1. Landsat 8 download procedure

1. Enter Search Criteria:

  • path/row tab, enter Type WRS2: Path: 16, Row: 35
  • Date range: 01/01/2013 – today
  • Click on the “Data sets >>” button

2. Select Your Data Set(s):

  • Expand the entry + Landsat Archive
        [x] L8 OLI/TIRS
  • Click on the “Results >>” button

(We jump over the additional criteria)

4. Search Results

From the resulting list, we pick the data set:

earthexplorer_selection_lsat8Entity ID: LC80160352013134LGN03
Coordinates: 36.04321,-79.28696
Acquisition Date: 14-MAY-13

Using the “Download options”, you can download the data set (requires login). Select the choice:
[x] Level 1 GeoTIFF Data Product (842.4 MB)

You will receive the file “LC80160352013134LGN03.tar.gz”.

2. Unpacking the downloaded Landsat 8 dataset

To unpack the data, run (or use a graphical tool at your choice):

tar xvfz LC80160352013134LGN03.tar.gz

A series of GeoTIFF files will be extracted: LC80160352013134LGN03_B1.TIF, LC80160352013134LGN03_B2.TIF, LC80160352013134LGN03_B3.TIF, LC80160352013134LGN03_B4.TIF, LC80160352013134LGN03_B5.TIF, LC80160352013134LGN03_B6.TIF, LC80160352013134LGN03_B7.TIF, LC80160352013134LGN03_B8.TIF, LC80160352013134LGN03_B9.TIF, LC80160352013134LGN03_B10.TIF, LC80160352013134LGN03_B11.TIF, LC80160352013134LGN03_BQA.TIF

We may check the metadata with “gdalinfo“:

gdalinfo LC80160352013134LGN03_B1.TIF
Driver: GTiff/GeoTIFF
Files: LC80160352013134LGN03_B1.TIF
Size is 7531, 7331
Coordinate System is:
PROJCS["WGS 84 / UTM zone 17N",
    GEOGCS["WGS 84",
        DATUM["WGS_1984",
            SPHEROID["WGS 84",6378137,298.257223563,
...
Pixel Size = (30.000000000000000,-30.000000000000000)
...

3. Want to spatially subset the Landsat scene first?

If you prefer to cut out a smaller area (subregion), check here for gdal_translate usage examples.

4. Import into GRASS GIS 7

Note: While this Landsat 8 scene covers the area of the North Carolina (NC) sample dataset, it is delivered in UTM rather than the NC's state plane metric projection. Hence we preprocess the data first in its original UTM projection prior to the reprojection to NC SPM.

Using the Location Wizard, we can import the dataset easily into a new location (in case you don't have UTM17N not already created earlier):

grass70 -gui

grass7_loc_wizard1
grass7_loc_wizard2
grass7_loc_wizard3
grass7_loc_wizard4
grass7_loc_wizard5
grass7_loc_wizard6
grass7_loc_wizard7
grass7_loc_wizard8
grass7_loc_wizard9

 

 

 

Now start GRASS GIS 7 and you will find the first band already imported (the others will follow shortly!).

For the lazy folks among us, we can also create a new GRASS GIS Location right away from the dataset on command line:

grass70 -c LC80160352013134LGN03_B10.TIF ~/grassdata/utm17n

5. Importing the remaining Landsat 8 bands

The remaining bands can be easily imported with the raster import tool:

grass7_import1

The bands can now be selected easily for import:

grass7_import2

  • Select "Directory" and navigate to the right one
  • The available GeoTIFF files will be shown automatically
  • Select those you want to import
  • You may rename (double-click) the target name for each band
  • Extend the computation region accordingly automatically

Click on "Import" to get the data into the GRASS GIS location. This takes a few minutes. Close the dialog window then.

In the "Map layers" tab you can select the bands to be shown:

grass7_visualize1

6. The bands of Landsat 8

(cited from USGS)

Landsat 8 Operational Land Imager (OLI) and Thermal Infrared Sensor (TIRS) images consist of nine spectral bands with a spatial resolution of 30 meters for Bands 1 to 7 and 9. New band 1 (ultra-blue) is useful for coastal and aerosol studies. New band 9 is useful for cirrus cloud detection. The resolution for Band 8 (panchromatic) is 15 meters. Thermal bands 10 and 11 are useful in providing more accurate surface temperatures and are collected at 100 meters. Approximate scene size is 170 km north-south by 183 km east-west (106 mi by 114 mi).

Landsat 8 Operational Land Imager (OLI) and Thermal Infrared Sensor (TIRS)Launched February 11, 2013 Bands Wavelength (micrometers) Resolution (meters)
Band 1 - Coastal aerosol 0.43 - 0.45 30
Band 2 - Blue 0.45 - 0.51 30
Band 3 - Green 0.53 - 0.59 30
Band 4 - Red 0.64 - 0.67 30
Band 5 - Near Infrared (NIR) 0.85 - 0.88 30
Band 6 - SWIR 1 1.57 - 1.65 30
Band 7 - SWIR 2 2.11 - 2.29 30
Band 8 - Panchromatic 0.50 - 0.68 15
Band 9 - Cirrus 1.36 - 1.38 30
Band 10 - Thermal Infrared (TIRS) 1 10.60 - 11.19 100
Band 11 - Thermal Infrared (TIRS) 2 11.50 - 12.51 100

* TIRS bands are acquired at 100 meter resolution, but are resampled to 30 meter in delivered data product.

7. Natural color view (RGB composite)

Due to the introduction of a new "Cirrus" band (#1), the BGR bands are now 2, 3, and 4, respectively. See also "Common band combinations in RGB" for Landsat 7 or Landsat 5, and Landsat 8.

From Digital Numer (DN) to reflectance:
Before creating an RGB composite, it is important to convert the digital number data (DN) to reflectance (or optionally radiance). Otherwise the colors of a "natural" RGB composite do not look convincing but rather hazy (see background in the next screenshot). This conversion is easily done using the metadata file which is included in the data set with i.landsat.toar:

grass7_landsat_toar0
grass7_landsat_toar1
grass7_landsat_toar2
grass7_landsat_toar3

Now we are ready to create a nice RGB composite:

grass7_landsat_rgb0

grass7_landsat_rgb1

Select the bands to be visually combined:

grass7_visualize2

... and voilà!

grass7_landsat_rgb2

8. Applying the Landsat 8 Quality Assessment (QA) Band

One of the bands of a Landsat 8 scene is named "BQA" which contains for each pixel a decimal value representing a bit-packed combination of surface, atmosphere, and sensor conditions found during the overpass.  It can be used to judge the overall usefulness of a given pixel.

We can use this information to easily eliminate e.g. cloud contaminated pixels. In short, the QA concept is (cited here from the USGS page):

Cited from http://landsat.usgs.gov/L8QualityAssessmentBand.php‎

For the single bits (0, 1, 2, and 3):
0 = No, this condition does not exist
1 = Yes, this condition exists.

The double bits (4-5, 6-7, 8-9, 10-11, 12-13, and 14-15) represent levels of confidence that a condition exists:
00 = Algorithm did not determine the status of this condition
01 = Algorithm has low confidence that this condition exists (0-33 percent confidence)
10 = Algorithm has medium confidence that this condition exists (34-66 percent confidence)
11 = Algorithm has high confidence that this condition exists (67-100 percent confidence).

Detailed bit patterns (d: double bits; s: single bits):
d  Bit 15 = 0 = cloudy
d  Bit 14 = 0 = cloudy
d  Bit 13 = 0 = not a cirrus cloud
d  Bit 12 = 0 = not a cirrus cloud
d  Bit 11 = 0 = not snow/ice
d  Bit 10 = 0 = not snow/ice
d  Bit 9 = 0 = not populated
d  Bit 8 = 0 = not populated
d  Bit 7 = 0 = not populated
d  Bit 6 = 0 = not populated
d  Bit 5 = 0 = not water
d  Bit 4 = 0 = not water
s  Bit 3 = 0 = not populated
s  Bit 2 = 0 = not terrain occluded
s  Bit 1 = 0 = not a dropped frame
s  Bit 0 = 0 = not fill

Usage example 1:  Creating a mask from a bitpattern

We can create a cloud mask (bit 15+14 are set) from this pattern:
cloud:   1100000000000000

Using the Python shell tab, we can easily convert this into the corresponding decimal number for r.mapcalc:

Cited from http://landsat.usgs.gov/L8QualityAssessmentBand.php‎

Welcome to wxGUI Interactive Python Shell 0.9.8

Type "help(grass)" for more GRASS scripting related information.
Type "AddLayer()" to add raster or vector to the layer tree.

Python 2.7.5 (default, Aug 22 2013, 09:31:58) 
[GCC 4.8.1 20130603 (Red Hat 4.8.1-1)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> int(0b1100000000000000)
49152

Using this decimal value of 49152, we can create a cloud mask:

# set NULL for cloudy pixels, 1 elsewhere:
r.mapcalc "cloudmask = if(LC80160352013134LGN03_BQA == 49152, null(), 1 )"

# apply this mask
r.mask cloudmask

In our sample scene, there are only tiny clouds in the north-east, so no much to be seen. Some spurious cloud pixels are scattered over the scene, too, which could be eliminated (in case of false positives) or kept.

Usage example 2:  Querying the Landsat 8 BQA map and retrieve the bitpattern

Perhaps you prefer to query the BQA map itself (overlay the previously created RGB composite and query the BSA map by selecting it in the Layer Manager). In our example, we query the BQA value of the cloud:

Using again the Python shell tab, we can easily convert the decimal number (used for r.mapcalc) into the corresponding binary representation to verify with the  table values above.

>>> x=61440
>>> print(bin(x & 0xffffffff))
0b1111000000000000

Hence, bits 15,14,13, and 12 are set: cloudy and not a cirrus cloud. Looking at the RGB composite we tend to agree :-) Time to mask out the cloud!

wxGUI menu >> Raster >> Mask [r.mask]

Or use the command line, as shown already above:

# remove existing mask (if active)
r.mask -r

# set NULL for cloudy pixels, 1 elsewhere:
r.mapcalc "cloudmask = if(LC80160352013134LGN03_BQA == 61440, null(), 1 )" --o

# apply the new mask
r.mask cloudmask

The visual effect in the RGB composite is minimal since the cloud is white anyway (as NULL cells, too). However, it is relevant for real calculations such as NDVI (vegetation index) or thermal maps.

We observe dark pixels around the cloud originating from thin clouds. In a subsequent identification/mask step we may eliminate also those pixels with a subsequent filter.

Comparison of SOM Classification and Unsupervised KMeans image classification in SEXTANTE

faunaliagis

Detecting tree canopies with Unsupervised Classification in SEXTANTE

faunaliagis

  • Page 1 of 2 ( 27 posts )
  • >>
  • grass

Back to Top

Sponsors