Bu yazıda, kullanıcıların resimlerden metin çıkarıp, bu metni seçilen bir dile çevirebileceği bir OCR (Optical Character Recognition) ve çeviri uygulaması geliştireceğiz. Bu uygulama, görsellerden metin tanıyacak, ardından bu metni çevirecek ve kullanıcılara çevrilmiş metni gösterecek. Uygulamanın özellikleri arasında resim yükleme (sürükle-bırak), dil seçme ve metin kopyalama gibi işlevler yer alacak.

1. Gereksinimler ve Kurulum

Bu uygulamayı çalıştırmak için aşağıdaki Python kütüphanelerine ihtiyacınız olacak:

Tüm gereksinimleri kurmak için aşağıdaki gibi bir bat dosyası oluşturup çalıştırabilirsiniz:

@echo off
python --version >nul 2>&1
if %errorlevel% neq 0 (
    echo Python bulunamadi, kurulum baslatiliyor...
    echo Python 3.11.5 indiriliyor...
    curl -o python-installer.exe https://www.python.org/ftp/python/3.11.5/python-3.11.5-amd64.exe
    start /wait python-installer.exe /quiet InstallAllUsers=1 PrependPath=1
    del python-installer.exe
    echo Python kuruldu.
)
echo Pip guncelleniyor...
python -m pip install --upgrade pip
set "requirements=tkinter pillow paddleocr deep-translator tkinterdnd2 pyperclip"
for %%k in (%requirements%) do (
    python -c "import %%k" >nul 2>&1
    if %errorlevel% neq 0 (
        echo %%k kutuphanesi bulunamadi, kurulum baslatiliyor...
        python -m pip install %%k
    )
)
echo Tum kutuphaneler kurulu. Uygulamayi calistirabilirsiniz.
pause

2. Uygulama Tasarımı

Uygulamamızda bir kullanıcı arayüzü (GUI) olacak ve bu arayüzde aşağıdaki bileşenler bulunacak:

3. Kaynak Kod

Aşağıda, uygulamanın tüm kodunu bulabilirsiniz. Kodda detaylı açıklamalar yer almakta, böylece her adımı detaylıca inceleyebilirsiniz:

import tkinter as tk
from tkinter import ttk, messagebox
from PIL import Image, ImageTk
from paddleocr import PaddleOCR
from deep_translator import GoogleTranslator
import threading
from tkinterdnd2 import DND_FILES, TkinterDnD
import pyperclip


class FuturisticOCRTranslator:
    """
    Fütüristik görünümlü OCR ve çeviri uygulaması.
    Görüntülerden metin çıkarımı yapıp farklı dillere çeviri yapar.
    """
    def __init__(self):
        # Ana pencere ayarları
        self.root = TkinterDnD.Tk()
        self.root.title("OCR Çeviri")
        self.root.geometry("1200x450")
        self.root.configure(bg='#0a0a1f')

        # Combobox stil ayarları
        self.root.option_add('*TCombobox*Listbox.background', '#0a0a1f')
        self.root.option_add('*TCombobox*Listbox.foreground', '#00ff8c')
        self.root.option_add('*TCombobox*Listbox.selectBackground', '#1a1a3f')
        self.root.option_add('*TCombobox*Listbox.selectForeground', '#00ff8c')

        # Animasyon ve görüntü değişkenleri
        self.border_color_index = 0
        self.current_image = None
        self.MAX_IMAGE_SIZE = (250, 200)

        # Uygulama renk paleti
        self.colors = {
            'bg': '#0a0a1f',
            'accent': '#00FF00',
            'secondary': '#0066ff',
            'text': '#00ff8c',
            'border': '#00ccff',
            'box_bg': '#0f0f2f',
            'button_bg': '#1a1a3f'
        }

        # Ttk stil yapılandırması
        self.style = ttk.Style()
        self.style.theme_use('default')
        self.configure_styles()

        # Desteklenen diller sözlüğü
        self.languages = {
            'Türkçe': 'tr',
            'İngilizce': 'en',
            'Almanca': 'de',
            'Fransızca': 'fr',
            'İspanyolca': 'es',
            'İtalyanca': 'it',
            'Rusça': 'ru',
            'Japonca': 'ja',
            'Korece': 'ko',
            'Çince': 'zh-CN'
        }

        self.setup_ui()
        self.ocr = PaddleOCR(use_angle_cls=True, lang='en')
        self.animate_borders()

    def configure_styles(self):
        """Ttk bileşenleri için özel stillerin yapılandırılması"""
        self.style.configure('Cyber.TFrame', background=self.colors['bg'])
        self.style.configure('Cyber.TLabel',
                             background=self.colors['bg'],
                             foreground=self.colors['text'],
                             font=('Consolas', 11))
        self.style.configure('CyberTitle.TLabel',
                             background=self.colors['bg'],
                             foreground=self.colors['accent'],
                             font=('Consolas', 24, 'bold'))
        self.style.configure('CyberSubTitle.TLabel',
                             background=self.colors['bg'],
                             foreground='#888888',
                             font=('Consolas', 12))

        self.style.map('TCombobox',
                       fieldbackground=[('readonly', self.colors['bg'])],
                       selectbackground=[('readonly', self.colors['bg'])],
                       selectforeground=[('readonly', self.colors['text'])],
                       background=[('readonly', self.colors['bg'])],
                       foreground=[('readonly', self.colors['text'])])

        self.style.configure('TCombobox',
                             background=self.colors['bg'],
                             fieldbackground=self.colors['bg'],
                             foreground=self.colors['text'],
                             arrowcolor=self.colors['accent'],
                             selectbackground=self.colors['bg'],
                             selectforeground=self.colors['text'])

        self.style.configure('Cyber.TButton',
                             background=self.colors['button_bg'],
                             foreground=self.colors['text'],
                             borderwidth=2,
                             font=('Consolas', 10))

    def setup_ui(self):
        """Kullanıcı arayüzünün oluşturulması"""
        self.main_frame = ttk.Frame(self.root, style='Cyber.TFrame')
        self.main_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=10)

        title_frame = ttk.Frame(self.main_frame, style='Cyber.TFrame')
        title_frame.pack(fill=tk.X, pady=(0, 10))

        title = ttk.Label(title_frame,
                          text="LEIDENFROST OCR ÇEVİRİ 🈯",
                          style='CyberTitle.TLabel')
        title.pack()

        subtitle = ttk.Label(title_frame,
                             text="Gelişmiş Görüntü Tanıma ve Çeviri Sistemi",
                             style='CyberSubTitle.TLabel')
        subtitle.pack()

        # Kontrol paneli
        self.control_frame = ttk.Frame(self.main_frame, style='Cyber.TFrame')
        self.control_frame.pack(fill=tk.X, pady=(0, 10))

        # Dil seçimi
        lang_frame = ttk.Frame(self.control_frame, style='Cyber.TFrame')
        lang_frame.pack(pady=5)

        ttk.Label(lang_frame, text="KAYNAK ⟶", style='Cyber.TLabel').pack(side=tk.LEFT, padx=(0, 10))

        self.source_lang = ttk.Combobox(lang_frame,
                                        values=['Otomatik'],
                                        state='readonly',
                                        style='TCombobox',
                                        width=15)
        self.source_lang.pack(side=tk.LEFT, padx=(0, 20))
        self.source_lang.set('Otomatik')

        ttk.Label(lang_frame, text="HEDEF ⟶", style='Cyber.TLabel').pack(side=tk.LEFT, padx=(0, 10))

        self.target_lang = ttk.Combobox(lang_frame,
                                        values=list(self.languages.keys()),
                                        state='readonly',
                                        style='TCombobox',
                                        width=15)
        self.target_lang.pack(side=tk.LEFT)
        self.target_lang.set('Türkçe')

        self.source_lang.bind('<<ComboboxSelected>>', lambda e: self.update_combobox_colors(self.source_lang))
        self.target_lang.bind('<<ComboboxSelected>>', lambda e: self.update_combobox_colors(self.target_lang))
        self.root.after(10, lambda: self.update_combobox_colors(self.source_lang))
        self.root.after(10, lambda: self.update_combobox_colors(self.target_lang))

        # İçerik bölümü
        content_frame = ttk.Frame(self.main_frame, style='Cyber.TFrame')
        content_frame.pack(fill=tk.BOTH, expand=True)
        content_frame.grid_columnconfigure(0, weight=1)
        content_frame.grid_columnconfigure(1, weight=1)

        # Görüntü bölümü
        self.image_frame = tk.Frame(content_frame, bg=self.colors['bg'])
        self.image_frame.grid(row=0, column=0, sticky='nsew', padx=(0, 10))

        # Animasyonlu kenarlıklar
        self.border_frames = []
        current_frame = self.image_frame
        for i in range(3):
            frame = tk.Frame(current_frame, bg=self.colors['border'])
            frame.pack(fill=tk.BOTH, expand=True, padx=2, pady=2)
            self.border_frames.append(frame)
            current_frame = frame

        # İç frame
        self.inner_frame = tk.Frame(self.border_frames[-1], bg=self.colors['bg'])
        self.inner_frame.pack(fill=tk.BOTH, expand=True, padx=2, pady=2)

        self.image_container = ttk.Frame(self.inner_frame, style='Cyber.TFrame')
        self.image_container.pack(fill=tk.BOTH, expand=True)

        # Sürükle-bırak etiketi
        self.drop_label = ttk.Label(
            self.image_container,
            text=(
                "⤓ RESİM SÜRÜKLE BIRAK ⤓\n\n"
                "Desteklenen formatlar: PNG, JPG, JPEG, BMP, GIF\n"
                "WEBP, TIFF, TIF, HEIF, HEIC, RAW\n\n"
                "Resme tıklayarak tam ekran görüntüle"
            ),
            style='Cyber.TLabel'
        )
        self.drop_label.pack(fill=tk.BOTH, expand=True)

        # Görüntü etiketi
        self.image_label = ttk.Label(self.image_container, style='Cyber.TLabel')

        # Temizle butonu
        self.clear_button = tk.Button(self.inner_frame,
                                      text="🗑 RESMİ TEMİZLE",
                                      command=self.clear_image,
                                      bg=self.colors['button_bg'],
                                      fg=self.colors['text'],
                                      activebackground=self.colors['accent'],
                                      activeforeground=self.colors['bg'],
                                      font=('Consolas', 10),
                                      bd=0,
                                      padx=10,
                                      cursor='hand2')

        # Sonuç bölümü
        result_outer_frame = tk.Frame(content_frame, bg=self.colors['border'])
        result_outer_frame.grid(row=0, column=1, sticky='nsew', padx=(10, 0))

        self.result_frame = tk.Frame(result_outer_frame, bg=self.colors['box_bg'])
        self.result_frame.pack(fill=tk.BOTH, expand=True, padx=2, pady=2)

        text_header = tk.Frame(self.result_frame, bg=self.colors['box_bg'])
        text_header.pack(fill=tk.X, padx=10, pady=5)

        ttk.Label(text_header, text="Çeviri Sonucu:", style='Cyber.TLabel').pack(side=tk.LEFT)

        # Kopyala butonu
        copy_button = tk.Button(text_header,
                                text="📋 KOPYALA",
                                command=self.copy_text,
                                bg=self.colors['button_bg'],
                                fg=self.colors['text'],
                                activebackground=self.colors['accent'],
                                activeforeground=self.colors['bg'],
                                font=('Consolas', 10),
                                bd=0,
                                padx=10,
                                cursor='hand2')
        copy_button.pack(side=tk.RIGHT)

        # Sonuç metin alanı
        self.text_label = tk.Text(self.result_frame,
                                  wrap=tk.WORD,
                                  font=('Consolas', 11),
                                  bg=self.colors['box_bg'],
                                  fg=self.colors['text'],
                                  insertbackground=self.colors['text'],
                                  selectbackground=self.colors['accent'],
                                  selectforeground=self.colors['bg'],
                                  bd=0,
                                  height=10,
                                  padx=10,
                                  pady=10)
        self.text_label.pack(fill=tk.BOTH, expand=True)

        # Sürükle-bırak ve fare olayları
        self.drop_label.drop_target_register(DND_FILES)
        self.drop_label.dnd_bind('<<Drop>>', self.handle_drop)
        self.inner_frame.bind('<Enter>', self.on_hover_enter)
        self.inner_frame.bind('<Leave>', self.on_hover_leave)

    def update_combobox_colors(self, combobox):
        combobox.configure(
            foreground=self.colors['text'],
            background=self.colors['bg']
        )

    def clear_image(self):
        self.current_image = None
        self.image_label.pack_forget()
        self.drop_label.pack(fill=tk.BOTH, expand=True)
        self.clear_button.pack_forget()
        self.text_label.delete(1.0, tk.END)

    def copy_text(self):
        text = self.text_label.get(1.0, tk.END).strip()
        pyperclip.copy(text)

        temp_label = tk.Label(self.result_frame,
                              text="✓ Kopyalandı!",
                              fg=self.colors['accent'],
                              bg=self.colors['box_bg'],
                              font=('Consolas', 10))
        temp_label.place(relx=1, rely=0, anchor='ne')
        self.root.after(1000, temp_label.destroy)

    def animate_borders(self):
        colors = ['#00ccff', '#00ff8c', '#0066ff', '#ff00ff']
        for i, frame in enumerate(self.border_frames):
            new_color = colors[(i + self.border_color_index) % len(colors)]
            frame.configure(bg=new_color)
        self.border_color_index = (self.border_color_index + 1) % len(colors)
        self.root.after(1000, self.animate_borders)

    def on_hover_enter(self, event):
        self.drop_label.configure(foreground=self.colors['accent'])

    def on_hover_leave(self, event):
        self.drop_label.configure(foreground=self.colors['text'])

    def handle_drop(self, event):
        file_paths = event.data.split()

        if len(file_paths) > 1:
            messagebox.showerror("Hata", "Lütfen aynı anda sadece bir resim sürükleyin!")
            return

        file_path = file_paths[0]
        if file_path.startswith('{'):
            file_path = file_path[1:-1]

        if not file_path.lower().endswith((
            '.png', '.jpg', '.jpeg', '.bmp', '.gif', '.webp',
            '.tiff', '.tif', '.heif', '.heic', '.raw'
        )):
            messagebox.showerror("Hata", "Lütfen geçerli bir resim dosyası seçin!")
            return

        try:
            Image.open(file_path)
        except:
            messagebox.showerror("Hata", "Seçilen dosya geçerli bir resim değil!")
            return

        self.display_image(file_path)
        self.process_image(file_path)

    def display_image(self, file_path):
        self.drop_label.pack_forget()
        self.current_image = Image.open(file_path)
        display_size = self.calculate_display_size(self.current_image)
        image = self.current_image.resize(display_size, Image.Resampling.LANCZOS)
        photo = ImageTk.PhotoImage(image)
        self.image_label.configure(image=photo)
        self.image_label.image = photo
        self.image_label.pack(expand=True)
        self.clear_button.pack(pady=5)

    def calculate_display_size(self, image):
        max_width, max_height = self.MAX_IMAGE_SIZE
        width, height = image.size
        aspect_ratio = width / height

        if width > max_width or height > max_height:
            if aspect_ratio > max_width / max_height:
                new_width = max_width
                new_height = int(max_width / aspect_ratio)
            else:
                new_height = max_height
                new_width = int(max_height * aspect_ratio)
        else:
            new_width, new_height = width, height

        return (new_width, new_height)

    def process_image(self, file_path):
        """OCR ve çeviri işlemini gerçekleştirme"""
        def process():
            try:
                self.text_label.delete(1.0, tk.END)
                self.text_label.insert(tk.END, "İşleniyor...\n")

                # OCR
                result = self.ocr.ocr(file_path, cls=True)
                extracted_text = '\n'.join([line[1][0] for line in result[0]])

                # Çeviri
                target = self.languages[self.target_lang.get()]
                translator = GoogleTranslator(source='auto', target=target)
                translated_text = translator.translate(extracted_text)

                self.text_label.delete(1.0, tk.END)
                self.text_label.insert(tk.END, translated_text)

            except Exception as e:
                messagebox.showerror("Hata", f"İşlem sırasında bir hata oluştu: {str(e)}")
                self.text_label.delete(1.0, tk.END)
                self.text_label.insert(tk.END, "İşlem sırasında hata oluştu.")

        threading.Thread(target=process, daemon=True).start()

    def run(self):
        self.root.mainloop()


if __name__ == "__main__":
    app = FuturisticOCRTranslator()
    app.run()

4. Uygulama Ekran Görüntüsü

OCR uygulaması ekran görüntüsü

Sonuç

PaddleOCR ve DeepTranslator kütüphanesinin gücünü kullanan bu uygulama, özellikle çok dilli belge işleme, yabancı dildeki metinleri hızlıca anlama ve dijital içerik çevirisi gibi ihtiyaçlar için kullanışlı bir araç sunuyor. Açık kaynak kodlu bu projeyi kendi ihtiyaçlarınıza göre özelleştirebilir, geliştirebilir ve farklı projelerinize entegre edebilirsiniz.