목표
실시간으로 화면을 캡쳐하고, OCR로 인식한 문자를 번역한다.
아이디어 & 솔루션
- 화면을 실시간으로 캡쳐한다.
- PIL 라이브러리의 ImageGrab을 사용
- OCR을 이용해서 문자를 인식한다.
- 오픈소스 OCR 라이브러리 Tesseract
- 인식한 문장를 번역한다.
- Papago API (넉넉한 무료 플랜)
- GUI로 캡쳐한 화면, 인식한 문자, 번역된 문장을 표시한다.
- Python GUI 프레임워크 Tkinter
Step 1. GUI 설계
- 메인 프레임
- 캡쳐한 화면
- 인식한 문자열
- 번역한 문자열
- 캡쳐할 영역 프레임
코드
import tkinter as tk
class TranslateApp:
def __init__(self, root):
self.root = root
self.setup_frame_A()
self.setup_frame_B()
def setup_frame_A(self):
self.frame_A = tk.Toplevel(self.root)
self.frame_A.title('캡쳐')
self.frame_A.geometry('300x200') # 창 크기 설정
self.frame_A.wm_attributes('-transparentcolor', self.frame_A['bg']) # 뒤 화면이 보이기 위해선 배경이 투명하게
def setup_frame_B(self):
self.frame_B = tk.Toplevel(self.root)
self.frame_B.geometry('300x600+400+100')
self.frame_B.title('메인')
self.label = tk.Label(self.frame_B) # 캡쳐한 이미지를 보여줄 예정이라 빈칸
self.label.pack(fill=tk.BOTH, expand=True)
# OCR 인식 텍스트를 보여줄 레이블
self.ocr_text_label = tk.Label(self.frame_B, text="OCR 인식 텍스트", bg="white", height=10)
self.ocr_text_label.pack(fill=tk.X, expand=True)
# 번역된 텍스트를 보여줄 레이블
self.trans_text_label = tk.Label(self.frame_B, text="번역 텍스트", bg="white", height=10)
self.trans_text_label.pack(fill=tk.X, expand=True)
def set_text(self, text):
self.ocr_text_label.config(text=text)
def set_trans_text(self, text):
self.trans_text_label.config(text=text)
root = tk.Tk()
root.withdraw() # 프레임만 띄울거라 메인 루트는 가린다.
app = TranslateApp(root)
# Run the app
root.mainloop()
결과물
Step 2. 스크린 캡쳐
ImageGrep 사용해보기
from PIL import ImageGrab
from PIL import Image, ImageTk
image = ImageGrab.grab(bbox=(100, 100 ,300, 300),all_screens=True)
image.save("image.png")
image.png 파일로 화면의 (100,100) 에서 (300, 300) 까지의 영역이 캡쳐되어 저장된다.
Tkinter에 적용
# 사용할 라이브러리를 추가
from PIL import ImageGrab
from PIL import Image, ImageTk
from io import BytesIO
class TranslateApp:
def __init__(self, root):
self.root = root
self.setup_frame_A()
self.setup_frame_B()
# GUI를 초기화 하면 이미지 캡쳐를 시작한다.
self.update_capture()
# ... 생략
def update_capture(self):
title_bar_height = 31 # 윈도우의 타이틀바 높이
border_width = 8 # 윈도우 프레임
# Frame A의 위치와 넓이, 높이
x = self.frame_A.winfo_x()
y = self.frame_A.winfo_y()
width = self.frame_A.winfo_width()
height = self.frame_A.winfo_height()
# 프레임 내부 영역을 캡쳐
image = ImageGrab.grab(bbox=(x+border_width, y+title_bar_height, x + border_width+ width, y + title_bar_height + height),all_screens=True)
# 이미지를 캡쳐하지 못한 경우 아무것도 하지 않음
if image == None:
self.label.config(image=None)
return
# Tkinter의 PhotoImage로 사용하기 위해
# 이미지를 BytesIO 오브젝트로 변환한다.
img_byte_arr = BytesIO()
image.save(img_byte_arr, format='PNG')
img_byte_arr.seek(0)
photo = tk.PhotoImage(data=img_byte_arr.read())
# 이미지 컴포넌트를 업데이트 한다.
self.label.config(image=photo)
self.label.image = photo # Keep a reference
# 1000ms 마다 재귀적으로 호출한다.
self.frame_A.after(1000, self.update_capture)
결과물
Step 3. OCR
Tesseract 라이브러리 사용법은 따로 다루지 않고 아래 문서로 대체
(https://pypi.org/project/pytesseract/)
캡쳐한 이미지를 OpenCV 형식에 맞게 변환한 후 Tesseract로 문자를 감지한다.
이미지를 입력받으면 블록 단위로 문자열을 묶은 뒤, 탐지한 영역을 초록색 박스로 표시한다.
코드
import pytesseract
import numpy as np
import cv2
from collections import defaultdict
# Tesseract가 설치된 경로를 설정해줘야한다.
pytesseract.pytesseract.tesseract_cmd = r'C:/Program Files/Tesseract-OCR/tesseract.exe'
def ocr_box(image):
text_data = pytesseract.image_to_data(image, lang='eng')
data = defaultdict(list)
# pytesseract로 OCR을 하게 되면, 라인별, 블록별 그룹을 지을 수 있도록 데이터를 출력해준다.
for i, line in enumerate(text_data.splitlines()):
# 내용이 궁금하다면 print를 해보자.
# print(line)
if i == 0:
continue # 첫 번째 줄은 컬럼 이름이므로 스킵
line = line.split()
block_num = line[2] * 1000000 + line[3]*1000 + line[4]
if len(line) == 12: # 정상적으로 인식됐다면 12개의 컬럼이 나온다.
x, y, w, h = int(line[6]), int(line[7]), int(line[8]), int(line[9]) # 각각 좌표와 넓이 높이를 나타낸다.
# 이왕 이미지를 받았으니 인식한 부분을 박스로 그려주자.
cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 1)
# 우리는 블록번호를 기준으로 문자열을 묶을 예정
data[block_num].append(line[-1])
# 그림을 그린 이미지와 문자열을 리턴한다.
return image, [" ".join(data[k])for k in data.keys() ]
결과물
Step 4. 번역
파파고 API를 사용할 예정이다.
사용하기 위해선 네이버 파파고 API 문서를 참고하자. (https://developers.naver.com/docs/papago/papago-nmt-overview.md)
파파고 API 활용 코드
import requests
# 파파고 번역 API
url = "https://openapi.naver.com/v1/papago/n2mt"
# 발급받은 API키를 꼭 넣어야한다.
headers = {
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"X-Naver-Client-Id": "########################",
"X-Naver-Client-Secret": "###########"
}
# 심플하게 text를 입력받으면 번역 결과물을 리턴해주는 함수.
def translate(text):
data = {
"source": "en",
"target": "ko",
"text": text
}
response = requests.post(url, headers=headers, data=data)
translated_json = response.json()
return translated_json['message']['result']['translatedText']
기존 코드에 추가
class TranslateApp:
def __init__(self, root):
self.root = root
self.setup_frame_A()
self.setup_frame_B()
self.update_capture()
# 1초마다 쓸데 없이 번역API를 사용하는건 낭비이므로
# 이전 문장과 같으면 번역하지 않기 위해 저장해둔다.
self.last_text = ""
# ....
# OCR 처리된 문장이 표시될 때 처리를 한다.
def set_text(self, text):
self.ocr_text_label.config(text=text)
# 이전 문장과 같거나, 10자 미만인 글자는 번역하지 않는다.
if len(text) > 10 and text!= self.last_text:
# 번역 라벨에 번역된 문장을 넣는다.
self.set_trans_text(translate(text))
self.last_text = text
결과물
최종 결과물
반응형
'Dev > Python' 카테고리의 다른 글
[SublimeText] 플러그인 만들기 - URL Decoder (0) | 2022.01.08 |
---|---|
Python 접근제어자 (1) | 2018.05.28 |
카카오톡 챗봇 (2) (2) | 2017.12.22 |
카카오톡 챗봇 (1) (3) | 2017.12.15 |