276 lines
11 KiB
Python
276 lines
11 KiB
Python
import cv2
|
|
import numpy as np
|
|
from PyQt5.QtCore import QThread, pyqtSignal
|
|
from PyQt5.QtGui import QImage, QPixmap
|
|
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QLabel, QVBoxLayout, QPushButton, QFileDialog, QLineEdit
|
|
import requests
|
|
from PIL import Image
|
|
import os
|
|
import tempfile
|
|
|
|
class ImageThread(QThread):
|
|
finished = pyqtSignal(list)
|
|
|
|
def __init__(self, original_img_path, target_img_paths):
|
|
super().__init__()
|
|
self.original_img_path = original_img_path
|
|
self.target_img_paths = target_img_paths
|
|
|
|
def run(self):
|
|
# 원본 이미지 읽기
|
|
original_img = cv2.imread(self.original_img_path)
|
|
|
|
# 대상 이미지 연관도 분석
|
|
similarities = []
|
|
for target_img_path in self.target_img_paths:
|
|
target_img = cv2.imread(target_img_path)
|
|
similarity = self.calculate_similarity(original_img, target_img)
|
|
similarities.append(similarity)
|
|
print(f"{target_img_path} 의 연관도 : {similarity}")
|
|
|
|
# 연관도가 높은 순으로 정렬 및 결과 추출
|
|
# sorted_indices = np.argsort(similarities)[::-1]
|
|
sorted_indices = np.argsort(similarities)
|
|
sorted_target_img_paths = [self.target_img_paths[i] for i in sorted_indices]
|
|
|
|
self.finished.emit(sorted_target_img_paths)
|
|
|
|
def calculate_similarity(self, img1, img2):
|
|
# 이미지 특징 추출 (ORB)
|
|
orb = cv2.ORB_create()
|
|
kp1, des1 = orb.detectAndCompute(img1, None)
|
|
kp2, des2 = orb.detectAndCompute(img2, None)
|
|
|
|
# 특징 매칭 (BFMatcher)
|
|
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
|
|
matches = bf.match(des1, des2)
|
|
|
|
# 좋은 매칭만 추출
|
|
good_matches = [m for m in matches if m.distance < 0.75]
|
|
|
|
# 연관도 계산
|
|
similarity = len(good_matches) / len(kp1)
|
|
return similarity
|
|
|
|
|
|
|
|
|
|
class MainWindow(QMainWindow):
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
self.setWindowTitle("Image Similarity Analysis")
|
|
self.main_widget = QWidget()
|
|
self.setCentralWidget(self.main_widget)
|
|
|
|
# 레이아웃 설정
|
|
layout = QVBoxLayout()
|
|
self.main_widget.setLayout(layout)
|
|
|
|
# 원본 이미지 선택
|
|
self.original_img_label = QLabel("원본 이미지")
|
|
layout.addWidget(self.original_img_label)
|
|
self.original_img_path_edit = QLineEdit()
|
|
self.original_img_path_edit.setPlaceholderText("원본 이미지 경로를 입력하세요")
|
|
layout.addWidget(self.original_img_path_edit)
|
|
|
|
# 대상 이미지 선택
|
|
self.target_img_labels = []
|
|
self.target_img_path_edits = []
|
|
for i in range(5):
|
|
label = QLabel(f"대상 이미지 {i+1}")
|
|
layout.addWidget(label)
|
|
self.target_img_labels.append(label)
|
|
edit = QLineEdit()
|
|
edit.setPlaceholderText(f"대상 이미지 {i+1} 경로를 입력하세요")
|
|
layout.addWidget(edit)
|
|
self.target_img_path_edits.append(edit)
|
|
|
|
# 비교 버튼
|
|
self.compare_button = QPushButton("비교")
|
|
self.compare_button.clicked.connect(self.compare_images)
|
|
layout.addWidget(self.compare_button)
|
|
|
|
# 팝업 창 설정
|
|
self.popup_window = QWidget()
|
|
self.popup_window.setWindowTitle("비교 결과")
|
|
self.popup_layout = QVBoxLayout()
|
|
self.popup_window.setLayout(self.popup_layout)
|
|
|
|
# 팝업 창에 원본 이미지 표시
|
|
self.original_img_popup_label = QLabel()
|
|
self.popup_layout.addWidget(self.original_img_popup_label)
|
|
|
|
# 팝업 창에 결과 표시
|
|
self.target_img_popup_labels = []
|
|
for i in range(3):
|
|
label = QLabel()
|
|
self.popup_layout.addWidget(label)
|
|
self.target_img_popup_labels.append(label)
|
|
|
|
|
|
def download_and_process_images(self, urls):
|
|
"""
|
|
URL 리스트에서 이미지를 다운받아 'img' 폴더에 저장합니다.
|
|
|
|
Args:
|
|
urls (list): 이미지 URL 리스트
|
|
|
|
Returns:
|
|
list: 로컬 파일 경로 리스트
|
|
"""
|
|
# 'img' 폴더 경로 확인 및 생성
|
|
img_folder_path = os.path.join(os.getcwd(), 'img')
|
|
if not os.path.exists(img_folder_path):
|
|
os.makedirs(img_folder_path)
|
|
|
|
local_paths = []
|
|
for i, url in enumerate(urls):
|
|
# if i == 0:
|
|
# # filename = "original.jpg"
|
|
# else:
|
|
filename = f"target{i}.jpg"
|
|
|
|
local_path = os.path.join(img_folder_path, filename)
|
|
|
|
# 이미지 다운로드
|
|
headers = {
|
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36",
|
|
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
|
|
"Accept-Language": "en-US,en;q=0.9",
|
|
"Accept-Encoding": "gzip, deflate, br",
|
|
"DNT": "1", # Do Not Track 요청 헤더 (사용자의 추적을 거부)
|
|
"Connection": "keep-alive",
|
|
"Upgrade-Insecure-Requests": "1", # https로의 업그레이드를 요청
|
|
"Cache-Control": "max-age=0", # 캐시된 콘텐츠를 재사용하지 않도록 요청
|
|
}
|
|
response = requests.get(url, headers=headers)
|
|
|
|
if response.status_code == 200:
|
|
with open(local_path, "wb") as f:
|
|
f.write(response.content)
|
|
|
|
# 이미지 처리 로직 (필요한 경우)
|
|
# 예: 썸네일 생성, 이미지 사이즈 조정 등
|
|
|
|
local_paths.append(local_path)
|
|
else:
|
|
print(f"Error downloading image: {url}")
|
|
|
|
return local_paths
|
|
|
|
def download_and_process_image(self, urls):
|
|
"""
|
|
URL 리스트에서 이미지를 다운받아 'img' 폴더에 저장합니다.
|
|
|
|
Args:
|
|
urls (list): 이미지 URL 리스트
|
|
|
|
Returns:
|
|
list: 로컬 파일 경로 리스트
|
|
"""
|
|
# 'img' 폴더 경로 확인 및 생성
|
|
img_folder_path = os.path.join(os.getcwd(), 'ori_img')
|
|
if not os.path.exists(img_folder_path):
|
|
os.makedirs(img_folder_path)
|
|
|
|
local_paths = []
|
|
for i, url in enumerate(urls):
|
|
if i == 0:
|
|
filename = "original.jpg"
|
|
|
|
local_path = os.path.join(img_folder_path, filename)
|
|
|
|
# 이미지 다운로드
|
|
headers = {
|
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36",
|
|
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
|
|
"Accept-Language": "en-US,en;q=0.9",
|
|
"Accept-Encoding": "gzip, deflate, br",
|
|
"DNT": "1", # Do Not Track 요청 헤더 (사용자의 추적을 거부)
|
|
"Connection": "keep-alive",
|
|
"Upgrade-Insecure-Requests": "1", # https로의 업그레이드를 요청
|
|
"Cache-Control": "max-age=0", # 캐시된 콘텐츠를 재사용하지 않도록 요청
|
|
}
|
|
response = requests.get(url, headers=headers)
|
|
|
|
if response.status_code == 200:
|
|
with open(local_path, "wb") as f:
|
|
f.write(response.content)
|
|
|
|
# 이미지 처리 로직 (필요한 경우)
|
|
# 예: 썸네일 생성, 이미지 사이즈 조정 등
|
|
|
|
local_paths.append(local_path)
|
|
else:
|
|
print(f"Error downloading image: {url}")
|
|
|
|
return local_paths
|
|
|
|
def compare_images(self):
|
|
"""
|
|
입력받은 URL 이미지들을 로컬에 저장하고, 비교 스레드를 시작합니다.
|
|
"""
|
|
# 입력 경로 확인
|
|
original_img_url = self.original_img_path_edit.text()
|
|
if not original_img_url:
|
|
return
|
|
|
|
# 원본 이미지 로컬 저장 및 경로
|
|
local_paths = self.download_and_process_image([original_img_url])
|
|
if not local_paths:
|
|
return
|
|
original_img_path = local_paths[0]
|
|
self.original_img_path = local_paths[0] # 클래스 변수 업데이트
|
|
|
|
# 대상 이미지 로컬 저장 및 경로 리스트
|
|
target_img_urls = [edit.text() for edit in self.target_img_path_edits]
|
|
target_img_paths = self.download_and_process_images(target_img_urls)
|
|
if not target_img_paths:
|
|
return
|
|
|
|
# 이미지 비교 스레드 시작
|
|
self.thread = ImageThread(original_img_path, target_img_paths)
|
|
self.thread.finished.connect(self.show_results)
|
|
self.thread.start()
|
|
|
|
def add_text_to_image(self, img, text):
|
|
font = cv2.FONT_HERSHEY_SIMPLEX
|
|
font_scale = 1
|
|
font_color = (255, 0, 0) # 빨간색
|
|
font_thickness = 2
|
|
cv2.putText(img, text, (10, 30), font, font_scale, font_color, font_thickness)
|
|
|
|
|
|
def show_results(self, sorted_target_img_paths):
|
|
# 원본 이미지 팝업
|
|
original_img = cv2.imread(self.original_img_path)
|
|
original_img = cv2.resize(original_img, (200, 200))
|
|
self.add_text_to_image(original_img, "Original") # 원본 이미지에 텍스트 추가
|
|
qimage = QImage(original_img.data, original_img.shape[1], original_img.shape[0], QImage.Format_RGB888).rgbSwapped()
|
|
pixmap = QPixmap.fromImage(qimage)
|
|
self.original_img_popup_label.setPixmap(pixmap)
|
|
|
|
# 대상 이미지 팝업 업데이트
|
|
for i, label in enumerate(self.target_img_popup_labels):
|
|
if i < len(sorted_target_img_paths):
|
|
target_img_path = sorted_target_img_paths[i]
|
|
target_img = cv2.imread(target_img_path)
|
|
target_img = cv2.resize(target_img, (200, 200))
|
|
self.add_text_to_image(target_img, f"Target {i+1}") # 대상 이미지에 텍스트 추가
|
|
qimage = QImage(target_img.data, target_img.shape[1], target_img.shape[0], QImage.Format_RGB888).rgbSwapped()
|
|
pixmap = QPixmap.fromImage(qimage)
|
|
label.setPixmap(pixmap)
|
|
else:
|
|
label.setPixmap(QPixmap()) # 이미지가 없는 경우 비워둠
|
|
|
|
|
|
# 팝업 창 보여주기
|
|
self.popup_window.show()
|
|
|
|
if __name__ == "__main__":
|
|
app = QApplication([])
|
|
window = MainWindow()
|
|
window.show()
|
|
app.exec_()
|