728x90
반응형

 

PyQt5 의 기본 사용방법은 앞 포스팅에서 살펴보았습니다. 이번에는 응용하여 프로그램을 하나 만들어 보겠습니다. 

만들 프로그램은 사진의 GPS 정보를 이용하여 사진과 사진 사이의 거리를 측정하는 프로그램 입니다.


필요한 라이브러리

  1. PyQt5: GUI 애플리케이션 개발.
  2. Pillow (PIL): 사진 파일에서 EXIF 데이터 추출.
  3. geopy: GPS 좌표를 사용한 거리 계산.

설치 명령어

아래 명령어를 사용해 필요한 라이브러리를 설치하세요:

pip install pyqt5 pillow geopy

실행코드

import sys
import os
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QFileDialog, QListWidget, QVBoxLayout, QPushButton, QLabel, QWidget
)
from PIL import Image
from PIL.ExifTags import TAGS, GPSTAGS
from geopy.distance import geodesic


class GPSDistanceApp(QMainWindow):

    def __init__(self):
        super().__init__()
        self.initUI()
        self.photos = []  # 선택한 사진 경로 리스트
        self.gps_data = []  # 사진의 GPS 정보 리스트

    def initUI(self):
        # 위젯 설정
        self.setWindowTitle("GPS Distance Calculator")
        self.setGeometry(300, 300, 600, 400)

        self.centralWidget = QWidget()
        self.setCentralWidget(self.centralWidget)

        layout = QVBoxLayout()

        self.photoList = QListWidget()
        self.resultLabel = QLabel("Distances will appear here.")

        self.selectButton = QPushButton("Select Photos")
        self.selectButton.clicked.connect(self.openFileDialog)

        self.calculateButton = QPushButton("Calculate Distances")
        self.calculateButton.clicked.connect(self.calculateDistances)

        layout.addWidget(self.photoList)
        layout.addWidget(self.selectButton)
        layout.addWidget(self.calculateButton)
        layout.addWidget(self.resultLabel)

        self.centralWidget.setLayout(layout)

    def openFileDialog(self):
        # 여러 사진 선택
        filePaths, _ = QFileDialog.getOpenFileNames(self, "Select Photos", "", "Images (*.jpg *.jpeg *.png)")
        if filePaths:
            self.photos = filePaths
            self.photoList.clear()
            self.photoList.addItems(filePaths)

    def extractGPS(self, photoPath):
        try:
            img = Image.open(photoPath)
            exif_data = img._getexif()
            if not exif_data:
                return None
            gps_info = {}
            for tag, value in exif_data.items():
                tag_name = TAGS.get(tag, tag)
                if tag_name == "GPSInfo":
                    for gps_tag in value.keys():
                        gps_name = GPSTAGS.get(gps_tag, gps_tag)
                        gps_info[gps_name] = value[gps_tag]
            if gps_info:
                return self.convertGPS(gps_info)
            return None
        except Exception as e:
            print(f"Error reading GPS data: {e}")
            return None

    def convertGPS(self, gps_info):
        """Convert GPS EXIF data to latitude and longitude in decimal format."""
        def to_decimal(coord, ref):
            degrees, minutes, seconds = coord
            decimal = degrees + (minutes / 60.0) + (seconds / 3600.0)
            if ref in ['S', 'W']:
                return -decimal
            return decimal

        try:
            lat = to_decimal(gps_info["GPSLatitude"], gps_info["GPSLatitudeRef"])
            lon = to_decimal(gps_info["GPSLongitude"], gps_info["GPSLongitudeRef"])
            return lat, lon
        except KeyError:
            return None

    def calculateDistances(self):
        # GPS 정보 추출
        self.gps_data = [self.extractGPS(photo) for photo in self.photos]

        # 유효하지 않은 GPS 정보 확인
        if None in self.gps_data:
            self.resultLabel.setText("Some photos do not have valid GPS data.")
            return

        # 거리 계산
        distances = []
        for i in range(len(self.gps_data) - 1):
            dist = geodesic(self.gps_data[i], self.gps_data[i + 1]).meters
            distances.append(dist)

        # 결과 출력
        result_text = "Distances between photos:\n"
        for i, dist in enumerate(distances):
            result_text += f"{os.path.basename(self.photos[i])} -> {os.path.basename(self.photos[i + 1])}: {dist:.2f} m\n"
        self.resultLabel.setText(result_text)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = GPSDistanceApp()
    ex.show()
    sys.exit(app.exec_())

 


코드 설명

  1. GUI 구성
    • QListWidget: 선택한 사진 경로를 리스트 형식으로 표시.
    • QPushButton: 파일 선택 및 거리 계산 기능을 트리거.
    • QLabel: 거리 계산 결과를 표시.
  2. 사진 선택
    • QFileDialog.getOpenFileNames: 여러 장의 사진 선택.
    • 선택된 파일 경로를 self.photos 리스트에 저장하고 화면에 표시.
  3. GPS 정보 추출
    • PIL.Image의 _getexif 메서드를 사용해 EXIF 데이터 추출.
    • GPSInfo를 읽어 GPS 좌표를 추출하고, 이를 소수점 형식의 경위도(latitude, longitude)로 변환.
  4. 거리 계산
    • geopy.distance.geodesic: 두 GPS 좌표 간의 직선 거리를 계산.
    • 결과는 미터 단위로 표시.
  5. 결과 출력
    • 사진 간의 거리와 파일 이름을 화면에 표시.

728x90

실행결과

 

 


참고 포스팅

https://tylee82.tistory.com/418

 

PyQt5: QGridLayout으로 깔끔한 레이아웃 만들기

QGridLayout은 PyQt5에서 제공하는 레이아웃 관리 도구 중 하나로, 위젯들을 행(row)과 열(column)로 구성된 그리드 형태로 배치할 수 있습니다.이번 포스팅에서는 QGridLayout의 사용법과 예제 코드를 자세

tylee82.tistory.com

https://tylee82.tistory.com/420

 

QFileDialog를 활용한 파일 열기와 저장하기

QFileDialog는 PyQt5에서 파일 또는 디렉터리를 선택하는 대화 상자를 제공하는 클래스입니다. 파일 열기와 저장을 간단히 구현할 수 있어 응용 프로그램 개발에 자주 사용됩니다. 이번 포스팅에서

tylee82.tistory.com

https://tylee82.tistory.com/413

 

파이썬으로 이미지의 GPS 정보 읽기

사진 속에는 우리가 눈으로 볼 수 없는 다양한 메타데이터가 포함되어 있습니다. 특히 스마트폰이나 GPS 기능이 있는 카메라로 촬영한 사진에는 GPS 정보가 포함될 수 있습니다. 이번 포스팅에서

tylee82.tistory.com

 

728x90
반응형

+ Recent posts