AutoPercenty/compare.py

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_()