Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -20,10 +20,6 @@ from jinja2 import Template
|
|
20 |
import re
|
21 |
import time
|
22 |
|
23 |
-
# Add parent directory to path to import seg_rec_kraken
|
24 |
-
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
25 |
-
from seg_rec_kraken import seg_rec_image, PAGEXML_TEMPLATE
|
26 |
-
|
27 |
# Configure logging
|
28 |
logging.basicConfig(level=logging.WARNING)
|
29 |
logging.getLogger('kraken').setLevel(logging.WARNING)
|
@@ -36,11 +32,127 @@ MODELS_DIR = Path("models")
|
|
36 |
SEG_MODELS_DIR = MODELS_DIR / "seg"
|
37 |
REC_MODELS_DIR = MODELS_DIR / "rec"
|
38 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
39 |
# Create Jinja environment
|
40 |
TEMPLATE_DIR = Path("templates")
|
41 |
TEMPLATE_DIR.mkdir(exist_ok=True)
|
42 |
_ENV = Environment(loader=FileSystemLoader(str(TEMPLATE_DIR)))
|
43 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
# Create template files
|
45 |
def create_templates():
|
46 |
"""Create Jinja templates for visualization."""
|
|
|
20 |
import re
|
21 |
import time
|
22 |
|
|
|
|
|
|
|
|
|
23 |
# Configure logging
|
24 |
logging.basicConfig(level=logging.WARNING)
|
25 |
logging.getLogger('kraken').setLevel(logging.WARNING)
|
|
|
32 |
SEG_MODELS_DIR = MODELS_DIR / "seg"
|
33 |
REC_MODELS_DIR = MODELS_DIR / "rec"
|
34 |
|
35 |
+
# Embedded template
|
36 |
+
PAGEXML_TEMPLATE = '''{%+ macro render_line(line) +%}
|
37 |
+
<TextLine id="{{ line.id }}" {% if line.tags and "type" in line.tags %}custom="structure {type:{{ line.tags["type"] }};}"{% endif %}>
|
38 |
+
{% if line.boundary %}
|
39 |
+
<Coords points="{% for point in line.boundary %}{{ point|join(',') }}{% if not loop.last %} {% endif %}{% endfor %}"/>
|
40 |
+
{% endif %}
|
41 |
+
{% if line.baseline %}
|
42 |
+
<Baseline points="{% for point in line.baseline %}{{ point|join(',') }}{% if not loop.last %} {% endif %}{% endfor %}"/>
|
43 |
+
{% endif %}
|
44 |
+
{% if line.text is string %}
|
45 |
+
<TextEquiv{% if line.confidences|length %} conf="{{ (line.confidences|sum / line.confidences|length)|round(4) }}"{% endif %}><Unicode>{{ line.text|e }}</Unicode></TextEquiv>
|
46 |
+
{% else %}
|
47 |
+
{% for segment in line.recognition %}
|
48 |
+
<Word id="segment_{{ segment.index }}">
|
49 |
+
{% if segment.boundary %}
|
50 |
+
<Coords points="{% for point in segment.boundary %}{{ point|join(',') }}{% if not loop.last %} {% endif %}{% endfor %}"/>
|
51 |
+
{% else %}
|
52 |
+
<Coords points="{{ segment.bbox[0] }},{{ segment.bbox[1] }} {{ segment.bbox[0] }},{{ segment.bbox[3] }} {{ segment.bbox[2] }},{{ segment.bbox[3] }} {{ segment.bbox[2] }},{{ segment.bbox[1] }}"/>
|
53 |
+
{% endif %}
|
54 |
+
{% for char in segment.recognition %}
|
55 |
+
<Glyph id="char_{{ char.index }}">
|
56 |
+
<Coords points="{% for point in char.boundary %}{{ point|join(',') }}{% if not loop.last %} {% endif %}{% endfor %}"/>
|
57 |
+
<TextEquiv conf="{{ char.confidence|round(4) }}"><Unicode>{{ char.text|e }}</Unicode></TextEquiv>
|
58 |
+
</Glyph>
|
59 |
+
{% endfor %}
|
60 |
+
<TextEquiv conf="{{ (segment.confidences|sum / segment.confidences|length)|round(4) }}"><Unicode>{{ segment.text|e }}</Unicode></TextEquiv>
|
61 |
+
</Word>
|
62 |
+
{% endfor %}
|
63 |
+
{%+ if line.confidences|length %}<TextEquiv conf="{{ (line.confidences|sum / line.confidences|length)|round(4) }}"><Unicode>{% for segment in line.recognition %}{{ segment.text|e }}{% endfor %}</Unicode></TextEquiv>{% endif +%}
|
64 |
+
{% endif %}
|
65 |
+
</TextLine>
|
66 |
+
{%+ endmacro %}
|
67 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
68 |
+
<PcGts xmlns="http://schema.primaresearch.org/PAGE/gts/pagecontent/2019-07-15" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://schema.primaresearch.org/PAGE/gts/pagecontent/2019-07-15 http://schema.primaresearch.org/PAGE/gts/pagecontent/2019-07-15/pagecontent.xsd">
|
69 |
+
<Metadata>
|
70 |
+
<Creator>kraken {{ metadata.version }}</Creator>
|
71 |
+
<Created>{{ page.date }}</Created>
|
72 |
+
<LastChange>{{ page.date }}</LastChange>
|
73 |
+
</Metadata>
|
74 |
+
<Page imageFilename="{{ page.name }}" imageWidth="{{ page.size[0] }}" imageHeight="{{ page.size[1] }}" {% if page.base_dir %}readingDirection="{{ page.base_dir }}"{% endif %}>
|
75 |
+
{% for entity in page.entities %}
|
76 |
+
{% if entity.type == "region" %}
|
77 |
+
{% if loop.previtem and loop.previtem.type == 'line' %}
|
78 |
+
</TextRegion>
|
79 |
+
{% endif %}
|
80 |
+
<TextRegion id="{{ entity.id }}" {% if entity.tags and "type" in entity.tags %}custom="structure {type:{{ entity.tags["type"] }};}"{% endif %}>
|
81 |
+
{% if entity.boundary %}<Coords points="{% for point in entity.boundary %}{{ point|join(',') }}{% if not loop.last %} {% endif %}{% endfor %}"/>{% endif %}
|
82 |
+
{%- for line in entity.lines -%}
|
83 |
+
{{ render_line(line) }}
|
84 |
+
{%- endfor %}
|
85 |
+
</TextRegion>
|
86 |
+
{% else %}
|
87 |
+
{% if not loop.previtem or loop.previtem.type != 'line' %}
|
88 |
+
<TextRegion id="textblock_{{ loop.index }}">
|
89 |
+
<Coords points="0,0 0,{{ page.size[1] }} {{ page.size[0] }},{{ page.size[1] }} {{ page.size[0] }},0"/>
|
90 |
+
{% endif %}
|
91 |
+
{{ render_line(entity) }}
|
92 |
+
{% if loop.last %}
|
93 |
+
</TextRegion>
|
94 |
+
{% endif %}
|
95 |
+
{% endif %}
|
96 |
+
{% endfor %}
|
97 |
+
</Page>
|
98 |
+
</PcGts>'''
|
99 |
+
|
100 |
# Create Jinja environment
|
101 |
TEMPLATE_DIR = Path("templates")
|
102 |
TEMPLATE_DIR.mkdir(exist_ok=True)
|
103 |
_ENV = Environment(loader=FileSystemLoader(str(TEMPLATE_DIR)))
|
104 |
|
105 |
+
def seg_rec_image(image_path, seg_model, rec_model, output_dir=None):
|
106 |
+
try:
|
107 |
+
im = Image.open(image_path)
|
108 |
+
baseline_seg = blla.segment(im, model=seg_model)
|
109 |
+
|
110 |
+
# Run recognition and collect full BaselineOCRRecord objects
|
111 |
+
pred_it = rpred.rpred(network=rec_model, im=im, bounds=baseline_seg, pad=16)
|
112 |
+
records = [record for record in pred_it]
|
113 |
+
|
114 |
+
# Attach recognition results to segmentation lines
|
115 |
+
for line, rec_line in zip(baseline_seg.lines, records):
|
116 |
+
# Debug logging for recognition results
|
117 |
+
logger.debug(f'Recognition result - Prediction: {rec_line.prediction}')
|
118 |
+
logger.debug(f'Recognition result - Confidences: {rec_line.confidences}')
|
119 |
+
|
120 |
+
# Ensure the line has both prediction and confidence values
|
121 |
+
line.prediction = rec_line.prediction
|
122 |
+
line.text = rec_line.prediction # Set text field for serialization
|
123 |
+
|
124 |
+
# Store per-character confidences
|
125 |
+
line.confidences = rec_line.confidences # Keep the list of confidences
|
126 |
+
|
127 |
+
# Debug logging for line object
|
128 |
+
logger.debug(f'Line {line.id} - Prediction: {line.prediction}')
|
129 |
+
logger.debug(f'Line {line.id} - Confidences: {line.confidences}')
|
130 |
+
|
131 |
+
# Construct PAGE-XML segmentation only data
|
132 |
+
pagexml_seg_only = serialization.serialize(baseline_seg, image_size=im.size, template='pagexml', sub_line_segmentation=False)
|
133 |
+
|
134 |
+
# Serialize with recognition results
|
135 |
+
pagexml = serialization.serialize(baseline_seg,
|
136 |
+
image_size=im.size,
|
137 |
+
template='custom_pagexml',
|
138 |
+
template_source='custom',
|
139 |
+
sub_line_segmentation=False)
|
140 |
+
|
141 |
+
base_name = os.path.splitext(os.path.basename(image_path))[0]
|
142 |
+
if output_dir:
|
143 |
+
os.makedirs(output_dir, exist_ok=True)
|
144 |
+
output_path = os.path.join(output_dir, base_name + '.xml')
|
145 |
+
else:
|
146 |
+
output_path = os.path.splitext(image_path)[0] + '.xml'
|
147 |
+
|
148 |
+
with open(output_path, 'w') as fp:
|
149 |
+
fp.write(pagexml)
|
150 |
+
print(f"✅ Segmented/recognized: {os.path.basename(image_path)} → {os.path.basename(output_path)}")
|
151 |
+
except Exception as e:
|
152 |
+
print(f"❌ Failed to process {image_path}: {e}")
|
153 |
+
import traceback
|
154 |
+
traceback.print_exc()
|
155 |
+
|
156 |
# Create template files
|
157 |
def create_templates():
|
158 |
"""Create Jinja templates for visualization."""
|