99except Exception :
1010 LPD_YuNetORT = None
1111 ORT_AVAILABLE = False
12- import easyocr
12+ try :
13+ import easyocr
14+ EASY_AVAILABLE = True
15+ except ImportError :
16+ easyocr = None
17+ EASY_AVAILABLE = False
1318
1419try :
1520 from paddleocr import PaddleOCR
1621 PADDLE_AVAILABLE = True
1722except ImportError :
1823 PADDLE_AVAILABLE = False
1924
25+ try :
26+ import pytesseract
27+ TESSERACT_AVAILABLE = True
28+ except ImportError :
29+ pytesseract = None
30+ TESSERACT_AVAILABLE = False
31+
2032MODEL_PATH = os .path .join (os .path .dirname (__file__ ), 'license_plate_detection.onnx' )
2133CONF_THRESHOLD = 0.3
2234NMS_THRESHOLD = 0.3
@@ -52,16 +64,65 @@ def enhance_plate_image(plate_img, scale_factor=3.0):
5264 except Exception :
5365 return plate_img
5466
67+ ALLOWED_CHARS = 'АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
68+
69+
70+ def normalize_text (text ):
71+ if not text :
72+ return ""
73+ cleaned = '' .join (c for c in text if c .isalnum () or c in ALLOWED_CHARS )
74+ return cleaned .upper ()
75+
76+
5577def recognize_text_easyocr (img , reader ):
78+ if not EASY_AVAILABLE or reader is None :
79+ return ""
5680 try :
57- allowlist = 'АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
58- results = reader .readtext (img , detail = 1 , paragraph = False , allowlist = allowlist )
59- text = ' ' .join ([result [1 ] for result in results if result [2 ] > 0.2 ])
60- cleaned_text = '' .join (c for c in text if c .isalnum () or c in allowlist ).upper ()
61- return cleaned_text
81+ results = reader .readtext (img , detail = 1 , paragraph = False , allowlist = ALLOWED_CHARS )
82+ lines = [result [1 ] for result in results if len (result ) > 2 and result [2 ] > 0.2 ]
83+ return normalize_text (' ' .join (lines ))
6284 except Exception :
6385 return ""
6486
87+
88+ def recognize_text_paddle (img , reader ):
89+ if not PADDLE_AVAILABLE or reader is None :
90+ return ""
91+ try :
92+ # PaddleOCR returns a list of detections per image
93+ ocr_results = reader .ocr (img , cls = True )
94+ texts = []
95+ for result in ocr_results :
96+ for entry in result :
97+ if len (entry ) >= 2 :
98+ candidate = entry [1 ][0 ] if isinstance (entry [1 ], (list , tuple )) else entry [1 ]
99+ texts .append (candidate )
100+ return normalize_text (' ' .join (texts ))
101+ except Exception :
102+ return ""
103+
104+
105+ def recognize_text_tesseract (img ):
106+ if not TESSERACT_AVAILABLE :
107+ return ""
108+ try :
109+ config = '--oem 3 --psm 7'
110+ text = pytesseract .image_to_string (img , config = config , lang = 'eng+rus' )
111+ return normalize_text (text )
112+ except Exception :
113+ return ""
114+
115+
116+ def recognize_text (img , easy_reader = None , paddle_reader = None ):
117+ # Prefer PaddleOCR on Linux because it does not require PyTorch-sized dependencies
118+ text = recognize_text_paddle (img , paddle_reader )
119+ if text :
120+ return text
121+ text = recognize_text_easyocr (img , easy_reader )
122+ if text :
123+ return text
124+ return recognize_text_tesseract (img )
125+
65126def recognize_plate_from_rtsp (rtsp_url , frame_skip = 2 , min_score = 0.65 , min_area = 2000 , min_height = 40 , min_aspect = 1.2 , max_aspect = 7.5 , max_frames = 10 , use_ort = False ):
66127 """
67128 Recognize plates from RTSP stream.
@@ -88,7 +149,7 @@ def recognize_plate_from_rtsp(rtsp_url, frame_skip=2, min_score=0.65, min_area=2
88149 backendId = cv .dnn .DNN_BACKEND_OPENCV ,
89150 targetId = cv .dnn .DNN_TARGET_CPU
90151 )
91- reader = easyocr .Reader (['en' , 'ru' ])
152+ easyocr_reader = easyocr .Reader (['en' , 'ru' ]) if EASY_AVAILABLE else None
92153 paddle_reader = PaddleOCR (lang = 'en' , use_angle_cls = True , show_log = False , use_gpu = False ) if PADDLE_AVAILABLE else None
93154 cap = cv .VideoCapture (rtsp_url )
94155 frame_count = 0
@@ -130,7 +191,7 @@ def recognize_plate_from_rtsp(rtsp_url, frame_skip=2, min_score=0.65, min_area=2
130191 continue
131192 plate_img = frame [y_min :y_max , x_min :x_max ]
132193 plate_img = enhance_plate_image (plate_img )
133- text = recognize_text_easyocr (plate_img , reader )
194+ text = recognize_text (plate_img , easyocr_reader , paddle_reader )
134195 results .append ({
135196 "score" : float (score ),
136197 "text" : text ,
0 commit comments