Szállítás

Ingyenes kiszállítás

Támogatás 24

+36 (30) 525-2969

Shop.Szerver.Hu Blog

LocalAI-ANPR-1200x675

Rendszámfelismerés LocalAI-n, átlagos kamerával, töredékáron

Képzeld el, hogy van egy benzinkutad, ahonnan időnként fizetés nélkül lelép egy-két gyökér. De jó lenne tudni a rendszámukat, nem? Vagy van egy parkolóházad, telephelyed, ahol autók, teherautók jönnek-mennek. Jó lenne egy lista, milyen járművek, pontosan mikor érkeztek, távoztak. Akár napi/heti/havi perc alapú parkolódíjat lehetne számolni sorompók nélkül is!

Természetesen megvásárolhatók ilyen profi rendszerek. Csak érdekességképpen, egy speciális rendszámfelismerő kamera ára kb. nettó 3-400 ezer forintnál kezdődik. Egy ki-beléptető kapunál kell belőle két darab. Plusz meg kell venni hozzá a specifikus szoftvert újabb sokszáz-ezer forintért. Máris milliónál tartunk és még nincs benne a számítógép, ami igyekszik rögzíteni/feldolgozni.

Ezt a feladatot meg lehet oldani sokkal gazdaságosabban is:  LocalAI!

„Sima, bolti”, nem-speciális kamerákkal is kivitelezhető a dolog. Nem kell hozzá spec szoftvert sem venni, mert meg lehet íratni a kódot az AI-val. Akár a saját Local AI gépeden is, ChatGPT előfizetés nélkül. Szerintem elég menő.

Feladat: valós időben felismerni a képen felbukkanó rendszámokat és dátummal, időponttal együtt beírni egy MySQL adatbázisba.

A leolvasott rendszámok a MySQL adatbázisban:

rendszamok-phpmysql
Ha újra megnézed a videót, a második autó rendszáma túl sokáig takarásban volt, emiatt nem ismerte fel az OCR karakterfelismerő. Kellene még kalapálni a kódon, de ez most csak egy teszt.

A folyamat lépései, bedolgozók, kódok

Nem leszek túl részletes, inkább csak felsorolásszerűen adom meg a lépéseket, szőrmentiben mutatom be a felhasznált szoftvereket, folyamatokat, kódokat. Ha érdekelnek a további részletek, keress meg, szívesen segítek.

Alapvetően három részre bontható a feladat:

  1. objektumfelismerés (rendszámtábla felismerése)
  2. rendszám karakterek felismerése (OCR)
  3. az eredmény MySQL adatbázisba írása

1. Objektumfelismerés YOLO-val (You Only Look Once)

Az Ultralytics YOLO Vision a valós idejű objektumdetektálás legújabb fejlesztése, amely kiemelkedő pontosságot és hatékonyságot kínál különféle számítógépes objektumfelismerési feladatokhoz. Fejlett képességei révén ideális választás a rendszámfelismeréshez, mivel képes gyorsan és pontosan azonosítani és nyomon követni a járművek rendszámtábláit valós időben.yolo-logoTermészetesen egy csomó minden másra is használható a YOLO: termék- és selejtfelismerés futószalagon, raktárban, bárhol. Tárgyak, emberek, állatok felismerése, számlálása stb., mindez valós időben, kamerák képéről.

Elég egyszerű az installálása Ubuntun:

git clone clone https://github.com/ultralytics/ultralytics.git
cd ultralytics
pip install ultralytics

Ellenőrizzük le, hogy van-e Torch és GPU (CUDA) támogatásunk:

Ha ez eddig megvan, akkor minden rendben: van Torch és GPU támogatás (True).
ultralytics-folders
Még kiíratom a könyvtárakat, itt lesznek a feltöltött dataset-ek, modellek, és a képfelismerés eredmények.

Következő lépés kiválasztani egy YOLO modellt és betanítani, hogy ezúttal rendszámokat ismerjen fel.

A betanítást Roboflow-ról letöltött dataset segítségével végzem el. Nem kell nekem autókat fényképezni és egyenként bekeretezni a fotókon a rendszámokat, hogy ebből tanuljon a modell. Megtették ezt helyettem sokan mások, gond nélkül fel tudom használni, hiszen itt minden nyílt forráskódú.

A letöltött fényképeket meghatározott könyvtárakban helyezem el és megmutatom a YOLO modellnek a data.yaml fájlban, hol találja ezeket a betanulás során:

universe-roboflow-licenseplate
A data.yaml fájlban határozom meg a YOLO modell tanításához, hogy hol találja az előkészített rendszámos képeket

A modell betanítása egy szimpla parancssorból történhet. Az első tesztekhez a legújabb YOLO11 és annak legkisebb modelljét használtam: yolo11n.pt (ez a nano méretű, legkisebb modell).

yolo task=detect mode=train epochs=100 batch=16 plots=True model=yolo11n.pt data=data.yaml

100 epoch, azaz 100 lépésen keresztül tanítom a YOLO modellt az előzőleg letöltött autós képekkel. Ha megtörtént a betanítás, ideje kipróbálni! Íme, egy parancssorral már egy szimpla képen máris felismeri a rendszámot:

yolo task=detect mode=predict conf=0.25 save=True model=.pyenv/runs/detect/train2/weights/best.pt source=mza1-k.jpg

Nagyon hamar lefutott, a másodperc töredéke alatt. Kész is a kép a bekeretezett rendszámmal.

ultralytics-mza1-k
Woww, ez könnyű volt, megvan egy könnyed objektumfelismerés, egyetlen parancssorból! Az eredményt a .pyenv/runs/detect/predict5 könyvtárban találom.
A YOLO11 modell 81 százalékos biztonsággal ismerte fel a képen a rendszámot.

Ugyanígy parancssorból nemcsak képeken, hanem már videókon is felismeri már a betanított modell a rendszámokat. De lépjünk tovább: most még csak a betanított objektum (rendszámtábla) lett felismerve, olvassuk ki a betűket/számokat is, sőt rögzítsük egy táblázatban!

Rendszámfelismerés OCR-rel együtt, MySQL adatbázissal

A lényeg, hogy a képen (videó képkockán) felismert rendszámtábla, amely be van keretezve, na ezt a kis keretet egy kicsi képpé alakítva futtassunk rajta karakterfelismerést (OCR)!

Erre a feladatra most egy könnyű kis bedolgozót, PaddleOCR-t fogunk használni:

ocr = PaddleOCR()

Csak akkor csinálunk karakterfelismerést, ha a videón az autó rendszáma beért az általam megrajzolt kék keretbe. (Nem kell minden rendszámot felismerni, csak azokat, amiket én akarok.)

Kell egy kis szövegátalakítás a magyar rendszámok miatt, kivenni a karaktersorozat elejéről a kis H betűt és a szokásos formátumra hozni a rendszámot: ABC 123, vagy AB CD 123

Majd csatlakozunk a MySQL adatbázishoz és beírjuk az aktuális rekordot dátummal és idővel.

A teljes Python kód (LocalAI-val írattam):

				
					import cv2
from ultralytics import YOLO
from paddleocr import PaddleOCR
import numpy as np
from server import manage_numberplate_db
import cvzone
# Initialize PaddleOCR
ocr = PaddleOCR()
cap = cv2.VideoCapture('20250130_124028.mp4')
# model = YOLO("best_float32.tflite")
model = YOLO("/home/laszlofesus/.pyenv/runs/detect/train2/weights/best.pt")
with open("coco1.txt", "r") as f:
    class_names = f.read().splitlines()

plate_dict = {}  # Track ID -> rendszám tárolására

# Function to perform OCR on an image array
def perform_ocr(image_array):
    if image_array is None:
        raise ValueError("Image is None")

    # Perform OCR on the image array
    results = ocr.ocr(image_array, rec=True)  # rec=True enables text recognition
    detected_text = []

    # Process OCR results
    if results[0] is not None:
        for result in results[0]:
            text = result[1][0]
            detected_text.append(text)

    # Join all detected texts into a single string
    return ''.join(detected_text)

# Mouse callback function to print mouse position
def RGB(event, x, y, flags, param):
    if event == cv2.EVENT_MOUSEMOVE:
        point = [x, y]
        print(point)

cv2.namedWindow('RGB')
cv2.setMouseCallback('RGB', RGB)

# Initialize video capture and YOLO model
count = 0
area =[(400, 200), (400, 400), (800, 400), (800, 200)]  # a kék keret koordinátái
counter = []

while True:
    ret, frame = cap.read()
    if not ret:
        break
#    count += 1
#    if count % 3 != 0:
#        continue

    frame = cv2.resize(frame, (1280, 720))  # HD felbontás, több részletet tart meg
    # Run YOLOv11 tracking on the frame
    results = model.track(frame, persist=True,imgsz=640)  # 640 a maximum, 512-vel is jól működik, gyorsabb

    # Check if there are any boxes in the results
    if results[0].boxes is not None and results[0].boxes.id is not None:
        boxes = results[0].boxes.xyxy.int().cpu().tolist()  # Bounding boxes
        class_ids = results[0].boxes.cls.int().cpu().tolist()  # Class IDs
        track_ids = results[0].boxes.id.int().cpu().tolist()  # Track IDs
        confidences = results[0].boxes.conf.cpu().tolist()  # Confidence score

        for box, class_id, track_id, conf in zip(boxes, class_ids, track_ids, confidences):
            # c = class_names[class_id]  # most nincs szükség az osztálynevekre (itt most: "numberplate")
            x1, y1, x2, y2 = box
            cx=int(x1+x2)//2
            cy=int(y1+y2)//2
            # cv2.circle(frame,(cx,cy),4,(255,0,0),-1)
            # cvzone.putTextRect(frame,f'{track_id}',(x1,y1),1,1)
            # cv2.rectangle(frame,(x1,y1),(x2,y2),(0,255,0),2)

            result = cv2.pointPolygonTest(np.array(area, np.int32), ((cx, cy)), False)
            if result >= 0:
                if track_id not in counter:

                    counter.append(track_id)  # Only add if it's a new track ID

                    crop = frame[y1:y2, x1:x2]
                    crop = cv2.resize(crop, (130, 70))  # A rendszám téglalap mérete

                    text = perform_ocr(crop)
                    print(text)
                    print(f"Track ID: {track_id} - Rendszám: {text}")
                    text = text.replace('(', '').replace(')', '').replace(',', '').replace(']', '').replace('-', ' ')

                    # Ha magyar rendszám, és a beolvasott szöveg "H" betűvel kezdődik és legalább 4 betűből áll az első rész
                    parts = text.split()  # Szóközökkel felbontjuk
                    if len(parts) > 1 and parts[0].startswith("H") and len(parts[0]) == 4:
                        parts[0] = parts[0][1:]  # Levágjuk az első H betűt
                        text = " ".join(parts)  # Újra összerakjuk a rendszámot

                    # Csak akkor frissítsük a plate_dict-et, ha a rendszám még nincs benne!
                    if track_id not in plate_dict or plate_dict[track_id] != text:
                        plate_dict[track_id] = text  # Mentsd el a rendszámot a track_id-hez!

                    manage_numberplate_db(text)  # Writes the actual numberplate to the MySQL database

            # Rendszám box rajzolása
            cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)

            # Kiírás: ha van hozzátartozó rendszám, akkor azt írja ki, különben "--"
            plate_text = plate_dict.get(track_id, "--")
            cvzone.putTextRect(frame, plate_text, (x1, y1 - 10), 1, 1)

    mycounter = len(counter) # Egyedi rendszámok számlálása és a számláló kiírása
    cvzone.putTextRect(frame,f'{mycounter}',(50,60),1,1)
    cv2.polylines(frame, [np.array(area, np.int32)], True, (255, 0, 0), 2)

    # video/kép megjelenítése
    cv2.imshow("RGB", frame)
    if cv2.waitKey(1) & 0xFF == 27:  # cv2.waitKey(0) - képenként, cv2.waitKey(1) - folyamatosan, Press 'Esc' to exit
        break

# Close video capture and MySQL connection
cap.release()
cv2.destroyAllWindows()
				
			

Python modulok/könyvtárak amiket felhasználtunk a Python kód elején:

KönyvtárFunkció
cv2 (OpenCV)Kép/video beolvasása és előfeldolgozása
ultralytics.YOLOYOLO objektumdetekció (rendszámtábla felismerés)
paddleocr.PaddleOCROCR-alapú szövegfelismerés (rendszám kiolvasása)
numpy (np)Numerikus számítások és tömbkezelés
server.manage_numberplate_dbAdatbázis kezelés (rendszámok tárolása az adatbázisban)
cvzoneVizuális megjelenítés (bounding boxok, szöveg overlay)

Kis túlzással, többi időt töltöttem ennek a cikknek a megírásával, mint a YOLO munkára fogásával és a kódolással. De akárhogy is, nagyon élveztem, szuper ez az egész!

Talán mondanom sem kell, a kódok megírásánál is nagy segítségemre volt az AI.
Zseniális a LocalAI!

AI-szervert keresel?

Speciális munkafolyamatokra szabott AI szervereket és munkaállomásokat építünk akár előtelepített Linux/AI/LLM/RAG környezettel.

Nem tudod, hol kezd? Mi segítünk!

Lépj kapcsolatba AI műszaki tanácsadóink egyikével még ma! Segítünk kiválasztani az adott feladara legalkalmasabb LLM modellt és hozzá a megfelelő hardvert.

Older

LocalAI – aktuális árajánlat egy lokális AI munkaállomásra

Newer

A HPE MSA Gen7 Storage megérkezett – promóció!

Vélemény, hozzászólás?

Az e-mail címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük

Shopping cart
Sign in

No account yet?

Create an Account
Product Categories
Follow:
Termékkategóriák