2026년 8월 12일
시간표 이미지 분석 성능개선을 위한 셀 필터링 도입
동숲 프로젝트에서 시간표 이미지 자동 분석 시 성능개선을 위한 빈 셀 처리 방식을 적용한 과정을 정리했습니다.
OCR 처리 시간 단축을 위한 셀 필터링 도입
왜 OCR 처리 시간이 오래걸리나
동숲 프로젝트에는 사용자가 시간표 이미지를 업로드하면 자동으로 강의명, 교수명, 강의실, 요일, 교시 정보를 분석하는 기능이 있었습니다.
시간표 이미지 분석은 단순히 이미지 전체에 OCR을 한 번 수행하는 방식이 아니라, 시간표의 표 구조를 찾고 각 셀을 분리한 뒤 셀마다 OCR을 수행하는 방식으로 구성되어 있습니다.
문제는 이 과정에서 각 셀마다 OCR을 호출하기 때문에 전체 분석 시간이 오래 걸린다는 점이었습니다.
또한 이전에 비동기 처리 방식을 구성하여 요청과 분석 작업은 분리했지만, 이는 응답 지연 현상을 완화한 것이지 실제 이미지 분석 시간이 줄어드는 문제를 해결한 것은 아니었습니다.
즉 비동기 처리는 사용자가 기다리는 방식을 개선한 것이고, 셀 필터링은 실제 OCR 호출 횟수를 줄이기 위한 개선이라고 볼 수 있습니다.
기존 모든 셀 검사의 문제점
초기 구조에서는 시간표 이미지에서 추출된 모든 셀을 대상으로 OCR을 수행했습니다.
하지만 시간표 이미지의 모든 셀에 강의 정보가 들어있는 것은 아닙니다. 공강 시간처럼 비어 있는 셀도 있고, 요일이나 교시를 나타내는 헤더 셀도 존재합니다. 또한 표 라인 검출 과정에서 실제 셀이 아닌 작은 영역이 잘못 검출되는 경우도 있었습니다.
이런 셀까지 모두 OCR 대상으로 처리하면 불필요한 OCR 호출이 많아지고, 전체 분석 시간이 증가하게 됩니다.
특히 Tesseract OCR은 셀 하나를 처리할 때마다 이미지 전처리와 텍스트 인식 과정이 필요하기 때문에, 빈 셀까지 모두 OCR에 전달하는 것은 사용자와 서버 모두에게 불필요한 자원 낭비라고 판단했습니다.
따라서 모든 셀을 동일하게 OCR 처리하는 방식이 아니라, 실제 강의 정보가 들어있을 가능성이 있는 셀만 선별하는 과정이 필요했습니다.
적용 방식
이를 개선하기 위해 셀 필터링 로직을 추가했습니다.
셀 필터링은 표에서 추출된 모든 셀을 바로 OCR에 전달하는 것이 아니라, OCR을 수행할 필요가 있는 유효 셀인지 먼저 판단하는 과정입니다.
적용한 기준은 다음과 같습니다.
- 너무 작은 셀 제거
- 빈 셀 제거
- 헤더 셀 제외
- 중복 셀 제거
전체 흐름은 다음과 같이 변경했습니다.
시간표 이미지 업로드
↓
이미지 전처리
↓
표/grid 라인 검출
↓
셀 좌표 추출
↓
셀 필터링 - 신규 추가
↓
유효 셀만 OCR 수행
↓
OCR 결과 보정
↓
요일, 교시, 강의명, 교수명, 강의실 구조화
기존에는 셀 좌표를 추출한 뒤 바로 OCR을 수행했다면, 개선 후에는 셀 필터링 단계를 추가하여 불필요한 셀을 먼저 제거하도록 변경했습니다.
1. 너무 작은 셀 제거
OpenCV를 활용해 시간표의 가로선과 세로선을 검출하는 과정에서 실제 시간표 셀이 아닌 작은 영역이 셀처럼 추출되는 경우가 있었습니다.
예를 들어 선이 겹쳐 있거나, 이미지 품질이 좋지 않아 테두리가 끊겨 있는 경우 작은 박스 형태의 영역이 잘못 생성될 수 있습니다.
이런 영역은 실제 강의 정보가 들어있는 셀이 아니기 때문에 OCR을 수행해도 의미 있는 결과를 얻기 어렵습니다.
따라서 셀의 너비와 높이를 기준으로 일정 크기 이하의 영역은 OCR 대상에서 제외했습니다.
셀 너비 < 최소 너비 기준
OR
셀 높이 < 최소 높이 기준
→ OCR 대상에서 제외
이 처리를 통해 표 라인 검출 과정에서 발생하는 잘못된 셀 후보를 줄일 수 있었습니다.
2. 빈 셀 제거
시간표에는 공강 시간처럼 아무 내용도 없는 셀이 많이 존재합니다.
빈 셀은 OCR을 수행해도 의미 있는 텍스트가 나오지 않거나, 이미지 노이즈로 인해 잘못된 문자가 인식될 수 있습니다.
이를 해결하기 위해 셀 내부의 픽셀 정보를 확인하여 텍스트가 거의 없는 셀은 빈 셀로 판단했습니다.
이미지를 grayscale로 변환하고 threshold 처리를 적용하면, 텍스트나 선처럼 어두운 영역과 배경 영역을 어느 정도 구분할 수 있습니다. 이후 셀 내부에서 텍스트로 판단할 수 있는 픽셀 비율이 너무 낮으면 OCR을 수행하지 않도록 처리했습니다.
셀 내부의 텍스트 픽셀 비율이 기준값보다 낮음
→ 빈 셀로 판단
→ OCR 대상에서 제외
이 방식은 OCR을 호출하기 전에 간단한 이미지 연산만으로 빈 셀을 걸러낼 수 있기 때문에, 전체 처리 시간을 줄이는 데 도움이 되었습니다.
3. 헤더 셀 제외
시간표에서 상단 영역은 월, 화, 수, 목, 금과 같은 요일 정보를 나타내고, 왼쪽 영역은 1교시, 2교시와 같은 교시 정보를 나타냅니다.
이 정보는 시간표 구조를 해석하기 위한 기준으로는 필요하지만, 강의명, 교수명, 강의실을 추출하는 대상과는 역할이 다릅니다.
따라서 헤더 셀은 OCR 분석 대상에서 제외하고, 좌표를 기반으로 요일과 교시를 매핑하는 기준으로 활용했습니다.
즉 헤더 셀을 완전히 버린 것이 아니라, 강의 정보 추출 대상에서는 제외하고 시간표 구조를 해석하는 데만 사용했습니다.
상단 헤더 영역 → 요일 매핑 기준
왼쪽 헤더 영역 → 교시 매핑 기준
나머지 본문 셀 → 강의 정보 OCR 대상
이렇게 역할을 분리하면서 불필요한 OCR 호출을 줄일 수 있었습니다.
4. 중복 셀 제거
표 라인 검출 과정에서는 비슷한 위치의 선이 여러 번 검출될 수 있습니다. 이 경우 같은 셀이 여러 개의 좌표로 중복 생성될 수 있습니다.
예를 들어 실제로는 하나의 세로선인데 이미지의 두께나 노이즈로 인해 여러 개의 선으로 감지되면, 셀 좌표도 중복으로 생성될 수 있습니다.
이런 중복 셀에 대해 OCR을 여러 번 수행하면 처리 시간이 증가하고, 동일한 강의 정보가 중복 결과로 들어갈 수 있습니다.
따라서 가까운 위치의 x, y 좌표는 하나의 기준선으로 병합하고, 동일한 영역으로 판단되는 셀은 중복 제거했습니다.
비슷한 x 좌표 병합
비슷한 y 좌표 병합
중복된 셀 영역 제거
이를 통해 같은 셀에 OCR이 여러 번 수행되는 문제를 줄였습니다.
적용하면서 고려한 점
셀 필터링을 적용하면서 가장 중요하게 고려한 부분은 "필요한 셀까지 제거하지 않는 것"이었습니다.
불필요한 OCR 호출을 줄이는 것도 중요하지만, 실제 강의 정보가 들어있는 셀을 잘못 제거하면 분석 결과가 누락될 수 있습니다.
따라서 필터링 기준을 너무 엄격하게 잡기보다는, 빈 셀이나 잘못 검출된 셀을 우선 제거하는 방향으로 적용했습니다.
특히 시간표 이미지는 사용자마다 형태가 다를 수 있습니다. 어떤 시간표는 글씨가 진하고, 어떤 시간표는 글씨가 작거나 흐릴 수 있습니다. 또한 셀 크기나 여백, 선 두께도 이미지마다 다를 수 있습니다.
이 때문에 단순히 하나의 기준값만으로 모든 이미지를 처리하기에는 한계가 있었습니다.
그래서 셀의 크기, 내부 픽셀 비율, 위치 정보를 함께 고려하여 필터링하도록 구성했습니다.
또한 헤더 셀의 경우 OCR 대상에서는 제외했지만, 요일과 교시를 매핑하기 위한 기준으로는 필요했기 때문에 완전히 제거하지 않고 역할을 분리했습니다.
개선된 부분
기존에는 시간표 이미지에서 추출된 모든 셀을 OCR 대상으로 처리했습니다. 하지만 실제 분석 결과를 확인해보니 전체 셀 중 상당수는 강의 정보가 없는 빈 셀이거나, OCR 결과로 사용할 필요가 없는 영역이었습니다.
실제 시간표 이미지 분석 과정에서 추출된 셀 수는 다음과 같았습니다.
| 항목 | 개수 | 비율 |
|---|---|---|
| 전체 셀 수 | 1027개 | 100% |
| 빈 셀 수 | 597개 | 약 58.1% |
| 텍스트가 감지된 셀 수 | 430개 | 약 41.9% |
| 최종 OCR 대상으로 채택된 셀 수 | 49개 | 약 4.8% |
전체 1027개의 셀 중 최종적으로 OCR 대상으로 사용한 셀은 49개였습니다. 즉 전체 셀의 약 95.2%는 OCR을 수행하지 않아도 되는 셀이었습니다.
기존 방식처럼 모든 셀을 OCR 대상으로 처리했다면 1027번의 OCR 호출이 필요했지만, 셀 필터링을 적용한 뒤에는 실제 분석에 필요한 49개 셀만 OCR 대상으로 전달할 수 있었습니다.
이를 통해 다음과 같은 효과를 기대할 수 있었습니다.
- 불필요한 OCR 호출 감소
- 전체 이미지 분석 시간 단축
- 빈 셀에서 발생하는 의미 없는 OCR 결과 감소
- 강의명, 교수명, 강의실 구조화 과정의 노이즈 감소
- 서버 자원 사용량 완화
특히 비동기 처리와 멀티프로세싱은 이미지 분석 요청을 안정적으로 처리하기 위한 구조 개선이었다면, 셀 필터링은 실제 OCR 수행 횟수를 줄이는 성능 개선에 가까웠습니다.
즉 이전 개선이 "오래 걸리는 작업을 어떻게 안정적으로 처리할 것인가"에 대한 해결이었다면, 셀 필터링은 "애초에 불필요한 작업을 어떻게 줄일 것인가"에 대한 해결이었습니다.
결과와 기대 효과
셀 필터링을 도입한 결과, 시간표 이미지 분석 과정에서 OCR을 수행해야 하는 셀의 수를 크게 줄일 수 있었습니다.
실제 분석 기준으로 전체 1027개 셀 중 빈 셀은 597개였고, 최종 OCR 대상으로 채택된 셀은 49개였습니다. 이는 전체 셀 중 약 4.8%만 OCR 대상으로 사용했다는 의미입니다.
반대로 보면 약 95.2%의 셀은 OCR 호출 대상에서 제외되었습니다. OCR은 셀 단위로 반복 호출될수록 전체 처리 시간이 길어지기 때문에, 불필요한 셀을 사전에 제거하는 것만으로도 전체 분석 시간을 줄이는 데 도움이 되었습니다.
또한 빈 셀이나 잘못 검출된 셀에서 발생하는 잘못된 OCR 결과가 줄어들면서, 후처리 과정도 더 안정적으로 동작할 수 있었습니다.
시간표 분석 기능은 단순히 OCR 결과를 텍스트로 반환하는 것이 아니라, OCR 결과를 요일, 교시, 강의명, 교수명, 강의실 형태로 구조화해야 합니다.
따라서 OCR 결과에 노이즈가 많으면 후처리 로직도 복잡해지고, 잘못된 결과가 사용자에게 전달될 가능성도 높아집니다.
셀 필터링을 통해 OCR 이전 단계에서 노이즈를 줄이면서, 전체 분석 파이프라인의 안정성을 높일 수 있었습니다.
배운 점
이번 경험을 통해 OCR 성능 개선은 OCR 엔진 자체를 바꾸는 것만으로 해결되는 문제가 아니라는 것을 배웠습니다.
처음에는 OCR 처리 시간이 오래 걸리기 때문에 Tesseract 설정이나 멀티프로세싱 같은 실행 방식만 개선하면 된다고 생각했습니다.
하지만 실제 지표를 확인해보니, 전체 1027개 셀 중 최종적으로 OCR이 필요한 셀은 49개에 불과했습니다. 즉 문제는 OCR이 느린 것뿐만 아니라, OCR을 수행하지 않아도 되는 셀까지 모두 처리하고 있었다는 점에도 있었습니다.
셀 필터링을 적용하면서 불필요한 작업을 줄이는 것이 전체 성능 개선에 큰 영향을 줄 수 있다는 것을 경험했습니다.
또한 이미지 분석 파이프라인에서는 전처리, 셀 검출, OCR, 후처리 단계가 서로 연결되어 있기 때문에 한 단계의 노이즈가 다음 단계의 오류로 이어질 수 있다는 점도 알게 되었습니다.
빈 셀이나 잘못 검출된 셀을 OCR 대상에서 제외하는 단순한 처리만으로도 OCR 호출 횟수와 후처리 노이즈를 줄일 수 있었습니다.
결국 이번 개선을 통해 이미지 분석 성능은 모델이나 OCR 엔진 자체의 성능뿐만 아니라, 입력 데이터를 얼마나 잘 선별하고 정리하느냐에 따라 달라질 수 있다는 점을 배웠습니다.