EasyOCR는 JaidedAI가 제공하는 Python용 OCR 라이브러리입니다. pip install easyocr로 설치하고 코드 두 줄만 쓰면, 이미지 안에 박혀 있던 텍스트를 문자열로 뽑아낼 수 있습니다. Apache-2.0 라이선스를 사용하며 80개 이상 언어를 지원한다고 안내하고, 실제 동작은 두 개의 PyTorch 모델로 이루어진 파이프라인입니다. 먼저 CRAFT 탐지기가 텍스트로 보이는 영역에 박스를 그린 뒤, 인식기가 각 박스 안의 문자를 읽어냅니다. 사전 학습 가중치는 처음 실행할 때 자동으로 내려받습니다. 구조상 페이지별 클라우드 OCR API가 아니라, Tesseract나 PaddleOCR의 자체 호스팅 대안에 가깝습니다.
기본 API는 아주 짧습니다. Reader(['en'])을 만들고 readtext()를 호출하면 됩니다. 하지만 배포 관점의 무게감은 꽤 큽니다. 이 환경에서는 PyTorch만 약 2GB, 실제 측정한 새 프로세스의 최대 상주 메모리는 대략 1GB였습니다. 저는 영어 PNG 샘플 36개를 직접 렌더링한 뒤, CPU에서 easyocr 1.7.2를 실행하고 생성한 정답과 문자 단위로 비교해 점수를 매겼습니다. 크기와 방향은 CER이 가장 크게 무너지는 구간이었고, 대시보드 샘플에서는 짧은 토큰 탐지와 달러 기호 인식 오류도 드러났습니다.
가장 눈에 띄는 실패는 모두가 추천하는 그 파라미터에서 나왔습니다. rotation_info는 회전된 이미지를 고칠 때 정답처럼 자주 언급되기 때문에, 같은 문장을 서로 직교하는 방향으로 세 번 회전해 테스트했습니다. 270°에서는 약속대로 제대로 작동해 CER을 0.83에서 0.10까지 낮췄습니다. 180°에서는 절반만 통했습니다. 0.85에서 0.67로 좋아졌지만 문구 하나가 빠졌습니다. 90°에서는 오히려 역효과가 났습니다. 0.81에서 0.92로 나빠졌고, 인식기가 거울에 비춘 듯한 텍스트를 내보내기 시작했습니다. 같은 파라미터, 같은 각도 목록인데 결과는 제각각이었습니다. 즉, 이 옵션을 켠다고 해서 “회전 문제는 해결됐다”고 말할 수는 없습니다. 같은 36개 샘플에서는 글자 크기 임계점, 달러 기호 오인식, 그리고 제가 완전히 잘못 예측했던 항목 하나도 함께 드러났습니다.
코트를 걸친 두 모델
EasyOCR은 하나의 모델이 아닙니다. 두 단계 파이프라인이고, 어느 단계에서 실패했는지 알아야 디버깅 방향이 달라집니다.
첫 번째 단계는 CRAFT 탐지기입니다. 역할은 오직 위치를 찾는 것입니다. 이미지 어디에 텍스트가 있는지 판단하고 박스를 돌려줍니다. 문자 자체는 읽지 않습니다. 두 번째 단계는 CRNN 인식기입니다. ResNet으로 특징을 뽑고, BiLSTM을 거쳐, CTC greedy decoding으로 각 박스 안의 문자를 읽습니다. 둘 다 PyTorch 위에서 동작합니다. CPU에서는 기본적으로 인식기가 int8로 동적 양자화되기 때문에, 단순한 파라미터 수만 보면 예상되는 것보다 더 가볍고 빠릅니다.

실무적으로 중요한 점은 EasyOCR의 실패 유형이 완전히 둘이라는 사실입니다. 각각의 해결책도 다릅니다. 탐지기가 박스를 하나도 그리지 못했다면, 인식기 튜닝은 아무 소용이 없습니다. 애초에 문자가 파이프라인에 들어오지도 못했기 때문입니다. 반대로 박스는 있는데 문자열이 틀렸다면 인식 문제이고, 전처리로 살릴 여지가 있습니다. 제가 본 “EasyOCR이 내 텍스트를 놓쳤다”는 글의 상당수는 이 둘을 섞어 말하고 있었습니다.
2026년 7월 27일 기준 프로젝트 현황은 별 29,825개, 열린 이슈 528개, Apache-2.0 라이선스, 그리고 2024년 9월에 나온 v1.7.2이며, master에 마지막으로 반영된 것은 2025년 12월입니다. 이 날짜들이 아키텍처 안정성이나 유지보수 상태를 보장해주지는 않습니다. 도입 전에 자신의 Python/PyTorch 조합과의 호환성, 최근 유지보수자의 응답 속도, 그리고 자신의 입력 유형과 관련된 이슈를 꼭 확인하세요.
OCR은 CAPTCHA 해결과 자주 엮이지만, 이 글의 범위는 그게 아닙니다. 여기서는 봇 차단을 우회하는 용도는 테스트하지 않았고, 그런 사용을 지지하지도 않습니다. 여기서 다루는 일은 읽을 권리가 있는 이미지와 스크린샷에서 텍스트를 읽는 것입니다.
무엇을 측정했는가, 그리고 이 수치가 말해주지 않는 것
테스트셋은 제가 직접 렌더링한 PNG 36개입니다. 그중 35개는 단일 라인 이미지로, 7개 폰트, 8개 크기, 7개 대비 수준, 7개 기울기 각도, 3개 직교 회전, 3개 배경을 훑도록 구성했습니다. 나머지 1개는 19개의 개별 라벨이 붙은 합성 대시보드 스크린샷입니다. 모든 이미지는 고정 문자열(Sphinx of black quartz, judge my vow. 1234567890 — 48자, 대소문자 혼합, 숫자, 구두점 포함)에서 생성했고, 정답 라벨도 같은 과정에서 함께 기록했기 때문에 이미지와 라벨이 따로 어긋날 수 없습니다.
정확도는 문자 오류율(CER) 로 계산했습니다. 레벤슈타인 거리를 문자 단위로 구한 뒤 정답 길이로 나눈 값입니다. CER 0은 완벽한 판독을 뜻하고, CER 0.10은 대략 열 글자 중 한 글자가 틀렸다는 의미입니다. 저는 대소문자를 구분하는 CER을 주 지표로, 대소문자를 무시한 값은 보조로 함께 제시했습니다. 실제로 대부분의 “오류”는 대소문자에서 발생했기 때문입니다.
하지만 숫자보다 중요한 건 경계 조건입니다.
- 영어만 테스트했습니다.
english_g2인식기를 사용했습니다. EasyOCR은 80개 이상 언어를 지원한다고 하지만, 저는 하나만 검증했습니다. 비라틴 문자에 대해서는 아무 말도 할 수 없고, 그것이야말로 발표된 학술 OCR 비교가 주로 다루는 영역입니다. - 합성 텍스트만 사용했습니다. 사진이 아니라 렌더링된 글자입니다. 카메라 노이즈, JPEG 압축, 조명, 원근 왜곡이 없습니다.
- 손글씨는 제외했습니다. 프로젝트 문서 자체가 아직 지원하지 않는다고 밝힙니다.
- CPU만 사용했습니다. macOS arm64,
gpu=False. 기기에는 MPS가 있었지만 EasyOCR은 CUDA가 아닌 환경에서는 CPU를 사용합니다. GPU 성능은 전혀 측정하지 않았으므로, 여기에는 GPU 수치가 없습니다. - 한 대의 기기, 한 버전만 썼습니다. easyocr 1.7.2, torch 2.13.0, Python 3.12입니다.
즉, 이 결과는 깨끗한 렌더링 라틴 텍스트에서 정밀도가 어디서 무너지는지 보여주는 통제된 단일 변수 곡선입니다. 실제 현업 코퍼스의 점수는 아니며, 그 대체물도 아닙니다.
증거는 노트북 안에 갇혀 있지 않고 그대로 확인할 수 있습니다. 샘플 생성기와 정확한 문자열은 tests/build_fixtures.py와 tests/fixtures/ground_truth.json에 있고, 인식·타이밍·리소스 수집은 tests/run_easyocr.py에 있습니다. 그리고 tests/metrics.py가 원시 출력으로부터 보고된 오류율을 계산합니다. 최종 인식 기록과 집계 메트릭은 artifacts/raw/에 보존되어 있습니다. 이 체인을 다시 돌려보면 현재 기기와 버전을 점검하는 데는 도움이 됩니다. 하지만 자신의 휴대폰 사진, 언어, 레이아웃, 전처리 파이프라인에서 EasyOCR이 어떻게 동작할지는 여전히 알 수 없습니다. 실제 도입 판단은 이 샘플 대신 대표 입력을 추가해서 해야 합니다.
하네스에서 주의할 함정 하나가 있습니다. 저는 처음에 그 함정에 빠져 거의 잘못된 헤드라인 수치를 만들 뻔했습니다. 첫 메트릭 계산 결과는 깨끗한 검은색 Arial에서 CER 0.375를 보고했는데, 가장 쉬워야 할 입력치고는 형편없는 결과였습니다. 하지만 문제는 EasyOCR이 아니었습니다. 탐지기가 한 줄을 단어 박스와 숫자 박스로 나눠 버렸고, 제가 만든 단순한 y-후 x 정렬 방식은 숫자를 앞에 붙여버리고 있었습니다. 세로 겹침을 기준으로 박스를 묶고, 그다음 좌→우로 읽는 라인 단위 그룹핑으로 바꾸자, 깨끗한 폰트들은 대체로 0.04–0.10 수준에 들어왔습니다. 직접 OCR 평가를 만들고 있다면, 같은 함정이 당신을 기다리고 있습니다.
설치는 가볍지만, 의존성은 가볍지 않다

pip install easyocr
설치는 이게 전부지만, 솔직히 말해 가벼운 패키지는 아닙니다. 패키지 자체는 단순하지만, 함께 끌려오는 것은 대략 2GB의 PyTorch입니다. 그리고 readtext()를 처음 호출하면 EasyOCR이 조용히 ~/.EasyOCR/model/에 가중치를 내려받습니다. 총 93.7 MiB이며, CRAFT 탐지기(craft_mlt_25k.pth)가 79.30 MiB, 영어 인식기(english_g2.pth)가 14.44 MiB입니다.
이 부분은 튜토리얼에서 잘 언급하지 않으니 짚고 가자면, 첫 실행에는 네트워크가 필요하고 다운로드 동안 잠깐 멈춥니다. 컨테이너 배포라면 이 가중치를 이미지에 포함시키거나, 콜드 스타트 때마다 내려받는 비용을 감수해야 합니다. 한 번 캐시되면 그다음부터는 오프라인으로 동작합니다.
콜드 상태의 Reader() 초기화, 즉 모델을 디스크에서 RAM으로 올리고 int8 양자화까지 수행하는 데는 실행마다 1.3–1.7초가 걸렸습니다. 그 뒤에는 아래처럼 쓰면 됩니다.
import easyocr
reader = easyocr.Reader(['en'], gpu=False)
result = reader.readtext('screenshot.png')
이렇게 두 줄이면 끝입니다. 설정도, 체크포인트를 따로 찾는 일도 없습니다. 이름의 “easy”는 이 구간에서 충분히 납득됩니다. 불편함은 API가 아니라 의존성 무게에서 생깁니다.
깨끗한 텍스트의 하한선: 글자는 거의 완벽, 대소문자는 아쉽다
7개 시스템 폰트, 흰 바탕에 검은 글자, 32px, 매번 같은 문자열:
| 폰트 | CER (대소문자 구분) | CER (대소문자 무시) |
|---|---|---|
| Georgia | 0.0625 | 0.0000 |
| Times | 0.0417 | 0.0417 |
| Comic Sans | 0.0417 | 0.0208 |
| Arial | 0.0833 | 0.0208 |
| Verdana | 0.0833 | 0.0208 |
| Impact | 0.0833 | 0.0208 |
| Courier | 0.1042 | 0.0417 |
| 평균 | 0.0714 | 0.0238 |
평균 CER은 0.071이지만, 대소문자를 무시하면 0.024까지 내려갑니다. 이 차이가 핵심입니다. EasyOCR은 깨끗한 라틴 텍스트에서 글자 자체를 놓치는 것이 아니라, 모양은 맞히고 대소문자만 틀리는 경우가 많습니다.
구체적으로는 lowercase 단어 vow를 7개 폰트 중 6개에서 VOW로 읽었습니다. Comic Sans만 Vow로 타협했습니다. Impact는 여기에 of를 Of로 바꾸는 실수를 추가했습니다. 또 반복적으로 보인 오류는 문장 끝 마침표입니다. 여러 폰트에서 : 또는 _로 돌아왔습니다. 대소문자를 신경 쓰지 않으면 Georgia는 완벽한 판독입니다.
이건 꽤 쓸모 있는 패턴입니다. 후속 단계가 퍼지 매칭, 키워드 검색, 또는 언어 모델 입력이라면 대소문자 뒤집힘은 거의 손해가 없습니다. 하지만 데이터베이스 키와 정확히 일치하는지 비교해야 한다면 이야기가 달라집니다. 비교 전에 대소문자를 정규화하면 EasyOCR의 체감 오류율 절반쯤은 사라집니다.
Courier가 가장 나쁜 결과(0.1042)를 낸 것도 설명이 됩니다. 고정폭 글꼴은 문자 간 간격이 비정상적으로 넓고, 이는 일반적인 글자 간격을 학습한 CTC 디코더에게 더 어렵기 때문입니다.
크기 임계점은 문서에 적힌 그대로 나타난다

readtext()에는 문서화된 min_size=10 파라미터가 있습니다. 10픽셀보다 짧은 탐지 박스를 버리는 옵션입니다. 대부분은 이걸 그냥 지나칩니다. 하지만 스크린샷이나 PDF 추출을 하는 사람에게는 API에서 가장 중요한 숫자일 수 있습니다. 렌더링한 글자 높이를 바꿔가며 테스트했을 때 결과는 다음과 같았습니다.
| 렌더링 px | CER | 무슨 일이 있었나 |
|---|---|---|
| 8 | 0.7708 | 붕괴 — 박스가 min_size 필터 아래로 떨어져 버리고 조각만 남음 |
| 10 | 0.1458 | 저하 — 바닥값 근처에서 탐지기가 한 줄을 3개 박스로 쪼갬 |
| 12 | 0.0417 | 회복 |
| 16 | 0.0000 | 완벽한 판독 |
| 20 | 0.0208 | 양호 |
| 28 | 0.0208 | 양호 |
| 40 | 0.0625 | 양호(대소문자 뒤집힘이 다시 등장) |
| 64 | 0.0625 | 양호(대소문자 뒤집힘) |
12px에서 8px로 내려갈 때 CER이 0.04에서 0.77로 튀는 것은 점진적 열화가 아닙니다. 문서에 적힌 대로 필터가 작동한 결과이고, 그 결과 기본 EasyOCR에서는 대략 10px 이하의 텍스트가 사실상 보이지 않게 됩니다.
가장 좋은 구간은 12–28px이며, 16px에서는 CER 0을 기록했습니다. 40px 이상에서는 다시 CER이 올라가는데, 글자가 더 어려워져서가 아니라 vow → VOW 뒤집힘이 다시 나타나기 때문입니다. 큰 글자가 더 어렵다기보다, 16px에서 우연히 맞아떨어졌던 글자 간격의 이점이 사라진 것입니다.
스크린샷에서 텍스트를 추출한다면, 모델 탓을 하기 전에 렌더링된 글자 높이부터 확인하세요. HiDPI 디스플레이에서 1×로 캡처한 대시보드나, 72 DPI로 래스터화한 PDF 페이지는 본문 텍스트가 흔히 10px 아래로 떨어집니다. 2×로 캡처하거나 OCR 전에 업스케일하면 “EasyOCR이 내 페이지 절반을 무시했다”는 버그 보고 대부분을 건너뛸 수 있습니다. 그게 불가능하다면 min_size를 낮출 수는 있지만, 필터가 원래 잡음 탐지를 억제하려고 존재한다는 점을 감안해야 합니다.
회전: 10° 정도는 버티지만, 대칭적인 해결책은 아니다
먼저 기울기부터 보겠습니다. 작은 각도, Arial 32px, 기본 설정과 rotation_info=[90,180,270] 비교입니다.
| 기울기 각도 | CER (기본) | CER (rotation_info 적용) |
|---|---|---|
| 0° | 0.0833 | 0.0833 |
| 5° | 0.0417 | 0.0417 |
| 10° | 0.0208 | 0.0833 |
| 15° | 0.2917 | 0.3750 |
| 20° | 0.7500 | 0.7708 |
| 30° | 0.8958 | 0.8750 |
| 45° | 0.8958 | 0.8750 |
기본 EasyOCR은 약 10° 까지는 무난하게 처리하고(CER ≤ 0.083), 15°에서 흔들리며, 20° 정도면 거의 무너집니다. rotation_info는 기울기에는 아무 도움이 되지 않습니다. 왜냐하면 이 옵션은 사용자가 지정한 각도만 다시 시도하는데, 15° 기울기는 90, 180, 270이 아니기 때문입니다. 10°에서는 오히려 약간 더 나빠졌습니다(0.021 → 0.083). 잘못된 각도의 재시도가 신뢰도 투표에서 이겨버릴 수 있기 때문입니다.
직교 회전에서는 이야기가 이상해집니다.
| 회전 | CER (기본) | CER (rotation_info 적용) | 복구됨? |
|---|---|---|---|
| 90° | 0.8125 | 0.9167 | 아니오 — 더 나쁨 |
| 180° | 0.8542 | 0.6667 | 부분적 |
| 270° | 0.8333 | 0.1042 | 예 |
같은 파라미터, 같은 각도 목록, 결과는 세 가지입니다.
270°에서는 rotation_info가 이 이슈 스레드에서 약속한 대로 작동합니다. CER이 0.83에서 0.10으로 떨어져 실용적인 판독이 됩니다. 180°에서는 절반만 성공해 CER이 0.67로 좋아지지만, my vow. 문구가 아예 빠집니다. 90°에서는 0.81에서 0.92로 오히려 악화되고, 원시 출력이 그 이유를 보여줍니다. 인식기가 거울상 문자열을 돌려줍니다. VOW는 MOA가 되고, quartz는 zuuenb가 됩니다. 거울에 비춰 읽으면 맞는 문자열이지만, 데이터 파이프라인에서는 쓸모가 없습니다.
이건 정렬 순서가 꼬여서 생긴 게 아닐까 의심했기에, 집계 수치가 아니라 원시 예측 결과를 직접 확인했습니다. 결론적으로 그건 조인이 꼬인 결과가 아니라, EasyOCR이 실제로 그렇게 반환한 것입니다.
작동 메커니즘은 측정이 아니라 가설입니다. 회전 관례 실험은 따로 하지 않았습니다. Pillow는 양의 각도를 반시계 방향으로 렌더링하므로, 우연히 270°로 렌더된 이미지가 인식기가 잘 처리하는 재시도 방향과 맞아떨어지고, 90° 케이스에서는 가장 점수가 높은 재시도가 뒤집힌 방향에 걸렸을 가능성이 있습니다. 메커니즘이 무엇이든 운영상 교훈은 달라지지 않습니다.
이 샘플은 rotation_info가 방향에 따라 대칭적으로 동작한다고 가정할 수 없음을 보여줍니다. 입력에서 예상되는 회전을 미리 검증하세요. 상류 단계에서 방향을 먼저 바로잡는 것이 유력한 완화책이지, 이 세 가지 렌더링 예제로 확립된 필수 조건은 아닙니다.
제가 틀렸던 예측
처음엔 저대비가 EasyOCR의 약점일 거라 예상했습니다. 흐릿한 회색 글자가 흰 배경에 있는 것은 전형적인 OCR 실패 사례이고, 이를 살리는 문서화된 경로도 있습니다. contrast_ths=0.1, adjust_contrast=0.5를 쓰면 저대비 박스를 대비를 올린 사본으로 다시 돌리고, 더 자신 있는 결과를 택하게 됩니다.
하지만 그 기능은 한 번도 발동하지 않았습니다. 필요가 없었기 때문입니다.
| 전경 회색 | Weber 대비 | CER (기본) | CER (adjust_contrast=1.0) |
|---|---|---|---|
| 0 (검정) | 1.000 | 0.0833 | 0.0833 |
| 64 | 0.749 | 0.0833 | 0.0833 |
| 110 | 0.569 | 0.0833 | 0.0833 |
| 150 | 0.412 | 0.1042 | 0.1042 |
| 180 | 0.294 | 0.0625 | 0.0625 |
| 200 | 0.216 | 0.0417 | 0.0417 |
| 220 | 0.137 | 0.0417 | 0.0417 |
Weber 0.14까지 내려가도 CER은 계속 양호한 범위를 벗어나지 않았습니다. 회색 220의 흰 배경처럼, 샘플을 확인하려고 눈을 찡그려야 할 정도로 흐린 경우에도 마찬가지였습니다. 그리고 대비 보정 열은 모든 단계에서 기본 열과 완전히 동일했습니다. 기본 값으로도 이미 성공했기 때문입니다.
배경도 같은 이야기를 했습니다. 모두 검은 글자입니다.
| 배경 | CER |
|---|---|
| 단색 연파랑 패널 | 0.083 |
| 세로 그라디언트 | 0.021 |
| 가우시안 노이즈 (μ200, σ22) | 0.000 |
가장 노이즈가 심한 샘플에서도 완벽한 판독이 나왔습니다.
다만 범위는 좁습니다. 이 결과는 색만 다른 단색, 노이즈 없는 저대비 텍스트에 대한 것이지, 센서 노이즈와 JPEG 압축이 섞인 사진 영수증이 아닙니다. 이 샘플 세트에서는 기하학적 조건과 짧은 토큰이 가장 큰 실패 요인이었고, 테스트한 색상 및 합성 노이즈 변형은 그렇지 않았습니다.
실제 시나리오: 대시보드 스크린샷에서 숫자 뽑기
실제 Python OCR 작업의 대부분은 이런 경우입니다. 누군가 내부 대시보드의 스크린샷을 보내거나, 차트가 많은 분석 페이지를 대상으로 Python 스크래핑 파이프라인을 돌리고 있는데 숫자가 렌더링된 픽셀로만 존재할 때, 그 값을 데이터로 가져오고 싶어집니다.
저는 “Sales Dashboard” 창을 렌더링했습니다. 어두운 헤더에 제목과 원형 아바타 배지, 3개의 KPI 패널, 3개의 버튼, 2×3 표가 있는 화면이었습니다. 그리고 19개 텍스트 요소를 각각 정확한 문자열과 픽셀 박스로 라벨링한 뒤, 박스 겹침을 기준으로 EasyOCR 출력과 매칭했습니다.
탐지 재현율: 19개 중 16개. 놓친 3개는 다음과 같습니다.
- 한 글자 배지인 "A"
- 표 셀 "Q1"
- 표 셀 "Q2"
반면 "Q3"는 탐지되었습니다. 폰트도 같고, 크기도 같고, 같은 열에 있는 항목인데, 탐지기는 두 글자 토큰 하나는 잡고 다른 둘은 놓쳤습니다. 비슷해 보이는 셀들 사이에서도 탐지가 들쭉날쭉했습니다. 이 실행들이 결정적이었기 때문에, 이는 무작위 “동전 던지기” 행동의 증거는 아닙니다. 비슷한 스크린샷 품질 이슈는 #460에 추적되어 있습니다.
찾아낸 16개 요소에서는 텍스트가 거의 완벽했습니다. 평균 CER은 0.027이었고, 16개 중 13개는 완전 일치했습니다. 제목, 라벨, 버튼("Save", "Cancel", "Export CSV"), 열 머리글, 쉼표로 묶인 숫자까지 모두 CER 0으로 나왔습니다. 1,284도 쉼표까지 정확하게 읽혔습니다.
불완전한 3개 읽기는 모두 같은 오류였습니다. 달러 금액입니다.
| 정답 | EasyOCR 결과 |
|---|---|
$57,912 | S57,912 |
$18,330 | S18,330 |
$25,178 | S25,178 |
$12,004 | $12,004 (정상) |
달러 기호 4개 중 3개가 대문자 S로 바뀌었습니다. 시각적으로는 이해할 수 있는 오인식이지만, 추출 결과의 모든 통화 필드가 한 글자만 틀려도 엉망이 될 수 있다는 뜻입니다. 단순히 float()를 호출하면 전부 예외가 납니다.
스크린샷 파이프라인에 짧은 라벨이나 통화가 포함되어 있다면, 업스케일링, 여백을 둔 크롭, 필드 형식에 맞는 기대값 제한, 기호 인식 후처리 같은 완화책을 검증해 보세요. 여기서는 어느 것도 벤치마크하지 않았고, 선행 S를 치환하는 정규식은 진짜 값을 망가뜨릴 수도 있습니다. 스키마와 검증 규칙상 안전할 때만 보정을 적용하세요.
실행 비용은 얼마나 드는가
같은 머신(macOS arm64, CPU, 단일 호스트, 측정 중 동시 부하 가능성 있음 — 보편적 벤치마크가 아니라 경향으로 봐야 함)에서의 수치입니다.
| 지표 | 값 |
|---|---|
| 디스크상의 모델 가중치 | 93.7 MiB (탐지기 79.30 + 인식기 14.44) |
| 새 CPU 프로세스의 최대 상주 메모리 | 984.5 MiB |
콜드 상태 Reader() 초기화 | 1.3–1.7초 |
| 워밍 상태, 깨끗한 48자 한 줄 처리 p50 | 약 0.062초 (p25–p75: 0.059–0.067초, n=20) |
detail=0 vs detail=1 | 거의 동일 (중앙값 0.062 vs 0.063초) |
가장 큰 비용은 94MB짜리 가중치가 아니라, 약 2GB짜리 torch 설치 위에 얹히는 프로세스당 약 1GB의 상주 메모리입니다. 이 수치가 컨테이너에 들어가는지 여부를 결정하고, 대부분은 이 숫자를 말해주지 않습니다.
속도는 쉬운 경우에는 괜찮습니다. CPU에서 깨끗한 단일 라인을 워밍 상태로 처리할 때 0.1초 미만이면 충분히 실용적입니다. 하지만 그건 정말 쉬운 경우입니다. 짧고 대비가 좋은 한 줄일 뿐입니다. 흔히 보이는 “EasyOCR이 CPU에서 수십 초 걸린다” 불만은 대형 다중 영역 문서를 전체 캔버스 크기로 처리하는 경우에 대한 것이고, 저는 그 재현까지는 하지 않았습니다. 다른 작업량이기 때문이며, 그 점은 주장하지 않고 인용만 합니다.
작은 मिथ 하나는 정리해두겠습니다. detail=0은 EasyOCR을 더 빠르게 만들지 않습니다. 반환값에서 바운딩 박스와 confidence만 제거할 뿐입니다. 계산은 이미 끝난 뒤입니다. 중앙값 차이는 1밀리초 수준이라 잡음입니다.
장단점
장점
- 깨끗하게 렌더링된 라틴 텍스트에 대한 문자 재현율이 사실상 완벽합니다. 대소문자 구분 CER 평균 0.071, 대소문자 무시 시 0.024, 16px에서 완전 판독 가능.
- 진짜로 두 줄짜리 API입니다.
Reader(['en'])다음readtext()면 끝이고, 설정도 모델 선택도 필요 없습니다. - 통념보다 대비에 훨씬 강합니다. 깨끗한 텍스트에서 Weber 0.14까지도 붕괴하지 않았고, 노이즈/그라디언트/컬러 배경에서도 성능이 유지됐습니다(가우시안 노이즈 샘플은 완벽한 판독).
- 탐지된 스크린샷 요소에서는 거의 완벽합니다. 평균 CER 0.027, 16개 중 13개 정확, 쉼표가 들어간 숫자도 포함.
- 결정적입니다. 여기 나온 정확도 수치는 서로 독립적인 두 번의 프로세스 실행에서 바이트 단위로 동일했으며, 시간만 달라졌습니다.
- Apache-2.0 라이선스의 자체 호스팅 도구이며 벤더 사용료가 없습니다. 대신 연산, 메모리, 저장소, 큐잉은 운영비가 됩니다.
단점
- 문서에 적힌
min_size=10기준 아래에서는 급격히 무너집니다. 8px에서 CER 0.77. 작은 UI 텍스트는 기본 상태에서 사실상 보이지 않습니다. - 기울기 허용 범위는 약 10° 정도까지이고, 20°쯤 되면 무너집니다.
rotation_info는 대칭적인 해결책이 아닙니다. 270°는 복구되고, 180°는 부분적으로만 고쳐지며, 90°는 더 나빠지고 거울 텍스트를 돌려줍니다.- 탐지기가 짧은 단일 토큰을 놓칩니다. 한 글자 배지와 두 개의 2글자 셀은 빠지고, 형식이 같은 다른 셀은 살아남았습니다.
- 통화 값에서
$를S로 바꾸는 체계적 오인식이 있습니다(4개 중 3개). - 프로세스당 약 1GB 상주 메모리, 게다가 약 2GB짜리 torch 의존성이 붙습니다.
- 최신 릴리스가 2024년 9월이라, 프로젝트는 활발히 진화하기보다 안정화된 상태에 가깝습니다.
누구에게 맞고, 누구는 피해야 하는가
입력이 깨끗하고, 똑바로 서 있고, 충분한 크기로 렌더링된 텍스트라면 EasyOCR을 평가해 볼 만합니다. 스크린샷, UI 캡처, 래스터화된 PDF, 생성 리포트처럼요. 벤더 사용료 없는 자체 호스팅 Python 파이프라인이 필요할 때도 적합합니다. 여기서의 합성 영어 CPU 결과는 이 사용 시나리오에 해당합니다. 사진, 손글씨, 다른 스크립트는 별도 테스트가 필요합니다.
다음에 해당한다면 다른 선택지를 보세요. 사진 — 제 수치는 합성 렌더 텍스트에 대한 것이며, 카메라 노이즈·원근·조명에 대해선 아무 말도 하지 않습니다. 손글씨 — 프로젝트 자체가 지원을 주장하지 않습니다. 비라틴 스크립트 — EasyOCR은 80개 이상 언어를 지원하지만, 제가 검증한 것은 하나뿐이며, 이 영역에서는 합성 영어 스윕보다 발표된 학술 비교가 기준입니다. 임의 회전 입력 — 먼저 직접 방향 보정을 하지 않는다면 특히 그렇습니다. 메모리 제약 배포 — 워커 하나당 1GB는 금방 누적됩니다.
OCR을 고르기 전에 DOM과 네트워크 응답을 확인하세요. 원하는 값이 이미 구조화된 텍스트로 존재한다면, 그 소스를 추출하는 편이 OCR의 탐지·인식 오류를 피하는 길입니다. OCR은 픽셀만이 유일한 표현인 곳에서 써야 합니다.
대안, 그리고 우리 스택이 놓인 위치
EasyOCR은 Apache-2.0의 자체 호스팅 도구이며, 벤더 사용료는 없지만 실제 연산과 운영 비용이 듭니다. PaddleOCR, Tesseract, vision-language 모델은 이 벤치에 넣지 않았기 때문에, 직접 비교 결론은 내리지 않았습니다.
더 흥미로운 비교는 OCR 대 OCR이 아닙니다. 아예 OCR을 해야 하는지 여부입니다.
제가 보는 스크린샷 추출 작업의 대부분은 사실 원래 웹 페이지를 스크래핑하기 어려워서 생긴 우회책입니다. JavaScript로 렌더링되는 표, 로그인 뒤의 대시보드, 반항적인 사이트 같은 것들입니다. 스크린샷을 찍고 OCR을 돌리는 건 가장 쉬워 보이지만, 멀쩡한 구조화 텍스트를 버리고 달러 기호 세금까지 치르면서 더 나쁜 버전을 다시 얻는 셈입니다.
작성자 노트: Thunderbit는 웹 페이지에서 추출할 때 사용하는 관리형 옵션입니다. 이 이미지 샘플들로는 테스트하지 않았습니다. 핵심 경계는 원본 표현 방식입니다. 구조화된 웹 데이터가 존재하면 DOM/네트워크 추출을 쓰고, 픽셀만 있을 때 OCR을 평가하세요.
같은 테스트 벤치에서 읽을 수 있는 관련 자료로는 전체 오픈소스 스크래퍼 비교, Crawl4AI 리뷰, 그리고 셀렉터를 거부하는 페이지를 위한 AI 기반 추출 개요가 있습니다.
결론
EasyOCR을 써야 할까요? 이미지가 똑바로 서 있고, 글자 높이가 최소 12픽셀이며, 라틴 스크립트를 읽는다면 그렇습니다. 그 조건 안에서는 꽤 좋습니다. 깨끗한 텍스트에서 평균 CER 0.071, 대소문자 정규화 후 0.024, 16px에서 완전 판독, 그리고 평판보다 더 나은 대비 내성을 보여줍니다. API는 정말 두 줄이면 되고, 출력이 결정적이라는 점도 파이프라인 디버깅에서는 생각보다 중요합니다.
그 밖에서는 예측 가능한 방식으로 실패합니다. 10px 이하 텍스트는 min_size 필터에 묻혀 사라집니다. 20°를 넘는 기울기는 읽기를 무너뜨립니다. rotation_info는 한 방향은 고치고, 다른 하나는 절반만 고치며, 세 번째는 거울 텍스트로 더 망가뜨립니다. 한 글자와 두 글자 토큰은 이웃은 살아남는데도 탐지기에서 빠집니다. 달러 기호는 S로 바뀝니다.
샘플 실패는 두 단계 모두에서 나왔습니다. 기하학 측면에서는 박스를 놓치거나 방향을 잘못 잡았고, 인식 측면에서는 달러 기호를 헷갈렸습니다. 업스케일링, 방향 정규화, 여백을 둔 크롭, 스키마 인식형 기호 보정은 안전한 보편 해법이 아니라 검증해 볼 후보로 보세요.
단, 제가 거의 그랬던 것처럼 깨진 평가 하네스에 이상한 숫자를 붙잡고 테스트하지는 마세요. 직접 샘플을 만들고, 정답을 정확히 알고, 자신의 한계점을 찾아내야 합니다.
웹 데이터 추출을 위해 Thunderbit 사용해보기 Get Started Free
자주 묻는 질문
EasyOCR은 프로덕션용 스크린샷 텍스트 추출에 충분히 정확한가요?
합성 대시보드에서는 매칭된 요소의 평균 CER이 0.027이었고, 16개 중 13개가 완전 일치했습니다. 하지만 19개 요소 중 3개는 탐지되지 않았고, 4개의 달러 기호 중 3개가 S로 바뀌었습니다. 이 정도가 허용 가능한지, 그리고 업스케일링이나 스키마 인식형 보정이 도움이 되는지는 대상 레이아웃에서 직접 테스트해야 합니다.
EasyOCR이 읽을 수 있는 최소 글자 크기는 얼마인가요?
실무적으로는 렌더링된 글자 높이 기준 약 12픽셀입니다. readtext()의 min_size=10은 10px보다 작은 탐지 박스를 버리고, 이 효과는 완만한 경사가 아니라 급격한 단차입니다. 8px에서 CER 0.77, 10px에서 0.15, 12px에서 0.04, 16px에서 0이었습니다. 제가 훑은 구간에서 깨끗한 범위는 12–28px였습니다. 소스가 HiDPI 스크린샷을 1×로 캡처한 것이거나, PDF를 72 DPI로 래스터화한 것이라면 min_size를 낮추기보다 OCR 전에 업스케일하세요. 이 필터는 잡음 탐지를 억제하려고 있는 것이기 때문입니다.
rotation_info가 EasyOCR에서 회전 이미지를 고쳐주나요?
항상 그런 것도 아니고, 대칭적으로 동작하지도 않습니다. 같은 문장을 90/180/270°로 각각 회전한 세 장에 rotation_info=[90,180,270]를 적용했을 때, 270° 이미지는 깨끗하게 복구됐고(CER 0.83 → 0.10), 180° 이미지는 절반만 나아졌으며(0.85 → 0.67, 문구 하나 누락), 90° 이미지는 오히려 더 나빠졌습니다(0.81 → 0.92). 이때 VOW가 MOA처럼 거울 텍스트로 돌아왔습니다. 또한 이 옵션은 작은 기울기에는 아무 효과가 없습니다. 리스트에 넣은 각도만 다시 시도하기 때문입니다. 따라서 EasyOCR을 부르기 전에 방향을 먼저 바로잡는 편이 낫습니다.
EasyOCR은 메모리와 디스크를 얼마나 사용하나요?
가중치는 93.7 MiB이며, 처음 사용 시 ~/.EasyOCR/model/에 내려받습니다. 탐지기 79.30 MiB와 영어 인식기 14.44 MiB로 나뉩니다. 측정한 새 CPU 프로세스의 최대 상주 메모리는 984.5 MiB였고, 여기에 약 2GB짜리 torch 설치가 추가됩니다. 콜드 상태의 reader 초기화는 1.3–1.7초 걸렸고, 깨끗한 한 줄은 이 머신에서 p50 약 0.062초였습니다. detail=0은 반환 형식만 바꾸고 측정된 실행 시간은 거의 바꾸지 않았습니다.
EasyOCR은 상업적으로 무료로 써도 되나요? 아직 유지보수 중인가요? 라이선스는 Apache-2.0이라서 완화적이며 상업적 사용에도 우호적입니다. 2026년 7월 27일 기준 저장소는 별 29,825개, 열린 이슈 528개, 최신 릴리스는 2024년 9월의 v1.7.2, master에 마지막으로 반영된 것은 2025년 12월입니다. 즉, 방치됐다기보다 안정된 상태로 보는 편이 맞습니다. 아키텍처는 한동안 크게 바뀌지 않았고, 활동은 이슈 트래커 쪽으로 옮겨갔다고 보면 됩니다. 실제로 빌드에 넣기 전에는 현재 라이선스와 릴리스 상태를 직접 확인하세요.


