Rozpoznávání dopravních značek / Habr
Počítačové vidění je obor informatiky, který se zaměřuje na reprodukci částí složitého lidského vizuálního systému a umožňuje počítačům identifikovat a zpracovávat objekty na obrázcích a videích, stejně jako lidi. Rané experimenty s počítačovým viděním začaly v 1950. letech 1970. století a byly poprvé komerčně použity k rozlišení mezi tištěným a ručně psaným textem v XNUMX. letech. Aplikace počítačového vidění dnes exponenciálně rostly. Tento článek ukazuje příklad, jak rozpoznat dopravní značky pomocí počítačového vidění.

Datový soubor dopravních značek
Tento článek používá veřejně dostupnou datovou sadu dostupnou na Kaggle: GTSRB je problém klasifikace jednoho snímku s více třídami, který byl proveden na Mezinárodní společné konferenci o neuronových sítích (IJCNN) 2011. Soubor dat obsahuje více než 50 000 snímků různých dopravních značek a je klasifikován do 43 různých tříd. Je to docela rozmanité: některé třídy obsahují mnoho obrázků a některé třídy obsahují několik obrázků.
Prozkoumání souboru dat
Nejprve naimportujeme všechny potřebné knihovny.
import os import matplotlib import numpy as np from PIL import Image from tensorflow.keras.preprocessing.image import img_to_array from sklearn.model_selection import train_test_split from keras.utils import to_categorical from keras.models import Sequential, load_model from keras.layers import Conv2D, MaxPool2D, Dense, Flatten, Dropout from tensorflow.keras import backend as K import matplotlib.pyplot as plt from sklearn.metrics import accuracy_score K trénování neuronové sítě použijeme obrázky ze složky „vlak“, která obsahuje 43 složek jednotlivých tříd. Inicializujeme dva seznamy: datum a štítky. Tyto seznamy budou zodpovědné za ukládání našich obrázků, které nahrajeme, spolu s jejich odpovídajícími štítky tříd.
data = [] labels = [] Dále pomocí modulu os projdeme všechny třídy a přidáme obrázky a jejich odpovídající štítky do seznamu. datum и etikety. Knihovna se používá k otevření obsahu obrázku. PIL.
for num in range(0, classes): path = os.path.join('train',str(num)) imagePaths = os.listdir(path) for img in imagePaths: image = Image.open(path + '/'+ img) image = image.resize((30,30)) image = img_to_array(image) data.append(image) labels.append(num) Tato smyčka jednoduše stáhne a změní velikost každého obrázku na pevných 30×30 pixelů a uloží všechny obrázky a jejich štítky do seznamů datum и etikety.
Poté musíte seznam převést na pole otupělý pro vkládání do modelu.
data = np.array(data) labels = np.array(labels) Tvar dat je (39209, 30, 30, 3), což znamená, že existuje 39 obrázků o velikosti 209×30 pixelů a poslední 30 znamená, že data obsahují barevné obrázky (hodnota RGB).
print(data.shape, labels.shape) (39209, 30, 30, 3) (39209,) Z balíčku sklearn používáme metodu train_test_split() k rozdělení trénovacích a testovacích dat, přičemž 80 % obrázků používáme pro trénování a 20 % pro testování. Toto je typické rozdělení pro toto množství dat.
X_train, X_test, y_train, y_test = train_test_split(data, labels, test_size=0.2, random_state=42) print(X_train.shape, X_test.shape, y_train.shape, y_test.shape) (31367, 30, 30, 3) (7842, 30, 30, 3) (31367,) (7842,) Pojďme zkontrolovat, kolik tříd máme a kolik obrázků je v trénovací sadě pro každou třídu a vykreslete graf rozdělení tříd.
def cnt_img_in_classes(labels): count = <> for i in labels: if i in count: count[i] += 1 else: count[i] = 1 return count samples_distribution = cnt_img_in_classes (y_train) def diagram(count_classes): plt.bar(range(len(dct)), sorted(list(count_classes.values())), align='center') plt.xticks(range(len(dct)), sorted(list(count_classes.keys())), rotation=90, fontsize=7) plt.show() diagram(samples_distribution) 
Z grafu vidíme, že trénovací dataset není vyvážený, ale s tímto faktem se můžeme vypořádat pomocí metody augmentace dat.
def aug_images(images, p): from imgaug import augmenters as iaa augs = iaa.SomeOf((2, 4), [ iaa.Crop(px=(0, 4)), iaa.Affine(scale=), iaa.Affine(translate_percent=), iaa.Affine(rotate=(-45, 45)) iaa.Affine(shear=(-10, 10)) ]) seq = iaa.Sequential([iaa.Sometimes(p, augs)]) res = seq.augment_images(images) return res def augmentation(images, labels): min_imgs = 500 classes = cnt_img_in_classes(labels) for i in range(len(classes)): if (classes[i] < min_imgs): add_num = min_imgs - classes[i] imgs_for_augm = [] lbls_for_augm = [] for j in range(add_num): im_index = random.choice(np.where(labels == i)[0]) imgs_for_augm.append(images[im_index]) lbls_for_augm.append(labels[im_index]) augmented_class = augment_imgs(imgs_for_augm, 1) augmented_class_np = np.array(augmented_class) augmented_lbls_np = np.array(lbls_for_augm) imgs = np.concatenate((images, augmented_class_np), axis=0) lbls = np.concatenate((labels, augmented_lbls_np), axis=0) return (images, labels) X_train, y_train = augmentation(X_train, y_train) Po augmentaci má naše tréninková datová sada následující tvar.
print(X_train.shape, X_test.shape, y_train.shape, y_test.shape) (36256, 30, 30, 3) (7842, 30, 30, 3) (36256,) (7842,) Znovu zkontrolujeme rozložení dat.
augmented_samples_distribution = cnt_img_in_classes(y_train) diagram(augmented_samples_distribution) 
Graf ukazuje, že naše sestava se stala vyrovnanější. Dále z balíku keras.utils používáme metodu to_categorical k převodu štítků přítomných v y_train a t_test na jednorázové kódování.
y_train = to_categorical(y_train, 43) y_test = to_categorical(y_test, 43) Budování neuronové sítě
K vytvoření neuronové sítě bude použita knihovna Keras. Pro klasifikaci obrázků do příslušných kategorií vytvoříme model CNN (Convolutional Neural Network). CNN je nejvhodnější pro účely klasifikace obrázků.
Architektura našeho modelu:
- 2 vrstvy Conv2D (filtr=32, kernel_size=(5,5), aktivace=”relu”)
- MaxPool2D vrstva (pool_size=(2,2))
- Vrstva vyřazení (míra = 0.25)
- 2 vrstvy Conv2D (filtr=64, kernel_size=(3,3), aktivace=”relu”)
- MaxPool2D vrstva (pool_size=(2,2))
- Vrstva vyřazení (míra = 0.25)
- Zploštěním vrstvy stlačíte vrstvy do 1 rozměru
- Hustá vrstva (500, aktivace = “relu”)
- Vrstva vyřazení (míra = 0.5)
- Hustá vrstva (43, aktivace = “softmax”)
class Net: @staticmethod def build(width, height, depth, classes): model = Sequential() inputShape = (height, width, depth) if K.image_data_format() == 'channels_first': inputShape = (depth, heigth, width) model = Sequential() model.add(Conv2D(filters=32, kernel_size=(5,5), activation='relu', input_shape=inputShape)) model.add(Conv2D(filters=32, kernel_size=(5,5), activation='relu')) model.add(MaxPool2D(pool_size=(2, 2))) model.add(Dropout(rate=0.25)) model.add(Conv2D(filters=64, kernel_size=(3, 3), activation='relu')) model.add(Conv2D(filters=64, kernel_size=(3, 3), activation='relu')) model.add(MaxPool2D(pool_size=(2, 2))) model.add(Dropout(rate=0.25)) model.add(Flatten()) model.add(Dense(500, activation='relu')) model.add(Dropout(rate=0.5)) model.add(Dense(classes, activation='softmax')) return model Modelový trénink a testování
Náš model vytváříme pomocí optimalizátoru Adam a ztrátová funkce je kategorická_crossentropie, protože máme více tříd, které musíme kategorizovat. Poté model natrénujeme pomocí funkce model.fit().
epochs = 25 model = Net.build(width=30, height=30, depth=3, classes=43) model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) history = model.fit(X_train, y_train, batch_size=64, validation_data=(X_test, y_test), epochs=epochs) 
Jak můžete vidět, náš model byl trénován pro 25 epoch a dosáhl 93% přesnosti na trénovací datové sadě. Pomocí matplotlib vykreslíme přesnost a ztrátu.
plt.style.use("plot") plt.figure() N = epochs plt.plot(np.arange(0, N), history.history["loss"], label="train_loss") plt.plot(np.arange(0, N), history.history["val_loss"], label="val_loss") plt.plot(np.arange(0, N), history.history["accuracy"], label="train_acc") plt.plot(np.arange(0, N), history.history["val_accuracy"], label="val_acc") plt.title("Training Loss and Accuracy") plt.xlabel("Epoch") plt.ylabel("Loss/Accuracy") plt.legend(loc="lower left") plt.show() 
Testování modelu na testovací sadě
Datová sada obsahuje složku nazvanou „Test“ a soubor Test.csv obsahuje informace související s cestou k obrázku a popisky tříd. Extrahujeme cestu k obrázku a štítky ze souboru Test.csv pomocí frameworku Pandas. Dále změníme velikost obrázku na 30×30 pixelů a vytvoříme numpy pole obsahující všechna data obrázku. Pomocí přesnosti_skóre z metrik sklearn kontrolujeme přesnost předpovědí našeho modelu. Na tomto modelu jsme dosáhli přesnosti 96 %.
y_test = pd.read_csv('Test.csv') labels = y_test["ClassId"].values imgs = y_test["Path"].values images=[] for img in imgs: image = Image.open(img) image = image.resize((30,30)) images.append(img_to_array(image)) X_test=np.array(images) pred = model.predict_classes(X_test) print(accuracy_score(labels, pred)) 0.958590657165479 - krajta
- keras
- strojové učení
- hluboké učení
- strojové učení
- neuronové sítě
- zpracování obrazu
- rozpoznávání vzorů
- PYTHON
- Zpracování obrazu
- Strojové učení
Kolik toho musí řidič vědět, aby neporušoval obecně uznávaná pravidla silničního provozu! Je dobré, když je řidič zkušený a jeho jednání za volantem je automatizované. Co by ale měl dělat začínající automobilový nadšenec, který se jen snaží zvládnout základy řemesla? Aby takovým řidičům pomohli, snaží se největší automobilky „naučit“ svá auta maličkostem, které mohou člověku na silnici pomoci. Jedním z těchto pomocníků je systém rozpoznávání dopravních značek (zkráceně TSR), i když někteří výrobci dávají svým vynálezům jiná, exotičtější jména.

Účel systému
Řidiči si z různých důvodů někdy jednoduše nevšimnou dopravní značky stojící na kraji vozovky. Únava, rušivý zvuk nebo obraz za oknem, povětrnostní podmínky nebo jasné, oslepující světlo protijedoucího auta mohou způsobit, že přehlédnete značku obsahující důležité informace. Aby k takové situaci nedošlo, byl vyvinut speciální systém, který rozpozná dopravní značku a informuje o ní řidiče formou zvukového signálu a obrazu na obrazovce ve voze. Audi, BMW, Mercedes, Volkswagen a další velké automobilky považují za nutné vybavit své vozy takovými novinkami.
Tento systém samozřejmě ještě není dokonalý. Vzhledem k množství dopravních značek a jejich rozdílům v různých zemích vývojáři „naučili“ svůj vynález rozpoznávat značky, které nesou opravdu důležité informace. Patří sem:
- značky omezující rychlost;
- zákaz předjíždění;
- jednosměrná dopravní značka;
- Značka „Zákaz vstupu“ (probíhá testování).
Jak funguje systém rozpoznávání?
Samotné zařízení má malou sadu komponent, která zahrnuje videokameru vybavenou infračerveným senzorem pro tmavé hodiny, řídicí jednotku a samostatnou obrazovku.
Videokamera je instalována mezi čelním sklem automobilu a zpětným zrcátkem, i když někdy může být namontována do bočních zrcátek. Pokrývá prostor vpravo a nahoře, kde jsou umístěny dopravní značky, a přenáší obraz do řídící jednotky. Analyzuje data z videokamery podle následujícího schématu:
![]()
dochází k rozpoznání tvaru, barvy a nápisů dopravní značky;
![]()
analyzují se údaje o vozidle, především rychlost;
![]()
jsou porovnány informace o dopravních značkách a skutečné výsledky vozu;
![]()
Řidič je informován na obrazovce nebo zvukovým signálem.
Obraz obvykle postupně mizí z obrazovky, dokud se neobjeví další dopravní značka a zvukový signál se nezachová. Někdy rozpoznávací systém používá nejen data z videokamer, ale také elektronické mapy oblasti s vyznačenými značkami.
Displej zařízení je umístěn v blízkosti rychloměru, ale již existuje vývoj, který umožňuje promítat výsledky přímo na čelní sklo.

Přirozeně je příliš brzy spoléhat se na takové nové produkty, protože ve fungování zařízení existují určité nedokonalosti. Ve správném vyhodnocení situace na silnici mu mohou bránit povětrnostní podmínky, měnící se osvětlení a auto zaparkované na kraji vozovky. Proto je třeba takové zařízení prozatím považovat za dalšího asistenta, který upozorňuje na dopravní značky umístěné v jízdním pruhu.