PyQt5 의 기본 사용방법은 앞 포스팅에서 살펴보았습니다. 이번에는 응용하여 프로그램을 하나 만들어 보겠습니다.
만들 프로그램은 사진의 GPS 정보를 이용하여 사진과 사진 사이의 거리를 측정하는 프로그램 입니다.
필요한 라이브러리
- PyQt5: GUI 애플리케이션 개발.
- Pillow (PIL): 사진 파일에서 EXIF 데이터 추출.
- 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_())
코드 설명
- GUI 구성
- QListWidget: 선택한 사진 경로를 리스트 형식으로 표시.
- QPushButton: 파일 선택 및 거리 계산 기능을 트리거.
- QLabel: 거리 계산 결과를 표시.
- 사진 선택
- QFileDialog.getOpenFileNames: 여러 장의 사진 선택.
- 선택된 파일 경로를 self.photos 리스트에 저장하고 화면에 표시.
- GPS 정보 추출
- PIL.Image의 _getexif 메서드를 사용해 EXIF 데이터 추출.
- GPSInfo를 읽어 GPS 좌표를 추출하고, 이를 소수점 형식의 경위도(latitude, longitude)로 변환.
- 거리 계산
- geopy.distance.geodesic: 두 GPS 좌표 간의 직선 거리를 계산.
- 결과는 미터 단위로 표시.
- 결과 출력
- 사진 간의 거리와 파일 이름을 화면에 표시.
실행결과
참고 포스팅
https://tylee82.tistory.com/418
https://tylee82.tistory.com/420
https://tylee82.tistory.com/413