Chapter 24
Online data

With almost every computer connected to the Internet, the amount of online information is steadily growing. It is quite easy to retrieve valuable information. OTB has a few experimental classes for this purpose.

For these examples to work, you need to have OTB compiled with the OTB_USE_CURL option to ON (and the curl library installed somewhere).

Let’s see what we can do.

24.1 Name to Coordinates

The source code for this example can be found in the file
Examples/Projections/PlaceNameToLonLatExample.cxx.

This example will show how to retrieve the longitude and latitude from a place using the name of the city or the address. For that, we will use the otb::PlaceNameToLonLat class.

  #include "otbPlaceNameToLonLat.h"

You instantiate the class and pass the name you want to look for as a std::string to the SetPlaceName method.

The call to evaluate will trigger the retrival process.

    otb::PlaceNameToLonLat::Pointer pn2LL = otb::PlaceNameToLonLat::New();
    pn2LL->SetPlaceName(std::string(argv[1]));
    pn2LL->Evaluate();

To get the data, you can simply call the GetLon and GetLat methods.

    double lon = pn2LL->GetLon();
    double lat = pn2LL->GetLat();
  
    std::cout << "Latitude: " << lat << std::endl;
    std::cout << "Longitude: " << lon << std::endl;

If you tried with a string such as ”Toulouse” – a city where the heart of OTB relies – you should obtain something like:

   Latitude: 43.6044  
   Longitude: 1.44295  
   

24.2 Open Street Map

The power of sharing which is a driving force in open source software such as OTB can also be demonstrated for data collection. One good example is Open Street Map (http://www.openstreetmap.org/).

In this project, hundreds of thousands of users upload GPS data and draw maps of their surroundings. The coverage is impressive and this data is freely available.

It is even possible to get the vector data (not covered yet by OTB), but here we will focus on retrieving some nice maps for any place in the world. The following example describes the method. This part is pretty experimental and the code is not as polished as the rest of the library. You’ve been warned!

The source code for this example can be found in the file
Examples/IO/TileMapImageIOExample.cxx.

First, we need to include several headers. There will be a bit of manual work going on here.

  #include "itkRGBPixel.h"
  #include "otbImageFileReader.h"
  #include "otbTileMapImageIO.h"
  #include "otbInverseSensorModel.h"
  #include "otbForwardSensorModel.h"
  #include "otbExtractROI.h"
  #include "otbImageFileWriter.h"
  #include "otbTileMapTransform.h"
  #include "otbWorldFile.h"

We retrieve the input parameters:

    std::string inputFilename = argv[1];
    std::string outputFilename = argv[2];
    std::string cacheDirectory = argv[3];
    double      lon = atof(argv[4]);
    double      lat = atof(argv[5]);
    int         depth = atoi(argv[6]);

We now instantiate the reader. As some parameters need to be given to the IO which is an otb::TileMapImageIO , we need to manually create it:

    typedef itk::RGBPixel<unsigned char>    RGBPixelType;
    typedef otb::Image<RGBPixelType, 2>     ImageType;
    typedef otb::ImageFileReader<ImageType> ReaderType;
    typedef otb::TileMapImageIO             ImageIOType;
  
    ImageIOType::Pointer tileIO = ImageIOType::New();
    ReaderType::Pointer  readerTile = ReaderType::New();
    tileIO->SetDepth(depth);
    tileIO->SetCacheDirectory(cacheDirectory);
    readerTile->SetImageIO(tileIO);
    readerTile->SetFileName(inputFilename);
    readerTile->UpdateOutputInformation();

Now, we potentially have an image of several Peta-Bytes covering the whole world in the reader that’s why we don’t want to do an update before extracting a specific area.

The coordinates are referred with an origin at the North Pole and the change date meridian in Mercator projection. So we need to translate the latitude and the longitude in this funny coordinate system:

    typedef otb::TileMapTransform<otb::TransformDirection::FORWARD> TransformType;
    TransformType::Pointer transform = TransformType::New();
    transform->SetDepth(depth);
  
    typedef itk::Point <double, 2> PointType;
    PointType lonLatPoint;
    lonLatPoint[0] = lon;
    lonLatPoint[1] = lat;
  
    PointType tilePoint;
    tilePoint = transform->TransformPoint(lonLatPoint);

This enables us to use the otb::ExtractROI to retrieve only the area of interest and to avoid crashing our memory-limited computer.

    long int startX = static_cast<long int>(tilePoint[0]);
    long int startY = static_cast<long int>(tilePoint[1]);
    long int sizeX = 500;
    long int sizeY = 500;
  
    std::cerr << startX << ", " << startY << std::endl;
    std::cerr << sizeX << ", " << sizeY << std::endl;
  
    typedef otb::ExtractROI<RGBPixelType,  RGBPixelType> ExtractROIFilterType;
    ExtractROIFilterType::Pointer extractROIOsmFilter = ExtractROIFilterType::New();
    extractROIOsmFilter->SetStartX(startX - sizeX / 2);
    extractROIOsmFilter->SetStartY(startY - sizeY / 2);
    extractROIOsmFilter->SetSizeX(sizeX);
    extractROIOsmFilter->SetSizeY(sizeY);
  
    extractROIOsmFilter->SetInput(readerTile->GetOutput());

Finally, we just plug this to the writer to save our nice map of the area:

    typedef otb::ImageFileWriter<ImageType> WriterType;
    WriterType::Pointer writer = WriterType::New();
    writer->SetFileName(outputFilename);
    writer->SetInput(extractROIOsmFilter->GetOutput());
    writer->Update();

We also want to create the associated world file to be able to use this new image in a GIS system. For this, we need to compute the coordinates of the top left corner and the spacing in latitude and longitude.

For that, we use the inverse transform to convert the corner coordinates into latitude and longitude.

    typedef otb::TileMapTransform<otb::TransformDirection::INVERSE> InverseTransformType;
    InverseTransformType::Pointer transformInverse = InverseTransformType::New();
    transformInverse->SetDepth(depth);
  
  
    double lonUL, latUL, lonSpacing, latSpacing;
  
    tilePoint[0] = startX - sizeX / 2;
    tilePoint[1] = startY - sizeY / 2;
    lonLatPoint = transformInverse->TransformPoint(tilePoint);
    lonUL = lonLatPoint[0];
    latUL = lonLatPoint[1];
    tilePoint[0] = startX + sizeX / 2;
    tilePoint[1] = startY + sizeY / 2;
    lonLatPoint = transformInverse->TransformPoint(tilePoint);
    lonSpacing = (lonLatPoint[0] - lonUL) / (sizeX - 1);
    latSpacing = (lonLatPoint[1] - latUL) / (sizeY - 1);

Now that we have all the information, we can write the world file which has the wld extension. This is a simple text file containing the coordinates of the center of the top left pixel and the x and y spacing.

    otb::WorldFile::Pointer worldFile = otb::WorldFile::New();
    worldFile->SetImageFilename(outputFilename);
    worldFile->SetLonOrigin(lonUL);
    worldFile->SetLatOrigin(latUL);
    worldFile->SetLonSpacing(lonSpacing);
    worldFile->SetLatSpacing(latSpacing);
    worldFile->Update();

Figure 24.1 shows the output images created from open street map data.


PIC PIC

Figure 24.1: Map created from open street map showing the OTB headquarters


If your street is missing, go and improve the map by adding it yourself.