ژانویه 2009
هدف، واقعگرایانه
این آموزش به شما می آموزد که چگونه از عکس های دارای برچسب جغرافیایی برای ایجاد KML PhotoOverlays
استفاده کنید. در حالی که کد نمونه در پایتون نوشته شده است، بسیاری از کتابخانه های مشابه در زبان های برنامه نویسی دیگر وجود دارد، بنابراین ترجمه این کد به زبان دیگر مشکلی نیست. کد موجود در این مقاله بر یک کتابخانه منبع باز پایتون، EXIF.py متکی است.
معرفی
دوربین های دیجیتال چیزهای بسیار شگفت انگیزی هستند. بسیاری از کاربران متوجه این موضوع نیستند، اما آنها چیزی بیش از گرفتن عکس و فیلم انجام می دهند. آنها همچنین آن فیلم ها و عکس ها را با متادیتا در مورد دوربین و تنظیمات آن برچسب گذاری می کنند. در چند سال گذشته، مردم راههایی برای اضافه کردن دادههای جغرافیایی به آن اطلاعات پیدا کردهاند، که یا توسط سازندگان دوربین، مانند برخی از دوربینهای Ricoh و Nikon، یا از طریق دستگاههایی مانند GPS Logger و EyeFi Explore تعبیه شده است. تلفن های دوربین دار مانند آیفون و تلفن هایی که از سیستم عامل اندروید استفاده می کنند، مانند T-Mobile's G1 ، این داده ها را به طور خودکار جاسازی می کنند. برخی از سایتهای آپلود عکس، مانند Panoramio ، Picasa Web Albums و Flickr ، دادههای GPS را بهطور خودکار تجزیه میکنند و از آن برای برچسبگذاری جغرافیایی یک عکس استفاده میکنند. سپس می توانید آن داده ها را در فیدها برگردانید. اما کجای آن سرگرم کننده است؟ این مقاله چگونگی دستیابی به آن داده ها را بررسی می کند.
هدرهای Exif
رایج ترین راه برای جاسازی داده ها در یک فایل تصویری استفاده از فرمت فایل تصویری تبادلی یا EXIF است. داده ها به صورت باینری در سربرگ های EXIF به صورت استاندارد ذخیره می شوند. اگر مشخصات هدرهای EXIF را می دانید، می توانید خودتان آنها را تجزیه کنید. خوشبختانه، شخصی قبلاً کار سختی را انجام داده و یک ماژول پایتون برای شما نوشته است. کتابخانه منبع باز EXIF.py یک ابزار عالی برای خواندن سرصفحه های فایل های JPEG است.
کد
کد نمونه این مقاله در این فایل است: exif2kml.py . اگر میخواهید مستقیماً به استفاده از آن رد شوید، آن ماژول و همچنین EXIF.py را دانلود کنید و آنها را در همان فهرست قرار دهید. python exif2kml.py foo.jpg
foo.jpg را با مسیر عکس دارای برچسب جغرافیایی جایگزین foo.jpg کنید. فایلی به نام test.kml
تولید می کند.
تجزیه سرصفحه های Exif
EXIF.py یک رابط آسان برای بیرون کشیدن هدرهای Exif فراهم می کند. به سادگی تابع process_file()
را اجرا کنید و هدرها را به عنوان یک شی dict
برمی گرداند.
def GetHeaders(the_file): """Handles getting the Exif headers and returns them as a dict. Args: the_file: A file object Returns: a dict mapping keys corresponding to the Exif headers of a file. """ data = EXIF.process_file(the_file, 'UNDEF', False, False, False) return data
هنگامی که هدرهای Exif را دارید، باید مختصات GPS را استخراج کنید. EXIF.py اینها را بهعنوان اشیاء Ratio
، اشیایی برای ذخیرهسازی صورتدهنده و مخرج مقادیر در نظر میگیرد. این یک نسبت دقیق را به جای تکیه بر یک عدد ممیز شناور تنظیم می کند. اما، KML انتظار اعداد اعشاری، نه نسبت ها را دارد. بنابراین شما هر یک از مختصات را استخراج می کنید و صورت و مخرج را به یک عدد ممیز شناور برای درجه اعشار تبدیل می کنید:
def DmsToDecimal(degree_num, degree_den, minute_num, minute_den, second_num, second_den): """Converts the Degree/Minute/Second formatted GPS data to decimal degrees. Args: degree_num: The numerator of the degree object. degree_den: The denominator of the degree object. minute_num: The numerator of the minute object. minute_den: The denominator of the minute object. second_num: The numerator of the second object. second_den: The denominator of the second object. Returns: A deciminal degree. """ degree = float(degree_num)/float(degree_den) minute = float(minute_num)/float(minute_den)/60 second = float(second_num)/float(second_den)/3600 return degree + minute + second def GetGps(data): """Parses out the GPS coordinates from the file. Args: data: A dict object representing the Exif headers of the photo. Returns: A tuple representing the latitude, longitude, and altitude of the photo. """ lat_dms = data['GPS GPSLatitude'].values long_dms = data['GPS GPSLongitude'].values latitude = DmsToDecimal(lat_dms[0].num, lat_dms[0].den, lat_dms[1].num, lat_dms[1].den, lat_dms[2].num, lat_dms[2].den) longitude = DmsToDecimal(long_dms[0].num, long_dms[0].den, long_dms[1].num, long_dms[1].den, long_dms[2].num, long_dms[2].den) if data['GPS GPSLatitudeRef'].printable == 'S': latitude *= -1 if data['GPS GPSLongitudeRef'].printable == 'W': longitude *= -1 altitude = None try: alt = data['GPS GPSAltitude'].values[0] altitude = alt.num/alt.den if data['GPS GPSAltitudeRef'] == 1: altitude *= -1 except KeyError: altitude = 0 return latitude, longitude, altitude
هنگامی که مختصات را دارید، ایجاد یک PhotoOverlay
ساده برای هر عکس آسان است:
def CreatePhotoOverlay(kml_doc, file_name, the_file, file_iterator): """Creates a PhotoOverlay element in the kml_doc element. Args: kml_doc: An XML document object. file_name: The name of the file. the_file: The file object. file_iterator: The file iterator, used to create the id. Returns: An XML element representing the PhotoOverlay. """ photo_id = 'photo%s' % file_iterator data = GetHeaders(the_file) coords = GetGps(data) po = kml_doc.createElement('PhotoOverlay') po.setAttribute('id', photo_id) name = kml_doc.createElement('name') name.appendChild(kml_doc.createTextNode(file_name)) description = kml_doc.createElement('description') description.appendChild(kml_doc.createCDATASection('<a href="#%s">' 'Click here to fly into ' 'photo</a>' % photo_id)) po.appendChild(name) po.appendChild(description) icon = kml_doc.createElement('icon') href = kml_doc.createElement('href') href.appendChild(kml_doc.createTextNode(file_name)) camera = kml_doc.createElement('Camera') longitude = kml_doc.createElement('longitude') latitude = kml_doc.createElement('latitude') altitude = kml_doc.createElement('altitude') tilt = kml_doc.createElement('tilt') # Determines the proportions of the image and uses them to set FOV. width = float(data['EXIF ExifImageWidth'].printable) length = float(data['EXIF ExifImageLength'].printable) lf = str(width/length * -20.0) rf = str(width/length * 20.0) longitude.appendChild(kml_doc.createTextNode(str(coords[1]))) latitude.appendChild(kml_doc.createTextNode(str(coords[0]))) altitude.appendChild(kml_doc.createTextNode('10')) tilt.appendChild(kml_doc.createTextNode('90')) camera.appendChild(longitude) camera.appendChild(latitude) camera.appendChild(altitude) camera.appendChild(tilt) icon.appendChild(href) viewvolume = kml_doc.createElement('ViewVolume') leftfov = kml_doc.createElement('leftFov') rightfov = kml_doc.createElement('rightFov') bottomfov = kml_doc.createElement('bottomFov') topfov = kml_doc.createElement('topFov') near = kml_doc.createElement('near') leftfov.appendChild(kml_doc.createTextNode(lf)) rightfov.appendChild(kml_doc.createTextNode(rf)) bottomfov.appendChild(kml_doc.createTextNode('-20')) topfov.appendChild(kml_doc.createTextNode('20')) near.appendChild(kml_doc.createTextNode('10')) viewvolume.appendChild(leftfov) viewvolume.appendChild(rightfov) viewvolume.appendChild(bottomfov) viewvolume.appendChild(topfov) viewvolume.appendChild(near) po.appendChild(camera) po.appendChild(icon) po.appendChild(viewvolume) point = kml_doc.createElement('point') coordinates = kml_doc.createElement('coordinates') coordinates.appendChild(kml_doc.createTextNode('%s,%s,%s' %(coords[1], coords[0], coords[2]))) point.appendChild(coordinates) po.appendChild(point) document = kml_doc.getElementsByTagName('Document')[0] document.appendChild(po)
میبینید که ما فقط از روشهای استاندارد W3C DOM استفاده میکنیم، زیرا آنهایی هستند که در اکثر زبانهای برنامهنویسی موجود هستند. برای اینکه ببینید چگونه همه چیز با هم هماهنگ می شود، کد را از اینجا دانلود کنید.
این نمونه از قدرت کامل PhotoOverlays
که به شما امکان میدهد کاوشهای عمیق عکسهای با وضوح بالا ایجاد کنید. اما، نشان می دهد که چگونه می توان یک عکس را به سبک بیلبورد در Google Earth آویزان کرد. در اینجا نمونه ای از یک فایل KML ایجاد شده با استفاده از این کد آمده است:
<?xml version="1.0" encoding="utf-8"?> <kml xmlns="http://www.opengis.net/kml/2.2"> <Document> <PhotoOverlay id="photo0"> <name> 1228258523134.jpg </name> <description> <![CDATA[<a href="#photo0">Click here to fly into photo</a>]]> </description> <Camera> <longitude> -122.3902159196034 </longitude> <latitude> 37.78961266330473 </latitude> <altitude> 10 </altitude> <tilt> 90 </tilt> </Camera> <Icon> <href> 1228258523134.jpg </href> </Icon> <ViewVolume> <leftFov> -26.6666666667 </leftFov> <rightFov> 26.6666666667 </rightFov> <bottomFov> -20 </bottomFov> <topFov> 20 </topFov> <near> 10 </near> </ViewVolume> <Point> <coordinates> -122.3902159196034,37.78961266330473,0 </coordinates> </Point> </PhotoOverlay> </Document> </kml>
و این چیزی است که در Google Earth به نظر می رسد:
هشدارها
برچسب گذاری جغرافیایی عکس ها هنوز در مراحل اولیه است.
در اینجا تعدادی از موارد وجود دارد که باید از آنها آگاه بود:
- دستگاههای GPS همیشه 100% دقیق نیستند، بهویژه دستگاههایی که با دوربین عرضه میشوند، بنابراین باید موقعیت عکسهای خود را بررسی کنید.
- بسیاری از دستگاهها ارتفاع را ردیابی نمیکنند، در عوض آن را روی 0 تنظیم میکنند. اگر ارتفاع برای شما مهم است، باید راه دیگری برای گرفتن آن دادهها پیدا کنید.
- موقعیت GPS موقعیت دوربین است نه موضوع عکس. به همین دلیل است که این نمونه عنصر دوربین را در موقعیت GPS قرار می دهد و عکس واقعی را از آن موقعیت دور می کند.
- Exif اطلاعاتی در مورد جهتی که دوربین شما به سمت آن نشان می دهد نمی گیرد، بنابراین ممکن است به این دلیل نیاز به تنظیم
PhotoOverlays
خود داشته باشید. خبر خوب این است که برخی از دستگاهها، مانند تلفنهای ساخته شده بر روی سیستم عامل اندروید، به شما امکان میدهند تا دادههایی مانند جهت قطبنما و شیب را مستقیماً ضبط کنید، نه در هدرهای Exif.
تمام آنچه گفته شد، این هنوز یک راه قدرتمند برای تجسم عکس های شما است. امیدواریم در آینده نزدیک شاهد برچسب گذاری جغرافیایی بیشتر و دقیق تری از عکس ها باشیم.
از اینجا کجا برویم
اکنون که شروع به استفاده از هدرهای EXIF کردهاید، میتوانید مشخصات EXIF را بررسی کنید. دادههای زیادی در آنجا ذخیره میشوند، و ممکن است علاقه داشته باشید که آنها را بگیرید و در یک بالن توضیحات قرار دهید. همچنین ممکن است با استفاده از ImagePyramids
، PhotoOverlays
های غنی تر ایجاد کنید. مقاله راهنمای توسعه دهندگان در مورد PhotoOverlays
نمای کلی خوبی از استفاده از آنها دارد.