2025, Oct 15 22:31
EasyOCR से अक्षर-स्तर बॉक्स कैसे निकालें: OpenCV और connected components
EasyOCR अक्षर-स्तर बॉक्स नहीं देता. इस गाइड में OpenCV और connected components से शब्द-स्तर डिटेक्शन से अक्षर-स्तर बॉक्स निकालने का Python तरीका सीखें.
जब आपको शब्द-स्तर के OCR से आगे की जानकारी चाहिए, तो अक्षर-स्तर के निर्देशांक अक्सर अनिवार्य होते हैं: सूक्ष्म चयन, संरेखण या बाद की प्रोसेसिंग—ये सब हर ग्लिफ़ के लिए सटीक बॉक्स पर टिके होते हैं. EasyOCR शब्दों या वाक्यांशों के लिए बहुभुजी बॉक्स और एक कॉन्फिडेंस मान देता है, लेकिन प्रति-अक्षर बॉक्स नहीं. EasyOCR के आउटपुट पर थोड़ी सी इमेज प्रोसेसिंग जोड़कर इस अंतर को कैसे पाटा जा सकता है, नीचे बताया गया है.
समस्या
EasyOCR प्रत्येक डिटेक्टेड टेक्स्ट रीजन के लिए एक प्रविष्टि लौटाता है, जिसमें एक चतुर्भुज बॉन्डिंग बॉक्स, पहचानी गई स्ट्रिंग और कॉन्फिडेंस स्कोर होता है. एक सामान्य आइटम कुछ ऐसा दिखता है:
[
    [
        [60, 88],
        [639, 88],
        [639, 124],
        [60, 124]
    ],
    "Some phrase",
    0.6820449765391986
]
सवाल यह है कि क्या बिना हर अक्षर की स्थिति हाथ से निकाले, सीधे अक्षर-स्तर के बॉक्स प्राप्त किए जा सकते हैं?
समस्या क्यों आती है
EasyOCR मूल रूप से अक्षर-स्तर के निर्देशांक प्रदान नहीं करता. आपको प्रति-ग्लिफ़ नहीं, बल्कि प्रति-वाक्यांश एक बॉन्डिंग आकृति मिलती है. अक्षर बॉक्स निकालने के लिए, प्रत्येक डिटेक्टेड रीजन के भीतर काम करके सामग्री को खुद से सेगमेंट करना पड़ता है. एक व्यावहारिक तरीका है: क्रॉप किए गए हिस्से को बाइनरी में बदलें, connected components ढूँढें, और वे कंपोनेंट चुनें जो टेक्स्ट लाइन की क्षैतिज मध्य-रेखा (या बेसलाइन) को काटते हों. क्षैतिज चौड़ाई हर कंपोनेंट से ली जा सकती है, जबकि ऊर्ध्वाधर सीमा मूल EasyOCR रीजन से ली जा सकती है.
समाधान
कार्यप्रवाह सीधे EasyOCR के आउटपुट पर टिका है: रीजन को क्रॉप करें, उसे बाइनरी इमेज में बदलें, connected components इकट्ठे करें, क्षैतिज सेंटरलाइन पर स्कैन करके टेक्स्ट से जुड़े कंपोनेंट चुनें, और उन्हीं से अक्षर बॉक्स बनाएं. परीक्षण के लिए उपयोग की गई उदाहरण इमेज इस पेज से ली गई है. इस पर एक प्रासंगिक चर्चा यहाँ भी है: github.com/JaidedAI/EasyOCR/issues/631.
import easyocr
import cv2
import numpy as np
# EasyOCR चलाएँ
ocr_engine = easyocr.Reader(['en'])
src_path   = 'testocr.png'
frame      = cv2.imread(src_path)
detections = ocr_engine.readtext(src_path)
annotated  = frame.copy()
# OCR डिटेक्शंस पर लूप चलाएँ
for quad, snippet, score in detections:
    # 1) डिटेक्टेड रीजन को क्रॉप करें
    qarr = np.array(quad, dtype=np.int32)
    left,  top    = qarr[:, 0].min(), qarr[:, 1].min()
    right, bottom = qarr[:, 0].max(), qarr[:, 1].max()
    window = frame[top:bottom, left:right]
    # 2) बाइनराइज़ करें और connected components निकालें
    mono = cv2.cvtColor(window, cv2.COLOR_BGR2GRAY)
    _, mask = cv2.threshold(mono, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
    n_tags, tagmap, props, centers = cv2.connectedComponentsWithStats(mask, connectivity=8)
    # 3) रीजन की क्षैतिज मध्य-रेखा को स्कैन करें
    midrow = window.shape[0] // 2
    touched = set()
    for cx in range(window.shape[1]):
        tag = tagmap[midrow, cx]
        if tag != 0:
            touched.add(tag)
    # 4) कैरेक्टर बॉक्स बनाएँ: चौड़ाई कंपोनेंट्स से, ऊँचाई मूल रीजन से
    for tag in touched:
        px, py, pw, ph, pa = props[tag]
        bounds = (px + left, top, pw, bottom - top)
        cv2.rectangle(annotated, (bounds[0], bounds[1]), (bounds[0] + bounds[2], bounds[1] + bounds[3]), (0, 255, 0), 1)
cv2.imwrite('output.png', annotated)
यह कैसे काम करता है
EasyOCR से मिला वाक्यांश बॉक्स अक्षरों के लिए एक स्थिर ऊर्ध्वाधर फैलाव तय करता है. उसी रीजन के भीतर, बाइनराइज़ेशन और connected component विश्लेषण स्याही के सटे हुए ब्लॉब्स दिखाते हैं. रीजन की क्षैतिज सेंटरलाइन पर स्वाइप करके, आप सिर्फ वे कंपोनेंट इकट्ठे करते हैं जो टेक्स्ट लाइन पर बैठे हैं. प्रत्येक कंपोनेंट की चौड़ाई उसका क्षैतिज विस्तार देती है, जबकि ऊर्ध्वाधर सीमा EasyOCR वाले बॉक्स से आती है. मूल इमेज की प्रति पर खींचे गए आयत अक्षर-स्तर के बॉक्स दिखाते हैं.
यह क्यों मायने रखता है
जब आपका उपयोग-केस अक्षर-स्तर के निर्देशांकों पर टिका हो, तो केवल वाक्यांश-स्तर के बॉक्स पर्याप्त नहीं होते. EasyOCR के साथ connected component विश्लेषण जोड़ने से, बिना OCR इंजन में बदलाव किए या उसके अप्रकट फीचर्स पर निर्भर हुए, प्रति-अक्षर ज्योमेट्री पाने का व्यावहारिक रास्ता मिल जाता है.
मुख्य निष्कर्ष
यदि आपको EasyOCR से अक्षर बॉक्स चाहिए, तो वाक्यांश-स्तर के बहुभुजों को एंकर की तरह इस्तेमाल करें, अंदरूनी हिस्से को बाइनराइज़ करें, connected components इकट्ठे करें, glyphs की पहचान के लिए क्षैतिज सेंटरलाइन पर ट्रैवर्स करें, और प्रति-अक्षर आयतें निकालें. ऊपर दिया गया तरीका एक कामकाजी बेसलाइन है, जिसे आप अपने डेटा और सीमाओं के हिसाब से ढाल सकते हैं.