aafa
import cv2
import numpy as np
import pytesseract
import time
import pyautogui
import threading
import tkinter as tk
import re
from deep_translator import GoogleTranslator
from PIL import Image, ImageTk
from difflib import SequenceMatcher
# OCR motoru ayarı
pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe'
class RegionSelector:
def __init__(self, callback):
self.callback = callback
self.root = tk.Tk()
self.root.attributes('-fullscreen', True)
self.root.attributes('-alpha', 0.3)
self.root.configure(bg='grey')
self.canvas = tk.Canvas(self.root, cursor="cross", bg="grey")
self.canvas.pack(fill=tk.BOTH, expand=True)
self.start_x = None
self.start_y = None
self.current_rect = None
self.canvas.bind("<ButtonPress-1>", self.on_press)
self.canvas.bind("<B1-Motion>", self.on_drag)
self.canvas.bind("<ButtonRelease-1>", self.on_release)
self.instruction = tk.Label(self.root,
text="Çevirmek istediğiniz bölgeyi seçin\nİptal için ESC tuşuna basın",
font=("Arial", 14), bg="black", fg="white", bd=2)
self.instruction.place(relx=0.5, rely=0.1, anchor=tk.CENTER)
self.root.bind("<Escape>", self.cancel)
self.root.mainloop()
def on_press(self, event):
self.start_x = self.canvas.canvasx(event.x)
self.start_y = self.canvas.canvasy(event.y)
if self.current_rect:
self.canvas.delete(self.current_rect)
self.current_rect = self.canvas.create_rectangle(
self.start_x, self.start_y, self.start_x, self.start_y,
outline='red', width=2
)
def on_drag(self, event):
cur_x = self.canvas.canvasx(event.x)
cur_y = self.canvas.canvasy(event.y)
self.canvas.coords(self.current_rect, self.start_x, self.start_y, cur_x, cur_y)
def on_release(self, event):
end_x = self.canvas.canvasx(event.x)
end_y = self.canvas.canvasy(event.y)
x1 = min(self.start_x, end_x)
y1 = min(self.start_y, end_y)
x2 = max(self.start_x, end_x)
y2 = max(self.start_y, end_y)
if (x2 - x1 > 20) and (y2 - y1 > 20):
self.root.destroy()
self.callback((int(x1), int(y1), int(x2-x1), int(y2-y1)))
else:
messagebox.showwarning("Uyarı", "Lütfen daha büyük bir alan seçin!")
def cancel(self, event):
self.root.destroy()
self.callback(None)
class HitmanTranslator:
def __init__(self):
self.running = False
self.last_text = ""
self.target_language = "tr"
self.setup_overlay()
self.translation_history = {}
# Varsayılan yakalama bölgesi
self.capture_region = (150, 850, 1620, 130)
self.custom_region_set = False
# Metin stabilizasyonu için
self.text_buffer = []
self.buffer_size = 3
self.min_confidence_threshold = 50 # OCR güven eşiği (0-100)
self.min_text_length = 5 # Minimum anlamlı metin uzunluğu
self.similar_text_threshold = 0.7 # Benzerlik oranı (0-1)
# OCR algılama kararlılığı
self.consecutive_matches = 0
self.required_consecutive = 2 # Kaç kez aynı metin algılanmalı
# Saçma karakter filtreleme
self.gibberish_pattern = re.compile(r'^[a-zA-Z\s]{1,2}$|^[^a-zA-Z0-9\s]{1,3}$|^[a-zA-Z]{1,2}$|^\s*[a-zA-Z]\s*$')
def setup_overlay(self):
self.overlay = tk.Tk()
self.overlay.attributes('-topmost', True)
self.overlay.attributes('-alpha', 0.8)
self.overlay.geometry('600x250+50+50')
self.overlay.configure(bg='black')
self.overlay.overrideredirect(True)
# Kontrol paneli
control_frame = tk.Frame(self.overlay, bg="black")
control_frame.pack(side=tk.TOP, fill=tk.X)
# Bölge seçim butonu
select_region_button = tk.Button(control_frame, text="Bölge Seç",
command=self.select_region, bg="blue", fg="white")
select_region_button.pack(side=tk.LEFT, padx=5, pady=5)
# Varsayılan bölgeye dönme butonu
default_region_button = tk.Button(control_frame, text="Varsayılan Bölge",
command=self.reset_to_default_region, bg="green", fg="white")
default_region_button.pack(side=tk.LEFT, padx=5, pady=5)
# Çeviriyi temizleme butonu
clear_button = tk.Button(control_frame, text="Temizle",
command=self.clear_translation, bg="orange", fg="white")
clear_button.pack(side=tk.LEFT, padx=5, pady=5)
# Pencereyi taşımak için düğme
move_button = tk.Button(control_frame, text="Taşı", bg="gray", fg="white")
move_button.pack(side=tk.LEFT, padx=5, pady=5)
move_button.bind("<ButtonPress-1>", self.start_move)
move_button.bind("<ButtonRelease-1>", self.stop_move)
move_button.bind("<B1-Motion>", self.on_motion)
# Çıkış butonu
exit_button = tk.Button(control_frame, text="X", command=self.stop,
bg="red", fg="white", width=2)
exit_button.pack(side=tk.RIGHT, padx=5, pady=5)
# Bölge bilgisi
self.region_label = tk.Label(self.overlay,
text="Varsayılan bölge kullanılıyor",
bg="black", fg="yellow", font=("Arial", 10))
self.region_label.pack(pady=2)
# Algılanan metin bilgisi
self.detected_text_label = tk.Label(self.overlay,
text="Algılanan: -",
bg="black", fg="cyan", font=("Arial", 10))
self.detected_text_label.pack(pady=2)
# Çeviri metni için etiket
self.label = tk.Label(self.overlay, text="Çeviri bekleniyor...",
fg="white", bg="black", wraplength=580,
font=("Arial", 14), justify=tk.LEFT)
self.label.pack(pady=10, padx=10, fill=tk.BOTH, expand=True)
# Görüntü önizleme için frame
self.preview_frame = tk.Frame(self.overlay, bg="black", height=50)
self.preview_frame.pack(side=tk.BOTTOM, fill=tk.X)
self.preview_label = tk.Label(self.preview_frame, bg="black")
self.preview_label.pack(pady=5)
def clear_translation(self):
self.label.config(text="Çeviri bekleniyor...")
self.detected_text_label.config(text="Algılanan: -")
self.text_buffer = []
self.last_text = ""
self.consecutive_matches = 0
def select_region(self):
self.overlay.withdraw()
time.sleep(0.5)
RegionSelector(self.region_callback)
def region_callback(self, region):
self.overlay.deiconify()
if region:
self.capture_region = region
self.custom_region_set = True
self.region_label.config(text=f"Özel bölge: {region}")
print(f"Yeni bölge seçildi: {region}")
# Bölge değiştiğinde tamponları temizle
self.clear_translation()
def reset_to_default_region(self):
self.capture_region = (150, 850, 1620, 130)
self.custom_region_set = False
self.region_label.config(text="Varsayılan bölge kullanılıyor")
# Bölge değiştiğinde tamponları temizle
self.clear_translation()
def start_move(self, event):
self.x = event.x
self.y = event.y
def stop_move(self, event):
self.x = None
self.y = None
def on_motion(self, event):
deltax = event.x - self.x
deltay = event.y - self.y
x = self.overlay.winfo_x() + deltax
y = self.overlay.winfo_y() + deltay
self.overlay.geometry(f"+{x}+{y}")
def start(self):
self.running = True
self.overlay.deiconify()
threading.Thread(target=self.translation_loop, daemon=True).start()
def stop(self):
self.running = False
self.overlay.destroy()
def is_gibberish(self, text):
# Anlamsız kısa metinleri veya tekrarlayan harfleri filtrele
if len(text.strip()) < self.min_text_length:
return True
# Tekrarlayan karakterleri kontrol et
char_counts = {}
for char in text:
if char in char_counts:
char_counts[char] += 1
else:
char_counts[char] = 1
# Bir karakter toplam metnin %60'ından fazlasını oluşturuyorsa gibberish olarak işaretle
for char, count in char_counts.items():
if count > len(text) * 0.6 and len(text) > 3:
return True
# Anlamsız kısa karakter dizileri için düzenli ifade kontrolü
if self.gibberish_pattern.match(text):
return True
# Harf ve boşluk dışında pek bir şey yoksa anlamsız kabul et
if len(re.sub(r'[a-zA-Z\s]', '', text)) < 2 and len(text) < 10:
return True
return False
def similar_text_exists(self, text):
# Son algılanan metinlerde benzer bir metin var mı?
for old_text in self.text_buffer:
similarity = SequenceMatcher(None, text, old_text).ratio()
if similarity > self.similar_text_threshold:
return True
return False
def capture_subtitles(self):
# Görüntüyü yakala
screenshot = pyautogui.screenshot(region=self.capture_region)
img = np.array(screenshot)
img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
# Önizleme için görüntüyü küçült
h, w = img.shape[:2]
aspect = w / h
preview_width = 300
preview_height = int(preview_width / aspect)
preview_img = cv2.resize(img, (preview_width, preview_height))
self.update_preview(preview_img)
# Geliştirilmiş görüntü işleme
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Filtreleme ve kontrast iyileştirme
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
enhanced = clahe.apply(blurred)
# Binarizasyon (ikili görüntüye dönüştürme)
_, thresh = cv2.threshold(enhanced, 150, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
# Gürültü azaltma
kernel = np.ones((2, 2), np.uint8)
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
# OCR ayarları - daha sıkı parametreler
config = '--psm 6 --oem 3 -c tessedit_char_whitelist="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,:;\'\"!?-() "'
# Sadece güven derecesi yüksek metinleri al
data = pytesseract.image_to_data(thresh, lang='eng', config=config, output_type=pytesseract.Output.DICT)
# Güven değeri yüksek metinleri birleştir
text_parts = []
for i in range(len(data['text'])):
# Güven değeri eşiğimizden yüksek olan kelimeler
if int(data['conf'][i]) > self.min_confidence_threshold:
text_parts.append(data['text'][i])
text = ' '.join(text_parts)
# Temizleme
text = self.clean_text(text)
# Algılanan metni göster
max_display_len = 30
display_text = text if len(text) <= max_display_len else text[:max_display_len] + "..."
self.detected_text_label.config(text=f"Algılanan: {display_text}")
return text
def update_preview(self, img):
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = Image.fromarray(img)
img = ImageTk.PhotoImage(image=img)
self.preview_label.configure(image=img)
self.preview_label.image = img
def clean_text(self, text):
if not text:
return ""
# Temel temizlik
text = text.strip()
# Fazla boşlukları temizle
text = re.sub(r'\s+', ' ', text)
# Tek harfleri temizle
text = re.sub(r'\b[a-zA-Z]\b', '', text)
# Rakam olmayan sayıları kaldır
text = re.sub(r'[^\w\s\.,;:\-\?\!\'\"]+', '', text)
return text.strip()
def translate_text(self, text):
if not text or len(text) < self.min_text_length:
return None
# Saçma metin kontrolü
if self.is_gibberish(text):
print(f"Saçma metin algılandı ve filtrelendi: '{text}'")
return None
# Çok kısa metinleri engelle
if len(text.split()) < 2 and len(text) < 10:
print(f"Çok kısa metin filtrelendi: '{text}'")
return None
# Son metinle aynıysa yeniden çevirme
if text == self.last_text:
return self.translation_history.get(text, None)
# Daha önce çevrilmişse cache'den al
if text in self.translation_history:
self.last_text = text
return self.translation_history[text]
try:
# Çeviri yap
result = GoogleTranslator(source='auto', target=self.target_language).translate(text)
if result:
self.last_text = text
self.translation_history[text] = result
return result
return None
except Exception as e:
print(f"Çeviri hatası: {e}")
return None
def translation_loop(self):
consecutive_empty = 0
while self.running:
try:
# Metni yakala
game_text = self.capture_subtitles()
# Metin yoksa veya anlamsızsa
if not game_text or self.is_gibberish(game_text):
consecutive_empty += 1
time.sleep(0.5)
continue
# Benzer metin daha önce algılanmış mı kontrol et
if game_text == self.last_text:
self.consecutive_matches += 1
else:
self.consecutive_matches = 1
# Aynı metin belirli sayıda kez algılanırsa çevir
if self.consecutive_matches >= self.required_consecutive:
print(f"Kararlı metin algılandı: {game_text}")
translated = self.translate_text(game_text)
if translated:
consecutive_empty = 0
self.label.config(text=translated)
print(f"Çeviri: {translated}")
# Tampon belleğe ekle
self.text_buffer.append(game_text)
if len(self.text_buffer) > self.buffer_size:
self.text_buffer.pop(0)
# Metin bulunamadıysa
if consecutive_empty > 10: # 5 saniye
if self.label['text'] != "Çeviri bekleniyor...":
self.label.config(text="Çeviri bekleniyor...")
self.detected_text_label.config(text="Algılanan: -")
consecutive_empty = 0
time.sleep(0.5)
except Exception as e:
print(f"Döngü hatası: {e}")
time.sleep(1)
def run(self):
try:
self.start()
self.overlay.mainloop()
except KeyboardInterrupt:
self.stop()
if __name__ == "__main__":
translator = HitmanTranslator()
translator.run()