Manual

do

Maker

.

com

Como fazer predição de imagens com Keras e OpenCV

Como fazer predição de imagens com Keras e OpenCV

Fiz diversos testes com o dataset CIFAR-10. Não consegui ótimos resultados, mas consegui acurácia de 70% nas classes de meio de transporte; as demais estão bem precárias, vou fazer mais alguns testes e, se melhorar, coloco outro artigo. Nesse artigo vou compartilhar como fazer predição de imagens com Keras e OpenCV utilizando imagens que baixei através do Google Images.

Classificação de imagens com CIFAR-10

É bem interessante fazer o treinamento, cheguei a um resultado superior a 80% em um dos treinamentos, mas conforme varia (para cima ou para baixo) as predições falham em lugares diferentes; imagens que outrora foram reconhecidas adequadamente, deixam de ser reconhecidas. Por essa razão optei por utilizar um treinamento que fiz com margem de acurácia inferior, mas eficiente para as classes de meios de transporte, batendo  mesmo nos 70%. Claro, utilizei algumas imagens ruins em meio às óbvias e, na classificação de imagens boas, deve chegar a 100% de assertividade.

Se não leu minhas anotações sobre meu aprendizado e aprimoramento, sugiro que comece a partir da configuração do ambiente, descrito nesse artigo.

Por que Keras?

Poderia ter utilizado outra API, mas por acaso escolhi o Keras e acabei gostando bastante. O bom em utilizar algo assim é que além de facilitar a composição dos perceptrons, fica fácil mudar o backend, caso seja necessário migrar para outra plataforma. Antes de experimentar outras opções, vou dedicar por alguns meses um pouco do meu tempo ao aprendizado de deep learning, utilizando o Keras para minhas redes neurais.

Como fazer predição de imagens com Keras e OpenCV?

Essa foi uma dúvida que tive desde o começo. Realmente, não encontrei nada de exemplo, mas acredito que isso aconteceu porque procurei por predição em redes neurais, o que é algo bem isolado. É como pesquisar por "como definir chave primária em banco de dados MySQL". O banco é uma coisa, o sistema que o utilizará é outra. Da mesma forma a rede neural; não importa a integração que for feita, ela tem um propósito independente da interface que a consultará.

Seu ambiente já está preparado para uma rede neural?

Se você ainda não configurou o ambiente, siga para esse artigo. Reproduzir esse tutorial será algo bem divertido!

Poderia ser uma infelicidade, mas graças a Deus meu sistema deu problema e tive que formatar e reconfigurar tudo. Daí tive a oportunidade de corrigir problemas residuais, além de aumentar minha compreensão no processo de configuração do ambiente. Dessa vez não utilizei docker nem virtualenv, queria ter o quanto antes meu ambiente de estudos de volta.

Por que OpenCV?

Daria para ler a imagem sem utilizar OpenCV. Aliás, assim eu estava fazendo; passava a imagem como argumento do script e fazia um loop no shell, mais ou menos assim:

ls barco/*|while read line; do sleep 5;python testingLayers-77.py $line; xdg-open $line;done

Testei cada categoria de forma independente justamente buscando pela acurácia de cada uma. Para ver a imagem relacionada, coloquei nesse loop a execução do visualizador de imagens que corresponde ao mime-type da extensão (xdg-open abre automaticamente) e fiz um delay de 5 segundos entre cada execução da rede neural. Mas ai tinha outro problema; não conseguia perceber o quão rápido era o processo entre cada imagem, da abertura até a predição. Daí entrou o OpenCV.

Código completo

O código que utilizei para fazer predição de imagens com Keras e OpenCV é este abaixo. Ainda tem mais coisas a adicionar e outras a modificar, mas já está bom para a brincadeira inicial.

# 77,14 10 epochs
# 76,57 20 epochs
# 77,50 30 epochs
import time
#import matplotlib.pyplot as plt
import numpy as np
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.layers import Flatten
from keras.constraints import maxnorm
from keras.layers import Activation
from keras.layers.convolutional import Conv2D
from keras.layers.convolutional import MaxPooling2D
from keras.layers.normalization import BatchNormalization
from keras.utils import np_utils
from keras_sequential_ascii import sequential_model_to_ascii_printout
from keras import backend as K
import os

import tensorflow as tf
import multiprocessing as mp

from keras.datasets import cifar10

import sys
#sys.path.append("/usr/local/lib/pyhon2.7/dist-packages/")
import cv2

# fix random seed for reproducibility
seed = 7
np.random.seed(seed)

batch_size  = 32
num_classes = 10
epochz      = 30

global density
density     = 128 #512

(x_train, y_train), (x_test, y_test) = cifar10.load_data()

y_train = np_utils.to_categorical(y_train, num_classes)
y_test = np_utils.to_categorical(y_test, num_classes)
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train  /= 255.0
x_test /= 255.0
#ok

global labelsCifar10
labelsCifar10 = {}

if (os.path.isfile('labels')):
    rfile = open('labels', 'r')
    labelsRaw = rfile.readlines()
    rfile.close()

    for i in range(0,10):
        labelsCifar10[int(labelsRaw[i].split(",")[0])] = str(labelsRaw[i].split(",")[1].replace("\n",""))


def img_to_array(img, image_data_format='default'):
    """Converts numpy image into channels_first/channels_last format
       :param img: Numpy array x has format (height, width, channel) or (channel, height, width)
    """

    if image_data_format == "default":
        image_data_format = K.image_data_format()

    if image_data_format not in ['channels_first', 'channels_last']:
        raise Exception('Unknown image_data_format: ', image_data_format)

    x = np.asarray(img, dtype=K.floatx())

    # colored image
    # (channel, height, width)
    if len(x.shape) == 3:
        if image_data_format == 'channels_first':
            x = x.transpose(2, 0, 1)

    # grayscale
    elif len(x.shape) == 2:
        # already for th format
        x = np.expand_dims(x, axis=0)
        if image_data_format == 'channels_last':
            # (height, width, channel)
            x = x.reshape((x.shape[1], x.shape[2], x.shape[0]))
    # unknown
    else:
        raise Exception('Unsupported image shape: ', x.shape)

    return x

def base_model():
    global density

    model = Sequential()
    model.add(Conv2D(32, (3, 3), padding='same', input_shape=x_train.shape[1:]))
    model.add(Activation('relu'))
    model.add(Conv2D(64,(3, 3)))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    model.add(Dropout(0.2))

    model.add(Conv2D(64, (3, 3), padding='same'))
    model.add(Activation('relu'))
    model.add(Conv2D(128, (3,3)))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    model.add(Dropout(0.2))

    model.add(Flatten())
    model.add(Dense(128))
    model.add(Activation('relu'))
    model.add(Dropout(0.2))
    #ativacao de saida para 10 classes
    model.add(Dense(10))
    model.add(Activation('softmax'))

    #model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
    #para classificacao binaria
    #binary_crossentropy
    #para regressao
    #mse
    #para multiclasse
    #categorical_crossentropy
    model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

    return model

if len(sys.argv) == 1:
    cnn_n = base_model()
    cnn_n.summary()
    cnn = cnn_n.fit(x_train, y_train, batch_size=batch_size, epochs=epochz, validation_data=(x_test,y_test),shuffle=True)
    cnn_n.save_weights("77-img_class-adam-cross_entropy.h5", overwrite=True)

    scores = cnn_n.evaluate(x_test, y_test, verbose=0)
    print("Accuracy: %.2f%%" % (scores[1] * 100))

else:
    if not os.path.isdir(sys.argv[1]):
        print("Directory not found. Exiting...")
        exit(0)
    directory = sys.argv[1]
    files     = os.listdir(directory)

    files = [w.replace("\n","") for w in files]
    #print(files)
    #print(labelsCifar10)

    if len(files) < 1:
        print("There is no files in \'"+directory+"\' directory. Exiting...")
        exit(0)
    cnn_n = base_model()
    cnn_n.load_weights("77-img_class-adam-cross_entropy.h5")

    font = cv2.FONT_HERSHEY_SIMPLEX

    for filename in files:
        img = cv2.imread(directory + "/" +filename)
        img = cv2.resize(img, (32, 32))

        x = img_to_array(np.float32(img) / 255.0)
        x = np.expand_dims(x, axis=0)

        start_t = time.time()
        res = cnn_n.predict(x, verbose=0)
        ####print("took (s)", round(time.time() - start_t,2))
        #print("class index: ", res.argmax())

        detected = res.argmax()
        if labelsCifar10[res.argmax()] in filename:
            print(labelsCifar10[res.argmax()])

            imgRead = cv2.imread(directory + "/" + filename, cv2.IMREAD_COLOR)
            cv2.putText(imgRead, labelsCifar10[res.argmax()], (42, 42), font, 1, (0, 0, 0), 2, cv2.LINE_AA)
            cv2.putText(imgRead, labelsCifar10[res.argmax()], (38, 38), font, 1, (255, 255, 255), 2, cv2.LINE_AA)
            cv2.putText(imgRead, labelsCifar10[res.argmax()], (40, 40), font, 1, (0, 128, 255), 2, cv2.LINE_AA)
        else:
            print("unknown")
            imgRead = cv2.imread(directory + "/" + filename, cv2.IMREAD_COLOR)
            cv2.putText(imgRead, "unknown", (42, 42), font, 1, (0, 0, 0), 2, cv2.LINE_AA)
            cv2.putText(imgRead, "unknown", (38, 38), font, 1, (255, 255, 255), 2, cv2.LINE_AA)
            cv2.putText(imgRead, "unknown", (40, 40), font, 1, (0, 128, 255), 2, cv2.LINE_AA)

        cv2.imshow("CIFAR-10", imgRead)
        cv2.waitKey(0)
        cv2.destroyAllWindows()


Modo de uso

Crie um diretório com imagens misturadas, pertencentes (ou não) às classes do CIFAR-10. Se desejar, crie diretórios com as classes separadas e faça a predição por classe. Para fazer predição de imagens com Keras e OpenCV utilizando esse script, basta chamar o python seguido do programa e passando o nome do diretório como parâmetro:

python predictor.py aviao

Essa linha acima fará apenas a predição do diretório contendo as imagens de avião. As imagens podem ter qualquer nome, isso não importa. Prefira utilizar imagens com extensão .jpg para evitar quaisquer problemas.

Se o script for executado sem parâmetros, um novo treinamento será iniciado. Se esquecer de passar o parâmetro, não se preocupe, pode interromper com Ctrl+C ou com sua IDE de desenvolvimento, porque o model só seria sobrescrito ao final do treinamento.

prediction-cat.webp

Vídeo

Prometi em um dos artigos anteriores que mostraria a predição de imagens com Keras e OpenCV utilizando o dataset CIFAR-10, mas achei melhor esperar até esse momento, com um programa visualmente mais agradável. O vídeo deverá estar pronto algumas horas após a publicação desse artigo, vale a pena conferir. Faço alguns comentários a respeito das predições no vídeo. Visite (e se inscreva no canal) DobitAoByteBrasil no Youtube. Aproveite para clicar no sininho para receber notificações, assim quando o vídeo estiver publicado, você ficará sabendo logo. não deixe de ver o vídeo, uma parte decepciona e outra, surpreende.

Espero que se divirta como eu estou me divertindo. Até a próxima!

Primeira execução?

Se ainda não teve contato com CIFAR-10, o programa irá baixar o dataset automaticamente. Se quiser saber mais do dataset, visite o site oficial. A compilação levará um tempo, mas em uma próxima execução os pesos serão carregados do computador, pois estou salvando o treinamento ao final da execução do model.

Inscreva-se no nosso canal Manual do Maker no YouTube.

Também estamos no Instagram.

Nome do Autor

Djames Suhanko

Autor do blog "Do bit Ao Byte / Manual do Maker".

Viciado em embarcados desde 2006.
LinuxUser 158.760, desde 1997.