利用OpenCV dnn调用keras深度学习模块,实现图像分类

1. 导入库文件

# import the necessary packages
from keras.models import Sequential
from keras.layers.convolutional import Conv2D
from keras.layers.convolutional import MaxPooling2D
from keras.layers.core import Activation
from keras.layers.core import Flatten
from keras.layers.core import Dense
from keras import backend as K

 
# import the necessary packages
from keras.preprocessing.image import ImageDataGenerator
from keras.optimizers import Adam

from keras.preprocessing.image import img_to_array
from keras.utils import to_categorical
from imutils import paths
import matplotlib.pyplot as plt
import numpy as np

import random
import cv2
import os
import sys
sys.path.append('..')

2. 定义常量

 # initialize the number of epochs to train for, initial learning rate,
# and batch size
EPOCHS = 35
INIT_LR = 1e-3
BS = 32
CLASS_NUM = 62
norm_size = 32

3. 读取数据

def load_data(path):
    print("[INFO] loading images...")
    data = []
    labels = []
    # grab the image paths and randomly shuffle them
    imagePaths = sorted(list(paths.list_images(path)))
    random.seed(42)
    random.shuffle(imagePaths)
    # loop over the input images
    for imagePath in imagePaths:
        # load the image, pre-process it, and store it in the data list
        image = cv2.imread(imagePath)
        image = cv2.resize(image, (norm_size, norm_size))
        image = img_to_array(image)
        data.append(image)
 
        # extract the class label from the image path and update the
        # labels list
        label = int(imagePath.split(os.path.sep)[-2])       
        labels.append(label)
    
    # scale the raw pixel intensities to the range [0, 1]
    data = np.array(data, dtype="float") / 255.0
    labels = np.array(labels)
 
    # convert the labels from integers to vectors
    labels = to_categorical(labels, num_classes=CLASS_NUM)                         
    return data,labels

4. 训练并保存模型

def train(aug,trainX,trainY,testX,testY):
    # initialize the model
    print("[INFO] compiling model...")
    model = build(width=norm_size, height=norm_size, depth=3, classes=CLASS_NUM)
    opt = Adam(lr=INIT_LR, decay=INIT_LR / EPOCHS)
    model.compile(loss="categorical_crossentropy", optimizer=opt,
        metrics=["accuracy"])
 
    # train the network
    print("[INFO] training network...")
    H = model.fit_generator(aug.flow(trainX, trainY, batch_size=BS),
        validation_data=(testX, testY), steps_per_epoch=len(trainX) // BS,
        epochs=EPOCHS, verbose=1)
 
    # save the model to disk
    print("[INFO] serializing network...")
    model.save('traffic.h5')

5. 评估训练模型

 # plot the training loss and accuracy
    plt.style.use("ggplot")
    plt.figure()
    N = EPOCHS
    plt.plot(np.arange(0, N), H.history["loss"], label="train_loss")
    plt.plot(np.arange(0, N), H.history["val_loss"], label="val_loss")
    plt.plot(np.arange(0, N), H.history["acc"], label="train_acc")
    plt.plot(np.arange(0, N), H.history["val_acc"], label="val_acc")
    plt.title("Training Loss and Accuracy on traffic-sign classifier")
    plt.xlabel("Epoch #")
    plt.ylabel("Loss/Accuracy")
    plt.legend(loc="lower left")
    plt.show()
    

6. 训练模型主函数

#python train.py --dataset_train ../../traffic-sign/train --dataset_test ../../traffic-sign/test --model traffic_sign.model
if __name__ == '__main__':
    train_file_path = './data/train'
    test_file_path = './data/test'
    trainX,trainY = load_data(train_file_path)
    testX,testY = load_data(test_file_path)
    # construct the image generator for data augmentation
    aug =  ImageDataGenerator(
            rotation_range=15,
            width_shift_range=0.1,
            height_shift_range=0.1,
            horizontal_flip=True,
            vertical_flip=False
        )
    train(aug,trainX,trainY,testX,testY)
    

7. 模型转换,由keras的h5转换为tensorflow的pb模型

import keras
import tensorflow as tf
import os
 
#这个函数参考自网上
def freeze_session(session, keep_var_names=None, output_names=None, clear_devices=True):
    """
    Freezes the state of a session into a pruned computation graph.
    Creates a new computation graph where variable nodes are replaced by
    constants taking their current value in the session. The new graph will be
    pruned so subgraphs that are not necessary to compute the requested
    outputs are removed.
    @param session The TensorFlow session to be frozen.
    @param keep_var_names A list of variable names that should not be frozen,
                          or None to freeze all the variables in the graph.
    @param output_names Names of the relevant graph outputs.
    @param clear_devices Remove the device directives from the graph for better portability.
    @return The frozen graph definition.
    """
    graph = session.graph
    with graph.as_default():
        freeze_var_names = list(set(v.op.name for v in tf.global_variables()).difference(keep_var_names or []))
        output_names = output_names or []
        output_names += [v.op.name for v in tf.global_variables()]
        input_graph_def = graph.as_graph_def()
        if clear_devices:
            for node in input_graph_def.node:
                node.device = ''
        frozen_graph = tf.graph_util.convert_variables_to_constants(
            session, input_graph_def, output_names, freeze_var_names)
        return frozen_graph
 
 
if __name__ == '__main__':
    input_path = './'
    #keras训练保存的h5文件
    input_file = 'traffic.h5'
    weight_file_path = os.path.join(input_path, input_file)
    output_graph_name = weight_file_path[:-3] + '.pb'
 
    #  加载模型
    keras.backend.set_learning_phase(0)
    h5_model = keras.models.load_model(weight_file_path)
    frozen_graph = freeze_session(keras.backend.get_session(), output_names=[out.op.name for out in h5_model.outputs])
    tf.train.write_graph(frozen_graph, input_path, output_graph_name, as_text=False)
    print('Finished')
 
#    import cv2
#    model = cv2.dnn.readNetFromTensorflow("traffic.pb")
#    print('Load')
    
    
    

8. 预测模型,通过keras的loadModel实现

# -*- coding: utf-8 -*-
"""
Created on Mon Aug 24 10:08:04 2020

@author: Yonghong Li
"""


# import the necessary packages
from keras.preprocessing.image import img_to_array
from keras.models import load_model
import numpy as np
import argparse
import imutils
import cv2
 
norm_size = 32
 
    
def predict():
    # load the trained convolutional neural network
    print("[INFO] loading network...")
    model = load_model('traffic.h5')
    
    #load the image
    image = cv2.imread('E:/python learn/TrafficClassify/data/test/00058/00413_00000.png')
    orig = image.copy()
     
    # pre-process the image for classification
    image = cv2.resize(image, (norm_size, norm_size))
    image = image.astype("float") / 255.0
    image = img_to_array(image)
    image = np.expand_dims(image, axis=0)
     
    # classify the input image
    result = model.predict(image)[0]
    print (result)
    
    
    proba = np.max(result)
    print(proba)
    
    label = str(np.where(result==proba)[0])
    label = "{}: {:.2f}%".format(label, proba * 100)
    print(label)
    
    if True:   
        # draw the label on the image
        output = imutils.resize(orig, width=400)
        cv2.putText(output, label, (10, 25),cv2.FONT_HERSHEY_SIMPLEX,
            0.7, (0, 255, 0), 2)       
        # show the output image
        cv2.imshow("Output", output)
        cv2.waitKey(0)
 
 
#python predict.py --model traffic_sign.model -i ../2.png -s
if __name__ == '__main__':
    predict()

9. 预测模型,通过OpenCV dnn 加载

# -*- coding: utf-8 -*-
"""
Created on Sat Aug 29 15:57:15 2020

@author: Yonghong Li
"""


import cv2
import imutils
import numpy as np

norm_size = 32

def predict():
    # load the trained convolutional neural network
    print("[INFO] loading network...")
  
    net = cv2.dnn.readNetFromTensorflow('traffic.pb')

    
    #load the image
    image = cv2.imread('E:/python learn/TrafficClassify/data/test/00058/00413_00000.png')
    orig = image.copy()
     
    img_tensor =  cv2.dnn.blobFromImage(image, 1 / 255.0, (norm_size, norm_size), swapRB=True, crop=False)             
    net.setInput(img_tensor)
    #ln = net.getUnconnectedOutLayersNames()
    result = net.forward()
    print(result)
#    proba = np.max(result)
#    print(proba)
#    label = str(np.where(result==proba)[2])
#
#    print(label)
#
#    label = "{}: {:.2f}%".format(label, proba * 100)
#    print(label)     
##    # classify the input image
#  
   
    min_val,max_val,min_indx,max_indx=cv2.minMaxLoc(result)
    print(min_val,max_val,min_indx,max_indx)
    label = "{}: {:.2f}%".format(max_indx, max_val * 100)
##    
    if True:   
        # draw the label on the image
        output = imutils.resize(orig, width=400)
        cv2.putText(output, label, (10, 25),cv2.FONT_HERSHEY_SIMPLEX,
            0.7, (0, 255, 0), 2)       
#        # show the output image
        cv2.imshow("Output", output)
        cv2.waitKey(0)

if __name__ == '__main__':
    predict()

10. 通过OpenCV dnn加载深度学习模块,在传统的C++代码上实现了深度学习,能够根据输入的图像实现图像分类,完整代码 https://download.csdn.net/download/mr_liyonghong/12785394

你可能感兴趣的:(深度学习,深度学习,人工智能,图像分类,OpenCV,dnn,keras)