博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
GDAL读取jpg文件中GPS坐标信息
阅读量:5862 次
发布时间:2019-06-19

本文共 6586 字,大约阅读时间需要 21 分钟。

在目前很多相机都支持在拍照的时候保留GPS信息,这些信息一般都是存储在jpg图像的exif信息中。下面内容主要说明如何使用GDAL库来读取jpg图像中的GPS信息并解析经纬度坐标。

首先,还是最常用的工具,gdalinfo,来查看这个GPS信息到底在什么地方。下面是使用gdalinfo输出的信息,图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
图1 GDALINFO 输出的信息
从上面的输出信息可以看出,jpg中存储GPS的信息是以EXIF_GPS***开头的元数据信息里面所存储。知道了存储位置我们就可以写程序来解析了,首先要做的是从这么多一大堆的EXIF信息中提取GPS的信息,代码如下:

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] );			}		}	}
大概解释一下上面的代码,首先从poDataset 中获取元数据信息;然后判断元数据的个数是否大于0,也就是判断是否存在元数据;最后通过函数EQUALN来提取EXIF_GPS开头的元数据存放在新的字符串数组中。通过上面的代码提取之后的元数据如下:

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_GPS开头的含义可以参考这个()。通过这个页面可以得知,我们要获取的坐标就是下面这几个元数据里面的值,标识的含义见后面。

EXIF_GPSAltitude=(55.6)              ——海拔  EXIF_GPSAltitudeRef=00               ——海拔参考值(应该就是水平面高程)  EXIF_GPSLatitude=(39) (53) (41.298)  ——纬度信息  EXIF_GPSLatitudeRef=N                ——纬度标识,N为北纬,S为南纬  EXIF_GPSLongitude=(116) (17) (28.344)——经度信息  EXIF_GPSLongitudeRef=E               ——经度标识,E为东经,W为西经  EXIF_GPSMapDatum=WGS-84              ——参考椭球,这个应该都是WGS84吧
其中经度和纬度信息是使用度分秒格式表示。知道了格式及其含义,就可以很方便的解析了。下面是一个解析的函数,使用了boost库中的split函数和lexical_cast函数。

#include "gdal_priv.h"#include 
#include
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** papszMetadataGPS = NULL; for(int i = 0; papszMetadata[i] != NULL; i++ ) { if(EQUALN(papszMetadata[i], "EXIF_GPS", 8)) papszMetadataGPS = CSLAddString( papszMetadataGPS, papszMetadata[i]); } int iGPSCount = CSLCount(papszMetadataGPS); if (iGPSCount <=0) { CSLDestroy( papszMetadataGPS ); return false; } bool bIsNorth = true; bool bIsEast = true; for(int i = 0; papszMetadataGPS[i] != NULL; i++ ) { vector
vSplitStr; split(vSplitStr, papszMetadataGPS[i], is_any_of("=")); //使用=拆分字符串 if(vSplitStr.empty() || vSplitStr.size() != 2) continue; string strName = vSplitStr[0]; //取出标识符 string strValue = vSplitStr[1]; //取出值 if(strName.empty() || strValue.empty()) continue; if(strName == "EXIF_GPSAltitude") //获取海拔 { vector
vSplitValue; split(vSplitValue, strValue, is_any_of("( )"), token_compress_on); //使用( )拆分字符串 if(vSplitValue.size() != 3) dHgt = 0; else dHgt = lexical_cast
(vSplitValue[1]); } else if(strName == "EXIF_GPSLongitude") //获取经度 { vector
vSplitValue; split(vSplitValue, strValue, is_any_of("( )"), token_compress_on); //使用( )拆分字符串 if(vSplitValue.size() != 5) dLon = 0; else dLon = lexical_cast
(vSplitValue[1]) + lexical_cast
(vSplitValue[2]) / 60.0 + lexical_cast
(vSplitValue[3]) / 3600.0; } else if(strName == "EXIF_GPSLatitude") //获取纬度 { vector
vSplitValue; split(vSplitValue, strValue, is_any_of("( )"), token_compress_on); //使用( )拆分字符串 if(vSplitValue.size() != 5) dLat = 0; else dLat = lexical_cast
(vSplitValue[1]) + lexical_cast
(vSplitValue[2]) / 60.0 + lexical_cast
(vSplitValue[3]) / 3600.0; } else if(strName == "EXIF_GPSLongitude") //获取经度 { if (strValue == "E") bIsEast = true; else bIsEast = false; } else if(strName == "EXIF_GPSLatitude") //获取纬度 { if (strValue == "N") bIsNorth = true; else bIsNorth = false; } } dLon = bIsEast ? dLon : -1.0*dLon; dLat = bIsNorth ? dLat : -1.0*dLat; return true;}
需要注意的是,上面的代码中有句“split(vSplitValue, strValue, is_any_of("( )"), token_compress_on); //使用( )拆分字符串”,按理说这句应该会把括弧和空格去掉,我本机执行的时候确实去掉了,但是在解析后的字符串vector中的收尾增加了两个空字符串,所以下面只好从1开始了。解析后的输出如图2所示。

图2 解析的坐标信息

转载于:https://www.cnblogs.com/xiaowangba/archive/2013/04/26/6313959.html

你可能感兴趣的文章
什么是DDOS攻击?怎么防御?
查看>>
状态模式(State Pattern)
查看>>
log4j日志框架学习
查看>>
function 与 => 的区别
查看>>
VBScript:写excel的例子
查看>>
实验一 巩耀阳 201421430029
查看>>
TYVJ P1077 有理逼近 Label:坑,tle的好帮手 不懂
查看>>
面试题:缓存Redis与Memcached的比较 有用
查看>>
通过UIWebView加载读取本地文件
查看>>
由于缺少证书链,导致Android手机提示网站不安全
查看>>
DNS信息收集工具dig使用
查看>>
R语言数据的收益率和可能的波动性交易
查看>>
Dijkstra最短路算法
查看>>
Python 学习
查看>>
unix编程——管道
查看>>
网页时间特效_正确取时间
查看>>
控制文件损坏,丢失其中一个
查看>>
I/O复用
查看>>
EXCEL自动撤销合并单元格并填充相应内容(转帖)
查看>>
jquery validate(转)
查看>>