이탈리아 여행 지도 앨범을 Python으로 만들어 공유해 본 결과

얼마 전에 이탈리아를 여행했습니다. 밀라노 베네치아 피렌체 피사 로마 폼페이를 1주일에 돌는 투어로, 눈치채면 1000장 정도 사진을 찍고 있었습니다~.
거기 자유 시간도 있어 매일 1만 걸음 정도는 산책했기 때문에 루트 포함으로 기록에 남겨 두고 싶다, 라고 하는 것으로 맵 앨범을 만들어 보았습니다…

시각화



전체상은 이런 느낌. OpenStreetMap의지도를 사용합니다.



여기에서, 예를 들어 베니스를 확대하면, 이런 식으로 산책 루트를 볼 수 있습니다. 날에 따라 색으로 구분하고 있어, 베니스는 1박했기 때문에 2색 루트가 있네요.
그리고 마커가 사진을 찍은 포인트에서 클릭하면 사진이 팝업됩니다.



여기가 원래 사진입니다. 곤돌라 유람 중에 찍었기 때문에 마커도 수로에 있습니다.
베니스는 'ARIA'의 성지라고 하는 것으로 기대하고 있었습니다만, 기대보다 훨씬 환상적인 물의 수도였습니다. 전력으로 추천합니다.



이곳은 불후의 명작 「로마의 휴일」의 성지인 곳의 스페인 광장입니다. 나는 비행기로 보았다 (ぉ



이쪽은 분화로 멸망한 폼페이를 지켜보는 고양이입니다. 여기에 고양이가 출몰합니다. 고양이였습니다. 고맙습니다.



반응



가족이나 친구들에게 공유해 보았습니다만, 여로를 쫓으면서 사진을 보면서 추억을 말할 수 있었기 때문에, 많이 좋았습니다. 이 포장마차를 빠져나가, 이 가게에서 훌쩍 저녁 먹고, 이 길 달리고 집합 시간 빠듯했었어-, 같다.
단지 JupyterLab의 노트북을 내보낸 HTML 파일을 그대로 공유했기 때문에, 엔지니어계의 사람들은 Python의 코드를 읽기 시작해 버려, 이쪽의 이야기를 좀처럼 들어 주지 않는다고 하는 난점은 있었습니다w

절차



JupyterLab에서 50 줄 정도의 Python 코드를 작성하고 다음과 같은 처리를했습니다.
Folium은 업무에서도 사용하기 시작하고 있습니다만, 매우 간단하네요.
  • Pillow에서 이미지 파일을 읽습니다.
  • 이미지의 Exif에서 위도 및 경도 정보를 뽑습니다.
  • 화상의 Exif로부터 회전·반전의 정보를 뽑아 적용한다.
  • Folium에 위도·경도의 열을 먹여 루트를 그린다.
  • Folium에 위도·경도와 Base64로 인코딩한 이미지를 먹여 마커를 친다.
  • JupterLab에서 HTML 출력.

  • Folium의 마커에는 image 태그를 건네줄 수 있습니다만, 아무래도 로컬 파일은 참조할 수 없는 것 같기 때문에, Base64에 encode 한다고 하는 거친 기법을 사용하고 있습니다.
    덕분에 독립된 단일 HTML 파일을 출력할 수 있으므로 공유하는 것은 편합니다만, 축소하고 있다고는 해도 1000장 정도의 이미지를 쏟아 넣고 있기 때문에, 100MB 정도의 HTML 파일이 되었습니다… …w

    코드


    import base64
    import folium
    import glob
    import pandas as pd
    from io import BytesIO
    from matplotlib import pyplot as plt
    from PIL import ExifTags, Image, ImageOps
    
    def to_deg(v, ref, pos):
        d = float(v[0][0]) / float(v[0][1])
        m = float(v[1][0]) / float(v[1][1])
        s = float(v[2][0]) / float(v[2][1])
        return (d + (m / 60.0) + (s / 3600.0)) * (1 if ref == pos else -1)
    
    to_trans_methods = {
        1: [],
        2: [Image.FLIP_LEFT_RIGHT],
        3: [Image.ROTATE_180],
        4: [Image.FLIP_TOP_BOTTOM],
        5: [Image.FLIP_LEFT_RIGHT, Image.ROTATE_90],
        6: [Image.ROTATE_270],
        7: [Image.FLIP_LEFT_RIGHT, Image.ROTATE_270],
        8: [Image.ROTATE_90]
    }
    
    files = glob.glob('/path/to/*.jpg')
    
    rows = []
    for file in files:
        with Image.open(file) as im:
            exif = {ExifTags.TAGS[k]: v for k, v in im.getexif().items() if k in ExifTags.TAGS}
            if 'GPSInfo' in exif:
                gps = {ExifTags.GPSTAGS[k]: v for k, v in exif['GPSInfo'].items() if k in ExifTags.GPSTAGS}
                lat = to_deg(gps['GPSLatitude'], gps['GPSLatitudeRef'], 'N')
                lon = to_deg(gps['GPSLongitude'], gps['GPSLongitudeRef'], 'E')
                im.thumbnail((192, 192))
                for method in to_trans_methods[exif.get('Orientation', 1)]:
                    im = im.transpose(method)
                buf = BytesIO()
                im.save(buf, format="png")
                rows.append([lat, lon, exif['DateTimeOriginal'], base64.b64encode(buf.getvalue()).decode()])
    
    df = pd.DataFrame(rows, columns=['lat', 'lon', 'dt', 'base64'])
    df['dt'] = pd.to_datetime(df['dt'], format='%Y:%m:%d %H:%M:%S')
    df = df.sort_values('dt')
    
    fmap = folium.Map(location=[df['lat'].mean(), df['lon'].mean()], zoom_start=6)
    hsv=[plt.get_cmap('hsv', 12)(i) for i in range(12)]
    fmap.add_child(folium.ColorLine(zip(df['lat'], df['lon']), colors=df['dt'].dt.day, colormap=hsv, weight=4))
    for _, row in df.iterrows():
        fmap.add_child(folium.Marker([row['lat'], row['lon']], popup=f'<img src="data:image/png;base64,{row["base64"]}">'))
    fmap
    

    실행 환경


    $ python --version
    Python 3.7.4
    
    $ pip list | grep -e folium -e jupyter -e matplotlib -e pandas -e Pillow
    folium               0.10.1    
    jupyter-client       5.3.3     
    jupyter-core         4.5.0     
    jupyterlab           1.1.4     
    jupyterlab-server    1.0.6     
    matplotlib           3.1.2     
    pandas               1.0.1     
    Pillow               7.0.0     
    

    참고 링크



    Python에서 사진에 내장 된 GPS 정보에서 촬영 장소를 확인합시다 |
    PIL에서 EXIF ​​Orientation 태그를 고려한 처리 | Qiita
    View image on popup | python-visualization/folium

    좋은 웹페이지 즐겨찾기