Traffic Safety-kun: Reconnaissance des panneaux de signalisation en Python

L'environnement d'exécution de cet article est collaboratif.


** L'objectif de cette fois **

  1. Cette fois, reconnaissez le feu rouge, le feu vert, l'arrêt et le signe d'interdiction d'entrée.
  2. Soyez prudent avec la voix lorsque la lumière rouge, arrêt et aucune entrée.

Tout d'abord, jetez un œil au produit fini téléchargé sur YouTube. Traffic Safety-kun


table des matières

  1. Préparation préalable
  2. Apprentissage profond des panneaux de signalisation
  3. Analysez la vidéo et détectez la lumière rouge, l'arrêt, l'image sans entrée
  4. Mettez l'audio dans le cadre détecté

** 1, préparation préalable ** ① Prenez une vidéo avec votre smartphone à un endroit avec un panneau de signalisation. L'effet d'une qualité d'image élevée est bon. (1920 * 1080, 30FPS dans mon cas) ** Faites attention à la sécurité routière lorsque vous prenez des vidéos! ** ** (2) Créez des voix d'avertissement pour "Arrêt", "Feu rouge" et "Aucune entrée" Je l'ai créé avec gTTS, bien sûr, vous pouvez enregistrer votre propre voix.

makeAudio_Arrêtez.ipynb


from gtts import gTTS #Google Text to Speech
from google import colab

#Monter Google Drive
colab.drive.mount('/content/gdrive')

path="gdrive/My Drive/make_video/"
word="Arrête ça"
tts = gTTS(word,lang='ja') #Provide the string to convert to speech
tts.save(path+'STOP_2.wav') #save the string converted to speech as a .wav file
Audio(path+'STOP_2.wav') 

③ Préparez des images de panneaux de signalisation (feu rouge, feu vert, arrêt, pas d'entrée, ciel bleu). (2, utilisé pour l'apprentissage en profondeur des panneaux de signalisation)

Téléchargez des images à partir de la recherche d'images de Google.

python:1.getImage_STOP.ipynb


#Prendre une image d'un arrêt
!apt-get update
!apt install chromium-chromedriver
!cp /usr/lib/chromium-browser/chromedriver /usr/bin
!pip install selenium

import urllib.request as req
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import time
from selenium.webdriver.common.keys import Keys 

from google import colab
colab.drive.mount('/content/gdrive')

#Lancez le navigateur en mode sans tête et affichez le site Web
options = webdriver.ChromeOptions()
options.add_argument('--headless')
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
driver = webdriver.Chrome('chromedriver',options=options)
driver.implicitly_wait(10)

count=1
tempImageCount=0

#Spécification de l'URL cible
driver.get("https://www.google.com/search?rlz=1C1CAFC_enJP862JP870&biw=1366&bih=657&tbm=isch&sxsrf=ACYBGNSNeQ5IaB9V8b-6pc6q9gOtbrY4Uw%3A1577968008026&sa=1&ei=iOENXoiRAfCSr7wP-8ee0As&q=%E6%AD%A2%E3%81%BE%E3%82%8C%E6%A8%99%E8%AD%98&oq=%E6%AD%A2%E3%81%BE%E3%82%8C%E6%A8%99%E8%AD%98&gs_l=img.3..0l2j0i24l8.144019.154252..155304...3.0..0.429.5395.0j1j5j10j1......0....1..gws-wiz-img.......0i4i37j35i39j0i23j0i4i37i24.zXhLgCDtIBY&ved=0ahUKEwiI9db09OTmAhVwyYsBHfujB7oQ4dUDCAc&uact=5")
time.sleep(3)

while True:
    #acquisition de liste d'images
    image_list = driver.find_elements_by_class_name('rg_ic')
    print(len(image_list))
    
    #ScrollBar en bas
    driver.find_element_by_tag_name('body').send_keys(Keys.END)

    if len(image_list) > tempImageCount:
        tempImageCount = len(image_list)
        print('------------------- go to next page --------------------------')
        try:
            #Afficher le bouton "Afficher plus de résultats"
            driver.find_element_by_id('smb').click()
            print('------------------- click success --------------------------')
        except:
            driver.find_element_by_tag_name('body').send_keys(Keys.END)
            print('------------------- KEY END --------------------------')
    else:
        break

#acquisition de liste d'images
image_list = driver.find_elements_by_class_name('rg_ic')
print(len(image_list))
for image in image_list:
        #Obtenir l'URL de l'image
        image_url = image.get_attribute('src')
        
        #Enregistrer l'image
        try:
            image = req.urlopen(image_url).read()
            with open('gdrive/My Drive/image/Sécurité routière/Arrêtez/'+str(count)+'.jpg',mode='wb') as f:
                f.write(image)
            print('download - {}'.format(count))
            count += 1
        except:
            print('cant open url')

driver.quit()

Choisissons un bon parmi les images acquises. (Autant que possible, 20 ou plus) Bon exemple: (sans arrière-plan) 2.jpg Exemple NG: 205.jpg


** 2, panneau de signalisation Deep Learning **

① Convertir le fichier image au format Numpy

Les données de l'ensemble de données "MNIST" sont un tableau de (28,28) comme indiqué ci-dessous. image.png En imitant ↑, redimensionnez d'abord le fichier image en un carré de 50 * 50 puis convertissez-le au format Numpy. Puisqu'il s'agit d'un mode couleur RVB, ce sera un tableau de (50,50,3).

to_Dat.ipynb


import cv2
import os
from sklearn.model_selection import train_test_split
from PIL import Image
import os,glob
import numpy as np

from google import colab
colab.drive.mount('/content/gdrive')
!ls 'gdrive/My Drive'

#Sélectionnez une catégorie de classification
root_dir = 'gdrive/My Drive/image/Sécurité routière-kun 2/'
train_dir = 'gdrive/My Drive/data/'
groups = ['Lumière verte','une manière','Arrêtez','Entrée interdite','lumière rouge','ciel bleu']
nb_classes = len(groups)
image_size = 50

#Convertir les données d'image au format Numpy
#Lire les données d'image pour chaque dossier
X = []
Y = []
#Puisqu'il y a peu d'images, laissez-les étudier la même image 20 fois. Les humains se souviennent des choses encore et encore, est-ce que Deeplearning est la même chose?
for i in range(0,20,1):
  for idx,group in enumerate(groups):
      image_dir = root_dir + group
      files = glob.glob(image_dir+'/*.jpg')
      for i,f in enumerate(files):
          img = Image.open(f)
          img = img.convert('RGB') #Passer en mode RVB
          img = img.resize((image_size,image_size))#50*Redimensionner à 50
          data = np.asarray(img)
          X.append(data)
          Y.append(idx)
X = np.array(X)
Y = np.array(Y)

X_train,X_test,y_train,y_test = train_test_split(X,Y,random_state=0)
xy = (X_train,X_test,y_train,y_test)
np.save('gdrive/My Drive/data/Sécurité routière-kun 2.npy', xy)
print(X_train.shape[1:])
print('ok',len(Y))

② Apprentissage avec un réseau neuronal Présentant la technique de "Convolution", veuillez vous référer à l'URL suivante. Qu'est-ce qu'un réseau neuronal convolutif? La procédure est également expliquée avec soin Après avoir appliqué un filtre bidimensionnel aux données d'image comme indiqué dans ↑, vous pouvez accentuer les lignes horizontales et verticales, ce qui peut considérablement améliorer le taux de réussite.

deeplearning.ipynb


!pip install keras==2.2.4
import keras

from google import colab
colab.drive.mount('/content/gdrive')
!ls 'gdrive/My Drive'

import numpy as np
from keras.datasets import mnist
from keras.utils import np_utils

#Lire les données enregistrées en cours ①
x_train,x_test,y_train,y_test = np.load('gdrive/My Drive/data/Sécurité routière-kun 2.npy', mmap_mode=None, allow_pickle=True , fix_imports=True, encoding='ASCII')

x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255
num_classes = 10
y_train = np_utils.to_categorical(y_train, num_classes)
y_test = np_utils.to_categorical(y_test, num_classes)

#réseau neuronal
import numpy as np
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras.optimizers import Adam
import time

model = Sequential()
model.add(Conv2D(50, (3, 3), 
          input_shape=(50, 50, 3), activation='relu'))       #Pliage ①
model.add(Conv2D(32, (3, 3), activation='relu'))          #Pliage ②
model.add(MaxPooling2D(pool_size=(2, 2)))                
model.add(Conv2D(64, (3, 3), activation='relu'))         ##Pliage ③
model.add(MaxPooling2D(pool_size=(2, 2)))                
model.add(Dropout(0.25))                                 
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.25))                                 
model.add(Dense(num_classes, activation='softmax'))

model.compile(loss='categorical_crossentropy',
              optimizer=Adam(),
              metrics=['accuracy'])

startTime = time.time()

history = model.fit(x_train, y_train, batch_size=3000, epochs=20,
                    verbose=1, validation_data=(x_test, y_test))

score = model.evaluate(x_test, y_test, verbose=0)
#loss
print('loss:', score[0])
#taux de réussite
print('accuracy:', score[1])
#Temps d'étude
print("Computation time:{0:.3f} sec".format(time.time() - startTime))

#Enregistrer le modèle entraîné
model.save('gdrive/My Drive/model/Sécurité routière.h5')

Le taux de réussite est de 0,98, ce qui est un bon sentiment. loss: 0.11440953898268777 accuracy: 0.9878378378378379 Computation time:46.734 sec


** 3, analyser la vidéo et détecter la lumière rouge, arrêter, trame sans entrée **

① Comment découpez-vous l'image du signe de la photo réelle et l'identifiez-vous avec le modèle formé? 止まれ.jpg

J'ai évoqué ce qui suit. [Python / OpenCV] Détecter les objets en mouvement avec le suivi des couleurs

Obtenez le plus gros blob.ipynb


#Analyse Blob
def analysis_blob(binary_img):
    #Processus d'étiquetage d'image binaire
    label = cv2.connectedComponentsWithStats(binary_img)

    #Extraire les informations sur l'objet blob élément par élément
    n = label[0] - 1
    data = np.delete(label[2], 0, 0)
    center = np.delete(label[3], 0, 0)
    if len(center) <= 0:
        return
    #Index avec la plus grande zone de blob
    max_index = np.argmax(data[:, 4])

    return center[max_index]

Méthode de prédiction.ipynb (les arguments sont le fichier image et les coordonnées)


def predictWithModel(image_file, x_from, y_from, x_to, y_to):
    image_size = 50

    X1 = []
    #garniture
    img_crop = image_file[y_from : y_to, x_from: x_to]
    img_crop = cv2.cvtColor(img_crop, cv2.COLOR_BGR2RGB)
    img_crop = cv2.resize(img_crop, (image_size,image_size))#Changer la taille de l'image
    
    X1.append(img_crop)#Image en tant que vecteur
    X1 = np.array(X1)

    x_test = X1.astype('float32')
    x_test /= 255

    y = model.predict(x_test)  #Prévoir

    wk = y[0, :]
    wk_sort = np.sort(wk)
    wk_sort = wk_sort[::-1]
    max_indx = -1
    max_pcnt = -1
    if float(wk_sort[0]) > 0.9 and np.argmax(wk) != 5 and np.argmax(wk) != 0:
        max_pcnt = float(wk_sort[0])
        max_indx = np.argmax(wk)
        #print(max_indx)
        #print(max_pcnt)
    
    return max_indx, max_pcnt

Méthode d'ajustement des coordonnées.ipynb (la lumière rouge est rectangulaire, stop et aucune entrée n'est carrée)


def adjustSize(height, width, center_x, center_y, div_size, div_size_w, kbn):
    if kbn == 1:
        #Rectangle
        x_from = center_x - div_size_w*3//4
        x_to = x_from + div_size_w
        y_from =  center_y - div_size//2
        y_to = y_from + div_size
    else:
        #carré
        x_from = center_x - div_size//2
        x_to = x_from + div_size
        y_from =  center_y - div_size//2
        y_to = y_from + div_size

    if x_from < 0:
        x_from = 0
    if y_from < 0:
        y_from = 0
    if x_to >= width:
        x_to = width
    if y_to >= height:
        y_to = height
    
    return x_from, y_from, x_to, y_to

Analyse de fichier image.ipynb


def predictImage3(argimg):

    #Chargez l'image.
    height, width, channels = argimg.shape[:3]

    #Recadrage de l'image (le panneau de signalisation se trouve dans la moitié supérieure, analysez donc uniquement la moitié supérieure)
    img = argimg[0:height//2,0:width//2,::]
    #Conversion en espace colorimétrique HSV.
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

    #Extrayez la bordure rouge par binarisation.
    binary = cv2.inRange(hsv, (145, 70, 0), (180, 255, 255))
    if len(binary) <= 0:
        return argimg,-1

    #Éteignez le bruit avec OPENING.
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
    eroded = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)

    #Analyse blob de l'image de masque (acquérir des informations blob de la zone maximale)
    center = analysis_blob(eroded)
    if center is None:
        return argimg,-1

    #Obtenir les coordonnées du centre
    center_x = int(center[0])
    center_y = int(center[1])

    #Premier rectangulaire
    x_from, y_from, x_to, y_to = adjustSize(height, width, center_x, center_y, 60, 100, 1)
    max_indx, max_pcnt = predictWithModel(img, x_from, y_from, x_to, y_to)

    #Place de la recherche
    x_from2, y_from2, x_to2, y_to2 = adjustSize(height, width, center_x, center_y, 50, 100, 0)    max_indx2, max_pcnt2 = predictWithModel(img, x_from2, y_from2, x_to2, y_to2)

    #Rectangle 2 (ajuster la taille)
    x_from3, y_from3, x_to3, y_to3 = adjustSize(height, width, center_x, center_y, 40, 80, 1)
    max_indx3, max_pcnt3 = predictWithModel(img, x_from3, y_from3, x_to3, y_to3)

    pcnt = [max_pcnt, max_pcnt2, max_pcnt3]
    indx = [max_indx, max_indx2, max_indx3]
    max = np.argmax(pcnt)

    max_index = -1

    if indx[max] == 2:
        text="Arrêtez"
    elif indx[max] == 4:
        text="lumière rouge"
    elif indx[max] == 3:
        text="Entrée interdite"
    else:
        text=""

    if indx[max] > 0:
        #Tracez un cercle autour du centre de la goutte maximale sur le cadre
        cv2.circle(argimg, (center_x, center_y), 80, (0, 200, 0),thickness=3, lineType=cv2.LINE_AA)
        fontpath ='gdrive/My Drive/font/MSMINCHO.TTC' #Police de caractère
        font = ImageFont.truetype(fontpath, 128) #taille de police
        img_pil = Image.fromarray(argimg) #8 bits chaque valeur du tableau(1byte)Type entier(0~255)Vers l'image PIL.

        draw = ImageDraw.Draw(img_pil) #Créer une instance de dessin

        position = (center_x, center_y + 100) #Position d'affichage du texte
        draw.text(position, text, font = font , fill = (0,0,255,0) ) #Écrire du texte dans le remplissage de dessin:Couleur BGRA(RGB)
        max_index = indx[max]
        return np.array(img_pil),max_index #Convertir PIL en tableau
    
    return argimg,max_index

Après avoir préparé la méthode ci-dessus, analysez la vidéo préparée

Analyser la vidéo.ipynb


import cv2
from google.colab.patches import cv2_imshow
from PIL import ImageFont, ImageDraw, Image

target_dir = 'gdrive/My Drive/target/Sécurité routière-kun 2/'
files = glob.glob(target_dir+'/src_*.mp4')

target_avi_file = target_dir + "output.avi"
output_file = target_dir + "output.mp4"
#Créez un VideoWriter.
fourcc = cv2.VideoWriter_fourcc(*"DIVX")
writer = cv2.VideoWriter(target_avi_file, fourcc, 30, (1920, 1080))
    
frame_cnt=0

fame_index_result=np.empty((0,2), int)

for i,f in enumerate(files):
    #Créez un VideoCapture.
    cap = cv2.VideoCapture(f)
    temp=np.empty((0,2), int)

    while True:
        #Obtenez image par image.
        ret, frame = cap.read()
        if not ret:
            break  #Si l'acquisition d'images échoue ou si la fin de la vidéo est atteinte
        frame_cnt+=1

        frame,index = predictImage3(frame)
 
        if index > 0:
            temp = np.append(temp, np.array([[frame_cnt,index]]), axis=0)
        writer.write(frame)  #Écrivez un cadre.

    #Panneau de signalisation Enregistrez la première image reconnue (= moment pour insérer la voix)
    index_cnt = [np.count_nonzero(temp[:,1] == 2),np.count_nonzero(temp[:,1] == 3),np.count_nonzero(temp[:,1] == 4)]
    max_index = [2,3,4][np.argmax(index_cnt)]
    fame_index_result = np.append(fame_index_result, np.array([(temp[temp[:,1] == max_index])[0]]), axis=0)

writer.release()
cap.release()

** 4, placez l'audio dans l'image détectée **

Ajouter de l'audio.ipynb


!pip -q install pydub
!apt install libasound2-dev portaudio19-dev libportaudio2 libportaudiocpp0 ffmpeg
!pip install pyaudio
import cv2
import pyaudio
import sys
import time
import wave
import pydub
from pydub import AudioSegment
import moviepy.editor as mp
import datetime

temp_file = target_dir + "temp.mp4"

# Add audio to output video.
clip_output = mp.VideoFileClip(target_avi_file).subclip()
clip_output.write_videofile(temp_file, audio=mp3_file)

cap = cv2.VideoCapture(target_avi_file)
video_frame = cap.get(cv2.CAP_PROP_FRAME_COUNT) #Obtenez le nombre d'images
video_fps = cap.get(cv2.CAP_PROP_FPS)           #Obtenez FPS
video_len_sec = video_frame / video_fps         #Calculer la longueur (secondes)
print(video_len_sec)
video = mp.VideoFileClip(temp_file).subclip(0,video_len_sec)
video.write_videofile(output_file)

mp3_stop_file_2="gdrive/My Drive/mp3/stop_2.wav"
mp3_stop_file_3="gdrive/My Drive/mp3/stop_3.wav"
mp3_stop_file_4="gdrive/My Drive/mp3/stop_4.wav"
videos = np.empty((0), mp.VideoFileClip)

startSec=0
temp_file2 = target_dir + "temp2.mp4"

#Insérer une voix pour chaque image de panneau de signalisation
for idx in range(fame_index_result.shape[0]):

    if  fame_index_result[idx][1] == 2:
        mp3_stop_file = mp3_stop_file_2
    elif  fame_index_result[idx][1] == 3:
        mp3_stop_file = mp3_stop_file_3
    elif  fame_index_result[idx][1] == 4:
        mp3_stop_file = mp3_stop_file_4
    
    base_sound = AudioSegment.from_file(mp3_stop_file)
    length_seconds = base_sound.duration_seconds  #Vérifiez la longueur de la voix

    #Tout d'abord, coupez de 0 au cadre du panneau de signalisation
    video_len_sec_temp = fame_index_result[idx][0] / video_fps
    videos = np.append(videos, np.array([mp.VideoFileClip(temp_file).subclip(startSec,video_len_sec_temp)]), axis=0)

    #Faites correspondre la longueur de l'audio, découpez une vidéo de la même longueur et insérez l'audio
    clip_output = mp.VideoFileClip(temp_file).subclip(video_len_sec_temp, video_len_sec_temp+length_seconds)
    clip_output.write_videofile(temp_file2, audio=mp3_stop_file)
    
    #Vidéo restante
    videos = np.append(videos, np.array([mp.VideoFileClip(temp_file2).subclip()]), axis=0)
    if idx == fame_index_result.shape[0] - 1:
        last_sec =  video_len_sec
    else:
        last_sec = fame_index_result[idx+1][0] / video_fps
    if video_len_sec_temp+length_seconds < last_sec:
        videos = np.append(videos, np.array([mp.VideoFileClip(temp_file).subclip(video_len_sec_temp+length_seconds, last_sec)]), axis=0)
    startSec = last_sec

#Concaténer les vidéos éditées
final_clip = mp.concatenate_videoclips(videos)
final_clip.write_videofile(output_file)

Recommended Posts

Traffic Safety-kun: Reconnaissance des panneaux de signalisation en Python
Reconnaissance vocale avec Python
Jugement d'équivalence d'objet en Python
Implémentation du tri rapide en Python
Reconnaissance des nombres dans les images avec Python
Manipulation des pixels d'image en Python
Diviser timedelta dans la série Python 2.7
Gestion des fichiers JSON en Python
Implémentation du jeu de vie en Python
Affichage de la forme d'onde audio en Python
La loi des nombres en python
Implémentation du tri original en Python
Brouillage réversible d'entiers en Python
Reconnaissance de caractères manuscrits à l'aide de KNN en Python
Python: principes de base de la reconnaissance d'image à l'aide de CNN
Conversion de la chaîne <-> date (date, datetime) en Python
Vérifiez le comportement du destroyer en Python
Pratique d'utilisation de ceci en Python (mauvais)
Théorie générale de la relativité en Python: Introduction
Arborescence de sortie des fichiers en Python
Afficher une liste d'alphabets en Python 3
Comparaison des modules de conversion japonais en Python3
Python: Application de la reconnaissance d'image à l'aide de CNN
Introduction facile de la reconnaissance vocale avec Python
Le résultat de l'installation de python sur Anaconda
Modèles Gang of Four (GoF) en Python
Principes de base pour exécuter NoxPlayer en Python
Remplacement en bloc des chaînes dans les tableaux Python
Projet Euler # 16 "Somme des pouvoirs" en Python
Résumé des méthodes intégrées, etc. de la liste Python
Utilisation d'opérateurs non logiques de ou en python
À la recherche du FizzBuzz le plus rapide en Python
Exemple pratique d'architecture hexagonale en Python
Projet Euler # 17 "Nombre de caractères" en Python
Equation de mouvement à double pendule en python
Débarrassez-vous des images DICOM en Python
Statut de chaque système de traitement Python en 2020
Projet Euler # 1 "Multiple de 3 et 5" en Python
Reconnaissance de scène par quantité de fonctionnalités GIST en Python
Quadtree en Python --2
Python en optimisation
Sortie du nombre de cœurs de processeur en Python
Métaprogrammation avec Python
Dessiner un graphique d'une fonction quadratique en Python
Python 3.3 avec Anaconda
Géocodage en python
SendKeys en Python
[Python] Trier la liste de pathlib.Path dans l'ordre naturel
Recevoir le websocket de l'API kabu station ® en Python
Méta-analyse en Python
Unittest en Python
Projet Euler # 10 "somme des nombres premiers" en Python
Fonctionnement sans assistance des feuilles de calcul Google (etc.) en Python
Récupérer l'appelant d'une fonction en Python
Faites correspondre la distribution de chaque groupe en Python
Afficher le résultat du traitement de la géométrie en Python
Apprentissage de la reconnaissance de formes en vidéo Partie 1 Champ de reconnaissance de formes
Époque en Python
Discord en Python