Hayk Arutyunyan commited on
Commit
d249b39
·
1 Parent(s): 177fbfb

Add demo OCR version and Streamlit app

Browse files
requirements_demo.txt ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ numpy==1.26.4
2
+ pandas==2.2.3
3
+ pillow==10.4.0
4
+ opencv-python-headless==4.10.0.84
5
+ scikit-image==0.25.2
6
+
7
+ # OCR Stack — стабильный, без Paddlex
8
+ paddlepaddle==2.6.1
9
+ paddleocr==2.7.3
10
+ pytesseract==0.3.10
11
+
12
+ # Документы
13
+ python-docx==1.2.0
14
+ pdf2image==1.17.0
15
+
16
+ # Streamlit
17
+ streamlit==1.36.0
18
+ pyyaml==6.0.2
19
+ openpyxl==3.1.5
src/docx_reader.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from pdf2image import convert_from_path
3
+ from docx import Document
4
+ import tempfile
5
+
6
+ def docx_to_images(path: str):
7
+ """
8
+ Преобразовать .docx → изображения страниц.
9
+ Если poppler отсутствует, выбрасываем исключение,
10
+ чтобы Streamlit мог показать предупреждение.
11
+ """
12
+ try:
13
+ # docx → pdf → images
14
+ with tempfile.TemporaryDirectory() as tmp:
15
+ pdf_path = os.path.join(tmp, "temp.pdf")
16
+
17
+ # Преобразование docx → pdf
18
+ # Здесь мы делаем максимально простой экспорт:
19
+ doc = Document(path)
20
+ doc.save(pdf_path)
21
+
22
+ # pdf → images
23
+ images = convert_from_path(pdf_path)
24
+ return images
25
+
26
+ except Exception as e:
27
+ raise RuntimeError(
28
+ "DOCX обработка недоступна: отсутствует poppler "
29
+ "или системные зависимости."
30
+ ) from e
src/ocr_utils_demo.py ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ OCR-инструменты: pytesseract для титула и PaddleOCR для датчиков.
3
+ """
4
+
5
+ import cv2
6
+ import numpy as np
7
+ from paddleocr import PaddleOCR
8
+ import pytesseract
9
+
10
+
11
+ # --------------------------
12
+ # OCR титула (pytesseract)
13
+ # --------------------------
14
+ def ocr_title(img: np.ndarray) -> str:
15
+ """
16
+ OCR верхней области (титул мнемосхемы).
17
+ """
18
+ if img is None or img.size == 0:
19
+ return ""
20
+
21
+ gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
22
+ gray = cv2.convertScaleAbs(gray, alpha=2.0, beta=-40)
23
+
24
+ binary = cv2.adaptiveThreshold(
25
+ gray, 255,
26
+ cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
27
+ cv2.THRESH_BINARY_INV,
28
+ 15, 9
29
+ )
30
+
31
+ text = pytesseract.image_to_string(binary, lang="eng", config="--psm 7").strip()
32
+ return text
33
+
34
+
35
+ # --------------------------
36
+ # OCR датчиков (PaddleOCR)
37
+ # --------------------------
38
+ paddle_ocr = PaddleOCR(
39
+ lang="en",
40
+ use_angle_cls=False,
41
+ det=False,
42
+ rec=False
43
+ )
44
+
45
+
46
+ def ocr_sensors(rois: list[np.ndarray]) -> list[dict]:
47
+ """
48
+ OCR областей сенсоров через PaddleOCR.predict().
49
+ Формат вывода:
50
+ [{"text": str, "score": float}, ...]
51
+ """
52
+ results = []
53
+
54
+ if not rois:
55
+ return []
56
+
57
+ for roi in rois:
58
+ try:
59
+ ocr_results = paddle_ocr.ocr(roi, cls=False)
60
+ except Exception as e:
61
+ results.append({"text": "?", "score": 0.0})
62
+ continue
63
+
64
+ if ocr_results and ocr_results[0]:
65
+ text, score = ocr_results[0][0][1]
66
+ else:
67
+ text, score = "?", 0.0
68
+
69
+ results.append({
70
+ "text": text,
71
+ "score": float(score)
72
+ })
73
+
74
+ return results
75
+
src/pipeline.py CHANGED
@@ -9,7 +9,7 @@ from pathlib import Path
9
  from docx import Document
10
 
11
  from src.config_loader import load_config
12
- from src.ocr_utils import ocr_title, ocr_sensors
13
 
14
 
15
  # ---------------------------------------------------------
 
9
  from docx import Document
10
 
11
  from src.config_loader import load_config
12
+ from src.ocr_utils_demo import ocr_title, ocr_sensors
13
 
14
 
15
  # ---------------------------------------------------------
streamlit_app.py ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import numpy as np
3
+ import cv2
4
+ import pandas as pd
5
+ from pathlib import Path
6
+
7
+ from src.config_loader import load_config
8
+ from src.pipeline import extract_text
9
+ from src.docx_reader import docx_to_images
10
+
11
+ st.set_page_config(page_title="Mnemo OCR Demo", layout="wide")
12
+ st.title("🧠 Mnemo OCR — демонстрация")
13
+
14
+ CONFIG_PATH = Path("configs/config.yaml")
15
+ cfg = load_config(CONFIG_PATH)
16
+ color_ranges = cfg["colors"]
17
+
18
+ uploaded = st.file_uploader("Загрузите PNG/JPG/DOCX файл", type=["png", "jpg", "jpeg", "docx"])
19
+
20
+ if not uploaded:
21
+ st.info("Загрузите изображение или DOCX-файл.")
22
+ st.stop()
23
+
24
+ filename = uploaded.name.lower()
25
+
26
+ # ---- DOCX ----
27
+ if filename.endswith(".docx"):
28
+ st.subheader("Документ DOCX")
29
+
30
+ try:
31
+ images = docx_to_images(uploaded)
32
+ except Exception as e:
33
+ st.error(f"⚠ DOCX нельзя обработать в этой среде.\n{e}")
34
+ st.stop()
35
+
36
+ st.write("Обнаружено страниц:", len(images))
37
+
38
+ results_all = []
39
+
40
+ for idx, page in enumerate(images):
41
+ st.write(f"### Страница {idx+1}")
42
+
43
+ img = cv2.cvtColor(np.array(page), cv2.COLOR_RGB2BGR)
44
+
45
+ with st.spinner("OCR..."):
46
+ title_text, sensors = extract_text(img, color_ranges)
47
+
48
+ st.write("**Титул:**", title_text)
49
+
50
+ if sensors:
51
+ df = pd.DataFrame(sensors)
52
+ st.dataframe(df)
53
+ results_all.append(df)
54
+ else:
55
+ st.info("Сенсоры не найдены.")
56
+
57
+ if results_all:
58
+ df_total = pd.concat(results_all, ignore_index=True)
59
+ st.download_button("Скачать CSV", df_total.to_csv(index=False).encode(), "result.csv", "text/csv")
60
+
61
+ st.stop()
62
+
63
+ # ---- PNG/JPG ----
64
+ else:
65
+ file_bytes = np.frombuffer(uploaded.read(), np.uint8)
66
+ img = cv2.imdecode(file_bytes, cv2.IMREAD_COLOR)
67
+
68
+ st.image(cv2.cvtColor(img, cv2.COLOR_BGR2RGB), use_column_width=True)
69
+
70
+ with st.spinner("OCR..."):
71
+ title_text, sensors = extract_text(img, color_ranges)
72
+
73
+ st.write("### Титул")
74
+ st.write(title_text)
75
+
76
+ st.write("### Сенсоры")
77
+ if sensors:
78
+ df = pd.DataFrame(sensors)
79
+ st.dataframe(df)
80
+ st.download_button(
81
+ "Скачать CSV",
82
+ df.to_csv(index=False).encode(),
83
+ "sensors.csv",
84
+ "text/csv"
85
+ )
86
+ else:
87
+ st.info("Сенсоры не найдены.")