Currently, many cameras support retaining GPS information when taking photos. This information is generally stored in the EXIF information of JPG images. The following describes how to use the gdal library to read the GPS information in JPG images and parse the longitude and latitude coordinates.
First, it is also the most commonly used tool, gdalinfo, to see where the GPS information is. The following figure shows the information output using gdalinfo, as shown in figure 1.
Driver: JPEG/JPEG JFIFFiles: C:\Users\LiMinlu\Desktop\DSCN8806.JPGSize is 4608, 3456Coordinate System is `'Metadata: EXIF_ColorSpace=1 EXIF_ComponentsConfiguration=0x1 0x2 0x3 00 EXIF_CompressedBitsPerPixel=(2) EXIF_Contrast=0 EXIF_CustomRendered=0 EXIF_DateTime=2013:03:18 16:06:49 EXIF_DateTimeDigitized=2013:03:18 16:06:49 EXIF_DateTimeOriginal=2013:03:18 16:06:49 EXIF_DigitalZoomRatio=(0) EXIF_ExifVersion=0230 EXIF_ExposureBiasValue=(0) EXIF_ExposureMode=0 EXIF_ExposureProgram=2 EXIF_ExposureTime=(0.00625) EXIF_FileSource=0x3 EXIF_Flash=24 EXIF_FlashpixVersion=0100 EXIF_FNumber=(3.9) EXIF_FocalLength=(5) EXIF_FocalLengthIn35mmFilm=28 EXIF_GainControl=4 EXIF_GPSAltitude=(55.6) EXIF_GPSAltitudeRef=00 EXIF_GPSDateStamp=2013:03:18 EXIF_GPSImgDirection=(33.96) EXIF_GPSImgDirectionRef=T EXIF_GPSLatitude=(39) (53) (41.298) EXIF_GPSLatitudeRef=N EXIF_GPSLongitude=(116) (17) (28.344) EXIF_GPSLongitudeRef=E EXIF_GPSMapDatum=WGS-84 EXIF_GPSSatellites=03 EXIF_GPSTimeStamp=(8) (5) (41.02) EXIF_GPSVersionID=0x2 0x3 00 00 EXIF_ImageDescription= EXIF_Interoperability_Index=R98 EXIF_Interoperability_Version=0x30 0x31 0x30 0x30 EXIF_ISOSpeedRatings=125 EXIF_LightSource=0 EXIF_Make=NIKON EXIF_MakerNote=Nikon EXIF_MaxApertureValue=(3.9) EXIF_MeteringMode=5 EXIF_Model=COOLPIX AW100s EXIF_Orientation=1 EXIF_PixelXDimension=4608 EXIF_PixelYDimension=3456 EXIF_ResolutionUnit=2 EXIF_Saturation=0 EXIF_SceneCaptureType=0 EXIF_SceneType=0x1 EXIF_Sharpness=0 EXIF_Software=COOLPIX AW100sV1.0 EXIF_SubjectDistanceRange=2 EXIF_UserComment= EXIF_WhiteBalance=0 EXIF_XResolution=(300) EXIF_YCbCrPositioning=2 EXIF_YResolution=(300)Image Structure Metadata: COMPRESSION=JPEG INTERLEAVE=PIXEL SOURCE_COLOR_SPACE=YCbCrCorner Coordinates:Upper Left ( 0.0, 0.0)Lower Left ( 0.0, 3456.0)Upper Right ( 4608.0, 0.0)Lower Right ( 4608.0, 3456.0)Center ( 2304.0, 1728.0)Band 1 Block=4608x1 Type=Byte, ColorInterp=Red Image Structure Metadata: COMPRESSION=JPEGBand 2 Block=4608x1 Type=Byte, ColorInterp=Green Image Structure Metadata: COMPRESSION=JPEGBand 3 Block=4608x1 Type=Byte, ColorInterp=Blue Image Structure Metadata: COMPRESSION=JPEG
Figure 1 output information of gdalinfo
From the output, we can see that the GPS information stored in JPG is stored in the metadata information starting with exif_gps. Once we know the storage location, we can write a program to parse it. The first thing we need to do is to extract GPS information from so many EXIF messages. The Code is as follows:
char** papszMetadata = poDataset->GetMetadata( NULL ) ;char** papszMetadataGPS = NULL;if( CSLCount(papszMetadata) > 0 ){for(int i = 0; papszMetadata[i] != NULL; i++ ){if(EQUALN(papszMetadata[i], "EXIF_GPS", 8)){papszMetadataGPS = CSLAddString( papszMetadataGPS, papszMetadata[i]);printf( " %s\n", papszMetadata[i] );}}}
The above code roughly explains how to obtain metadata information from podataset and determine whether the number of metadata is greater than 0, that is, whether metadata exists; finally, metadata starting with exif_gps is extracted and stored in the New String Array Through the Function Limit n. The metadata extracted from the above Code is as follows:
EXIF_GPSAltitude=(55.6) EXIF_GPSAltitudeRef=00 EXIF_GPSDateStamp=2013:03:18 EXIF_GPSImgDirection=(33.96) EXIF_GPSImgDirectionRef=T EXIF_GPSLatitude=(39) (53) (41.298) EXIF_GPSLatitudeRef=N EXIF_GPSLongitude=(116) (17) (28.344) EXIF_GPSLongitudeRef=E EXIF_GPSMapDatum=WGS-84 EXIF_GPSSatellites=03 EXIF_GPSTimeStamp=(8) (5) (41.02) EXIF_GPSVersionID=0x2 0x3 00 00
Refer to this page (http://www.awaresystems.be/imaging/tiff/tifftags/privateifd/gps.html) for the meaning of the beginning of these exif_gps ). Through this page, we can know that the coordinates we want to obtain are the values in the following metadata. The meanings of the identifiers are described below.
Exif_gpsaltitude = (55.6) -- altitude exif_gpsaltituderef = 00 -- altitude reference value (which should be horizontal elevation) exif_gpslatitude = (39) (53) (41.298) -- latitude information exif_gpslatituderef = n -- latitude, N is north latitude, S is south latitude exif_gpslong== (116) (17) (28.344) -- longitude information exif_gpslongituderef = e -- longitude ID, e is the east longitude, W is the western longitude exif_gpsmapdatum = WGS-84-reference elliptical, this should be WGS84
The longitude and latitude information are expressed in the degree and second format. You can easily parse the format and its meaning. The following is a parsed function that uses the split function and the lexical_cast function in the boost library.
# Include "gdal_priv.h" # include <vector> # include <string> using namespace STD; # include "Boost/lexical_cast.hpp" # include "Boost/algorithm/string. HPP "using namespace boost; using namespace boost: algorithm; bool extractgpsinfo (char ** papszmetadata, double & dlon, double & dlat, double & dhgt) {If (cslcount (papszmetadata) <= 0) return false; char ** papszmeta1_ps = NULL; For (INT I = 0; papszmetadata [I]! = NULL; I ++) {If (equaln (papszmetadata [I], "exif_gps", 8) papszmetadatagps = csladdstring (papszmetadatagps, papszmetadata [I]);} int igpscount = cslcount (papszmeta1_ps); If (igpscount <= 0) {csldestroy (papszmeta1_ps); Return false;} bool bisnorth = true; bool biseast = true; for (INT I = 0; papszmeta1_ps [I]! = NULL; I ++) {vector <string> vsplitstr; split (vsplitstr, papszmeta1_ps [I], is_any_of ("= ")); // use = to split the string if (vsplitstr. empty () | vsplitstr. size ()! = 2) continue; string strname = vsplitstr [0]; // retrieve the identifier string strvalue = vsplitstr [1]; // retrieve the value if (strname. empty () | strvalue. empty () continue; If (strname = "exif_gpsaltitude") // obtain the elevation of {vector <string> vsplitvalue; split (vsplitvalue, strvalue, is_any_of ("()"), token_compress_on); // use () to split the string if (vsplitvalue. size ()! = 3) dhgt = 0; elsedhgt = lexical_cast <double> (vsplitvalue [1]);} else if (strname = "exif_gpslongpolling ") // obtain the longitude {vector <string> vsplitvalue; split (vsplitvalue, strvalue, is_any_of ("()"), token_compress_on); // use () to split the string if (vsplitvalue. size ()! = 5) dlon = 0; elsedlon = lexical_cast <double> (vsplitvalue [1]) + lexical_cast <double> (vsplitvalue [2]) /60.0 + lexical_cast <double> (vsplitvalue [3])/3600.0;} else if (strname = "exif_gpslatitude") // obtain the latitude {vector <string> vsplitvalue; split (vsplitvalue, strvalue, is_any_of ("()"), token_compress_on); // use () to split the string if (vsplitvalue. size ()! = 5) dlat = 0; elsedlat = lexical_cast <double> (vsplitvalue [1]) + lexical_cast <double> (vsplitvalue [2]) /60.0 + lexical_cast <double> (vsplitvalue [3])/3600.0;} else if (strname = "exif_gpslongpolling ") // obtain the longitude {If (strvalue = "e") biseast = true; elsebiseast = false;} else if (strname = "exif_gpslatitude ") // obtain the latitude {If (strvalue = "N") bisnorth = true; elsebisnorth = false ;}} dlon = biseast? Dlon:-1.0 * dlon; dlat = bisnorth? Dlat:-1.0 * dlat; return true ;}
Note that the above Code contains the following sentence: "Split (vsplitvalue, strvalue, is_any_of (" () "), token_compress_on); // use () to split the string ", it is reasonable to say that this sentence should remove the arc and space. I did remove it when executing it on the local machine, but added two empty strings to the end of the parsed string vector, so we have to start from 1. Output 2 after resolution.
Figure 2 resolved coordinate information