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.
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
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:
- the input filename is a simple text file specifying the access modality to open street map data;
- the output file is the image where you want to save the result;
- the cache directory is necessary to keep the data retrieved from the internet. It can also be
reused to minimize network access;
- longitude of the center of the scene;
- latitude of the center of the scene;
- depth which is inversely related to the resolution: when you increase the depth by one, you
divide the resolution by two.
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.
If your street is missing, go and improve the map by adding it yourself.