Kears+Opencv实现简单人脸识别


Posted in Python onAugust 28, 2019

写在前面:这篇文章也是借鉴了一些前辈的代码和思路写的,代码有些也是复用了别人的。

先说下思路:

1.首先利用Opencv检测出人脸的区域 

2.在成功的检测出人脸区域后,将识别出的人脸区域截取成图片,储存起来,用作后续的训练数据。

3.在获取到了足够多的数据后,搭建CNN网络进行训练。

5.训练完成后,将模型存储起来。 6.在利用Opencv实时读取视频流,将检测出人脸的区域变成图片放入模型中进行预测。

以上就是这个项目的一个基本的思路了。

1.利用Opencv检测人脸的代码如下,这个代码在Opencv的官方文档中也有,最重要的是加载的xml文件,因为这个xml文件中是保存这已经训练好的人脸检测模型。

import cv2
 
def identify_face(window_name, camera_idx):
  cv2.namedWindow(window_name)
 
  # 视频来源,可以来自一段已存好的视频,也可以直接来自USB摄像头
  cap = cv2.VideoCapture(camera_idx)
 
  # 告诉OpenCV使用人脸识别分类器
  classfier = cv2.CascadeClassifier("haarcascade_frontalface_alt2.xml")
 
  # 识别出人脸后要画的边框的颜色,RGB格式
  color = (0, 255, 0)
 
  while cap.isOpened(): # 是否初始化摄像头设备
    ok, frame = cap.read() # 读取一帧数据
    if not ok:
      break
 
    # 将当前帧转换成灰度图像
    grey = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
 
 
    # 人脸检测,1.2和4分别为图片缩放比例和需要检测的有效点数
    faceRects = classfier.detectMultiScale(grey, scaleFactor=1.2, minNeighbors=4, minSize=(32, 32))
    if len(faceRects) > 0: # 大于0则检测到人脸
      for faceRect in faceRects: # 单独框出每一张人脸
        x, y, w, h = faceRect  # 获得人脸的左上角对应坐标,及宽度和高度
        cv2.rectangle(frame, (x - 10, y - 10), (x + w + 10, y + h + 10), color, 2)
 
    # 显示图像
    cv2.imshow(window_name, frame)
    c = cv2.waitKey(10)
    if c & 0xFF == ord('q'):
      break
 
  # 释放摄像头并销毁所有窗口
  cap.release()
  cv2.destroyAllWindows()
 
 
if __name__ == '__main__':
  identify_face("identify face", 0)

2.在检测出人脸区域后,将人脸区域截取成图片保存下来

import cv2
from threading import Thread
 
 
 
def identify_face_and_store_face_image(window_name, camera_idx):
  cv2.namedWindow(window_name)
 
  # 视频来源,可以来自一段已存好的视频,也可以直接来自USB摄像头
  cap = cv2.VideoCapture(camera_idx)
 
  # 告诉OpenCV使用人脸识别分类器
  classfier = cv2.CascadeClassifier("haarcascade_frontalface_alt2.xml")
 
  # 识别出人脸后要画的边框的颜色,RGB格式
  color = (0, 255, 0)
 
 
  # 保存图片的索引
  num = 0
  while cap.isOpened(): # 是否初始化摄像头设备
    ok, frame = cap.read() # 读取一帧数据
    if not ok:
      break
 
    # 将当前帧转换成灰度图像
    grey = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
 
 
    # 人脸检测,1.2和2分别为图片缩放比例和需要检测的有效点数
    faceRects = classfier.detectMultiScale(grey, scaleFactor=1.2, minNeighbors=4, minSize=(32, 32))
    if len(faceRects) > 0: # 大于0则检测到人脸
      for faceRect in faceRects: # 单独框出每一张人脸
        x, y, w, h = faceRect  # 获得人脸的左上角对应坐标,及宽度和高度
 
        cv2.rectangle(frame, (x - 10, y - 10), (x + w + 10, y + h + 10), color, 2)
 
        # store_face_image(frame, h, num, w, x, y)
        # 开启一个线程去存储人脸图片
        t = Thread(target=store_face_image, args=(frame, h, num, w, x, y, ))
        t.start()
 
 
        # 显示捕捉了多少张人脸照片
        font = cv2.FONT_HERSHEY_SIMPLEX # 字体
        cv2.putText(frame, ('num %d' % num), (x + 30, y + 30), font, 1, (255, 0, 255), 2)
 
        num += 1
        if num <= 1000: # 保存1000张图片后就退出
          break
 
 
    if num >= 1000:
      break
 
    # 显示图像
    cv2.imshow(window_name, frame)
    c = cv2.waitKey(10)
    if c & 0xFF == ord('q'):
      break
 
  # 释放摄像头并销毁所有窗口
  cap.release()
  cv2.destroyAllWindows()
 
 
def store_face_image(frame, h, num, w, x, y):
  # 将当前帧保存为图片
  img_name = '%s/%d.jpg' % (r'face_image', num)
  image = frame[y - 10: y + h + 10, x - 10: x + w + 10]
  cv2.imwrite(img_name, image)
 
if __name__ == '__main__':
  identify_face_and_store_face_image("identify face", 0)

3.将保存的数据进行处理,比如打上标签,进行归一化等等,下列代码是load_datasets.py文件中的

import os
import sys
import numpy as np
import cv2
 
IMAGE_SIZE = 64
 
 
# 按照指定图像大小调整尺寸
def resize_image(image, height=IMAGE_SIZE, width=IMAGE_SIZE):
  top, bottom, left, right = (0, 0, 0, 0)
 
  # 获取图像尺寸
  h, w, _ = image.shape
 
  # 对于长宽不相等的图片,找到最长的一边
  longest_edge = max(h, w)
 
  # 计算短边需要增加多上像素宽度使其与长边等长
  if h < longest_edge:
    dh = longest_edge - h
    top = dh // 2
    bottom = dh - top
  elif w < longest_edge:
    dw = longest_edge - w
    left = dw // 2
    right = dw - left
  else:
    pass
 
  # RGB颜色
  BLACK = [0, 0, 0]
 
  # 给图像增加边界,是图片长、宽等长,cv2.BORDER_CONSTANT指定边界颜色由value指定
  constant = cv2.copyMakeBorder(image, top, bottom, left, right, cv2.BORDER_CONSTANT, value=BLACK)
 
  # 调整图像大小并返回
  return cv2.resize(constant, (height, width))
 
 
# 读取训练数据
images = []
labels = []
 
 
def read_path(path_name):
  for dir_item in os.listdir(path_name):
    # 从初始路径开始叠加,合并成可识别的操作路径
    full_path = os.path.abspath(os.path.join(path_name, dir_item))
 
    if os.path.isdir(full_path): # 如果是文件夹,继续递归调用
      read_path(full_path)
    else: # 文件
      if dir_item.endswith('.jpg'):
        image = cv2.imread(full_path)
        image = resize_image(image, IMAGE_SIZE, IMAGE_SIZE)
 
        # 放开这个代码,可以看到resize_image()函数的实际调用效果
        # cv2.imwrite('1.jpg', image)
 
        images.append(image)
        labels.append(path_name)
 
  return images, labels
 
 
# 从指定路径读取训练数据
def load_dataset(path_name):
  images, labels = read_path(path_name)
 
  # 将输入的所有图片转成四维数组,尺寸为(图片数量*IMAGE_SIZE*IMAGE_SIZE*3)
  # 共587张图片,IMAGE_SIZE为64,故对我来说尺寸为587 * 64 * 64 * 3
  # 图片为64 * 64像素,一个像素3个颜色值(RGB)
  images = np.array(images)
  print(images.shape)
 
  # 标注数据,'my_face_image'文件夹下都是我的脸部图像,全部指定为0,你可以在获取他人的脸部图片比如说同学的,指定为1,
  labels = np.array([0 if label.endswith('my_face_image') else 1 for label in labels])
 
  return images, labels
 
 
if __name__ == '__main__':
  if len(sys.argv) != 1:
    print("Usage:%s path_name\r\n" % (sys.argv[0]))
  else:
    images, labels = load_dataset("face_image")

4.搭建模型,进行训练

import random
 
import numpy as np
from sklearn.model_selection import train_test_split
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, Flatten
from keras.layers import Convolution2D, MaxPooling2D
from keras.optimizers import SGD
from keras.utils import np_utils
from keras.models import load_model
from keras import backend as K
 
from load_datasets import load_dataset, resize_image, IMAGE_SIZE
 
 
class Dataset:
  def __init__(self, path_name):
    # 训练集
    self.train_images = None
    self.train_labels = None
 
    # 验证集
    self.valid_images = None
    self.valid_labels = None
 
    # 测试集
    self.test_images = None
    self.test_labels = None
 
    # 数据集加载路径
    self.path_name = path_name
 
    # 当前库采用的维度顺序
    self.input_shape = None
 
  # 加载数据集并按照交叉验证的原则划分数据集并进行相关预处理工作
  def load(self, img_rows=IMAGE_SIZE, img_cols=IMAGE_SIZE,
       img_channels=3, nb_classes=2):
    # 加载数据集到内存
    images, labels = load_dataset(self.path_name)
 
    train_images, valid_images, train_labels, valid_labels = train_test_split(images, labels, test_size=0.3,
                                         random_state=random.randint(0, 100))
    _, test_images, _, test_labels = train_test_split(images, labels, test_size=0.5,
                             random_state=random.randint(0, 100))
 
    # 当前的维度顺序如果为'th',则输入图片数据时的顺序为:channels,rows,cols,否则:rows,cols,channels
    # 这部分代码就是根据keras库要求的维度顺序重组训练数据集
    if K.image_dim_ordering() == 'th':
      train_images = train_images.reshape(train_images.shape[0], img_channels, img_rows, img_cols)
      valid_images = valid_images.reshape(valid_images.shape[0], img_channels, img_rows, img_cols)
      test_images = test_images.reshape(test_images.shape[0], img_channels, img_rows, img_cols)
      self.input_shape = (img_channels, img_rows, img_cols)
    else:
      train_images = train_images.reshape(train_images.shape[0], img_rows, img_cols, img_channels)
      valid_images = valid_images.reshape(valid_images.shape[0], img_rows, img_cols, img_channels)
      test_images = test_images.reshape(test_images.shape[0], img_rows, img_cols, img_channels)
      self.input_shape = (img_rows, img_cols, img_channels)
 
      # 输出训练集、验证集、测试集的数量
      print(train_images.shape[0], 'train samples')
      print(valid_images.shape[0], 'valid samples')
      print(test_images.shape[0], 'test samples')
 
      # 我们的模型使用categorical_crossentropy作为损失函数,因此需要根据类别数量nb_classes将
      # 类别标签进行one-hot编码使其向量化,在这里我们的类别只有两种,经过转化后标签数据变为二维
      train_labels = np_utils.to_categorical(train_labels, nb_classes)
      valid_labels = np_utils.to_categorical(valid_labels, nb_classes)
      test_labels = np_utils.to_categorical(test_labels, nb_classes)
 
      # 像素数据浮点化以便归一化
      train_images = train_images.astype('float32')
      valid_images = valid_images.astype('float32')
      test_images = test_images.astype('float32')
 
      # 将其归一化,图像的各像素值归一化到0~1区间
      train_images /= 255
      valid_images /= 255
      test_images /= 255
 
      self.train_images = train_images
      self.valid_images = valid_images
      self.test_images = test_images
      self.train_labels = train_labels
      self.valid_labels = valid_labels
      self.test_labels = test_labels
 
 
# CNN网络模型类
class Model:
  def __init__(self):
    self.model = None
 
    # 建立模型
 
  def build_model(self, dataset, nb_classes=2):
    # 构建一个空的网络模型,它是一个线性堆叠模型,各神经网络层会被顺序添加,专业名称为序贯模型或线性堆叠模型
    self.model = Sequential()
 
    # 以下代码将顺序添加CNN网络需要的各层,一个add就是一个网络层
    self.model.add(Convolution2D(32, 3, 3, border_mode='same',
                   input_shape=dataset.input_shape)) # 1 2维卷积层
    self.model.add(Activation('relu')) # 2 激活函数层
 
    self.model.add(Convolution2D(32, 3, 3)) # 3 2维卷积层
    self.model.add(Activation('relu')) # 4 激活函数层
 
    self.model.add(MaxPooling2D(pool_size=(2, 2))) # 5 池化层
    self.model.add(Dropout(0.25)) # 6 Dropout层
 
    self.model.add(Convolution2D(64, 3, 3, border_mode='same')) # 7 2维卷积层
    self.model.add(Activation('relu')) # 8 激活函数层
 
    self.model.add(Convolution2D(64, 3, 3)) # 9 2维卷积层
    self.model.add(Activation('relu')) # 10 激活函数层
 
    self.model.add(MaxPooling2D(pool_size=(2, 2))) # 11 池化层
    self.model.add(Dropout(0.25)) # 12 Dropout层
 
    self.model.add(Flatten()) # 13 Flatten层
    self.model.add(Dense(512)) # 14 Dense层,又被称作全连接层
    self.model.add(Activation('relu')) # 15 激活函数层
    self.model.add(Dropout(0.5)) # 16 Dropout层
    self.model.add(Dense(nb_classes)) # 17 Dense层
    self.model.add(Activation('softmax')) # 18 分类层,输出最终结果
 
    # 输出模型概况
    self.model.summary()
 
  # 训练模型
  def train(self, dataset, batch_size=20, nb_epoch=10, data_augmentation=True):
    sgd = SGD(lr=0.01, decay=1e-6,
         momentum=0.9, nesterov=True) # 采用SGD+momentum的优化器进行训练,首先生成一个优化器对象
    self.model.compile(loss='categorical_crossentropy',
              optimizer=sgd,
              metrics=['accuracy']) # 完成实际的模型配置工作
 
    # 不使用数据提升,所谓的提升就是从我们提供的训练数据中利用旋转、翻转、加噪声等方法创造新的
    # 训练数据,有意识的提升训练数据规模,增加模型训练量
    if not data_augmentation:
      self.model.fit(dataset.train_images,
              dataset.train_labels,
              batch_size=batch_size,
              nb_epoch=nb_epoch,
              validation_data=(dataset.valid_images, dataset.valid_labels),
              shuffle=True)
    # 使用实时数据提升
    else:
      # 定义数据生成器用于数据提升,其返回一个生成器对象datagen,datagen每被调用一
      # 次其生成一组数据(顺序生成),节省内存,其实就是python的数据生成器
      datagen = ImageDataGenerator(
        featurewise_center=False, # 是否使输入数据去中心化(均值为0),
        samplewise_center=False, # 是否使输入数据的每个样本均值为0
        featurewise_std_normalization=False, # 是否数据标准化(输入数据除以数据集的标准差)
        samplewise_std_normalization=False, # 是否将每个样本数据除以自身的标准差
        zca_whitening=False, # 是否对输入数据施以ZCA白化
        rotation_range=20, # 数据提升时图片随机转动的角度(范围为0~180)
        width_shift_range=0.2, # 数据提升时图片水平偏移的幅度(单位为图片宽度的占比,0~1之间的浮点数)
        height_shift_range=0.2, # 同上,只不过这里是垂直
        horizontal_flip=True, # 是否进行随机水平翻转
        vertical_flip=False) # 是否进行随机垂直翻转
 
      # 计算整个训练样本集的数量以用于特征值归一化、ZCA白化等处理
      datagen.fit(dataset.train_images)
 
      # 利用生成器开始训练模型
      self.model.fit_generator(datagen.flow(dataset.train_images, dataset.train_labels,
                         batch_size=batch_size),
                   samples_per_epoch=dataset.train_images.shape[0],
                   nb_epoch=nb_epoch,
                   validation_data=(dataset.valid_images, dataset.valid_labels))
 
  MODEL_PATH = 'zhuhaipeng.face.model.h5'
 
  def save_model(self, file_path=MODEL_PATH):
    self.model.save(file_path)
 
  def load_model(self, file_path=MODEL_PATH):
    self.model = load_model(file_path)
 
  def evaluate(self, dataset):
    score = self.model.evaluate(dataset.test_images, dataset.test_labels, verbose=1)
    print("%s: %.2f%%" % (self.model.metrics_names[1], score[1] * 100))
 
  # 识别人脸
  def face_predict(self, image):
    # 依然是根据后端系统确定维度顺序
    if K.image_dim_ordering() == 'th' and image.shape != (1, 3, IMAGE_SIZE, IMAGE_SIZE):
      image = resize_image(image) # 尺寸必须与训练集一致都应该是IMAGE_SIZE x IMAGE_SIZE
      image = image.reshape((1, 3, IMAGE_SIZE, IMAGE_SIZE)) # 与模型训练不同,这次只是针对1张图片进行预测
    elif K.image_dim_ordering() == 'tf' and image.shape != (1, IMAGE_SIZE, IMAGE_SIZE, 3):
      image = resize_image(image)
      image = image.reshape((1, IMAGE_SIZE, IMAGE_SIZE, 3))
 
    # 浮点并归一化
    image = image.astype('float32')
    image /= 255
 
    # 给出输入属于各个类别的概率,我们是二值类别,则该函数会给出输入图像属于0和1的概率各为多少
    result = self.model.predict_proba(image)
    print('result:', result)
 
    # 给出类别预测:0或者1
    result = self.model.predict_classes(image)
 
    # 返回类别预测结果
    return result[0]
 
 
if __name__ == '__main__': # 训练模型
  dataset = Dataset('face_image')
  dataset.load()
 
  model = Model()
  model.build_model(dataset)
 
  # 测试训练函数的代码
  model.train(dataset)
 
if __name__ == '__main__': # 训练并保存模型
  dataset = Dataset('face_image')
  dataset.load()
 
  model = Model()
  model.build_model(dataset)
  model.train(dataset)
  model.save_model(file_path='model/zhuhaipeng.face.model.h5')
 
if __name__ == '__main__':  # 读取模型进行评估
  dataset = Dataset('face_image')
  dataset.load()
 
  # 评估模型
  model = Model()
  model.load_model(file_path='model/zhuhaipeng.face.model.h5')
  model.evaluate(dataset)

5.训练好模型后,使用Opencv实时读取视频流检测人脸位置,再将人脸放入模型中进行预测

# -*- coding: utf-8 -*-
 
import cv2
import sys
from face_train import Model
 
if __name__ == '__main__':
  if len(sys.argv) != 1:
    print("Usage:%s camera_id\r\n" % (sys.argv[0]))
    sys.exit(0)
 
  # 加载模型
  model = Model()
  model.load_model(file_path='model/zhuhaipeng.face.model.h5')
 
  # 框住人脸的矩形边框颜色
  color = (0, 255, 0)
 
  # 捕获指定摄像头的实时视频流
  cap = cv2.VideoCapture(0)
 
  # 人脸识别分类器本地存储路径
  cascade_path = "haarcascade_frontalface_alt2.xml"
 
  # 循环检测识别人脸
  while True:
    ret, frame = cap.read() # 读取一帧视频
 
    if ret is True:
 
      # 图像灰化,降低计算复杂度
      frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    else:
      continue
    # 使用人脸识别分类器,读入分类器
    cascade = cv2.CascadeClassifier(cascade_path)
 
    # 利用分类器识别出哪个区域为人脸
    faceRects = cascade.detectMultiScale(frame_gray, scaleFactor=1.2, minNeighbors=3, minSize=(32, 32))
    if len(faceRects) > 0:
      for faceRect in faceRects:
        x, y, w, h = faceRect
 
        # 截取脸部图像提交给模型识别这是谁
        image = frame[y - 10: y + h + 10, x - 10: x + w + 10]
        faceID = model.face_predict(image)
 
        # 如果是“我”
        if faceID == 0:
          cv2.rectangle(frame, (x - 10, y - 10), (x + w + 10, y + h + 10), color, thickness=2)
 
          # 文字提示是谁
          cv2.putText(frame, 'zhuhaipeng',
                (x + 30, y + 30), # 坐标
                cv2.FONT_HERSHEY_SIMPLEX, # 字体
                1, # 字号
                (255, 0, 255), # 颜色
                2) # 字的线宽
        else: # 如果不是我
          # 文字提示未知
          cv2.putText(frame, 'Unknown people ',
                (x + 30, y + 30), # 坐标
                cv2.FONT_HERSHEY_SIMPLEX, # 字体
                1, # 字号
                (255, 0, 255), # 颜色
                2) # 字的线宽
 
    cv2.imshow("identify me", frame)
 
    # 等待10毫秒看是否有按键输入
    k = cv2.waitKey(10)
    # 如果输入q则退出循环
    if k & 0xFF == ord('q'):
      break
 
  # 释放摄像头并销毁所有窗口
  cap.release()
  cv2.destroyAllWindows()

到此一个简单的人脸识别小项目就完成了,在这个项目中,只是简单的二分类,可以在此基础上进行扩展为多分类,如果识别的准确率低的话,可以尝试更改网络架构,或者对数据进行预处理等等,如果大家有兴趣改进的话,可以尝试一下。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
详解Python的Django框架中Manager方法的使用
Jul 21 Python
python开发之tkinter实现图形随鼠标移动的方法
Nov 11 Python
Python的string模块中的Template类字符串模板用法
Jun 27 Python
Python实现批量更换指定目录下文件扩展名的方法
Sep 19 Python
python flask 多对多表查询功能
Jun 25 Python
Python实现的递归神经网络简单示例
Aug 11 Python
python 实现求解字符串集的最长公共前缀方法
Jul 20 Python
python 画三维图像 曲面图和散点图的示例
Dec 29 Python
Python递归实现打印多重列表代码
Feb 27 Python
解决Python中报错TypeError: must be str, not bytes问题
Apr 07 Python
python爬虫判断招聘信息是否存在的实例代码
Nov 20 Python
利用Python将list列表写入文件并读取的方法汇总
Mar 25 Python
解决python 文本过滤和清理问题
Aug 28 #Python
解决Python对齐文本字符串问题
Aug 28 #Python
python+jinja2实现接口数据批量生成工具
Aug 28 #Python
解决Atom安装Hydrogen无法运行python3的问题
Aug 28 #Python
opencv实现简单人脸识别
Feb 19 #Python
Atom Python 配置Python3 解释器的方法
Aug 28 #Python
python聚类算法解决方案(rest接口/mpp数据库/json数据/下载图片及数据)
Aug 28 #Python
You might like
Uncaught exception com_exception with message Failed to create COM object
2012/01/11 PHP
PHP新手用的Insert和Update语句构造类
2012/03/31 PHP
ueditor 1.2.6 使用方法说明
2013/07/24 PHP
php实现高效获取图片尺寸的方法
2014/12/12 PHP
php模拟用户自动在qq空间发表文章的方法
2015/01/07 PHP
php动态生成版权所有信息的方法
2015/03/24 PHP
PHP实现的同步推荐操作API接口案例分析
2016/11/30 PHP
PHP实现压缩图片尺寸并转为jpg格式的方法示例
2018/05/10 PHP
PHP简单验证码功能机制实例详解
2019/03/27 PHP
Laravel创建数据库表结构的例子
2019/10/09 PHP
laravel excel 上传文件保存到本地服务器功能
2019/11/14 PHP
UserData用法总结 lanyu出品
2010/07/01 Javascript
js捕获鼠标右键菜单中的粘帖事件实现代码
2013/04/01 Javascript
JS数组去重与取重的示例代码
2014/01/24 Javascript
jquery选择checked在ie8普通模式下的问题
2014/02/12 Javascript
在JavaScript中操作时间之getYear()方法的使用教程
2015/06/11 Javascript
JS实现网页右侧带动画效果的伸缩窗口代码
2015/10/29 Javascript
深入分析jQuery的ready函数是如何工作的(工作原理)
2015/12/17 Javascript
Javascript 跨域知识详细介绍
2016/10/30 Javascript
详解js产生对象的3种基本方式(工厂模式,构造函数模式,原型模式)
2017/01/09 Javascript
javascript常用的设计模式
2017/02/09 Javascript
老生常谈javascript的面向对象思想
2017/08/22 Javascript
纯js实现图片匀速淡入淡出效果
2017/08/22 Javascript
利用Console来Debug的10个高级技巧汇总
2018/03/26 Javascript
angular组件间传值测试的方法详解
2020/05/07 Javascript
在Django中编写模版节点及注册标签的方法
2015/07/20 Python
Python初学时购物车程序练习实例(推荐)
2017/08/08 Python
python3结合openpyxl库实现excel操作的实例代码
2018/09/11 Python
python+opencv像素的加减和加权操作的实现
2019/07/14 Python
浅谈keras保存模型中的save()和save_weights()区别
2020/05/21 Python
Django serializer优化类视图的实现示例
2020/07/16 Python
python实现图片素描效果
2020/09/26 Python
捷克电器和DJ设备网上商店:Electronic-star
2017/07/18 全球购物
优秀管理者获奖感言
2014/02/17 职场文书
四风问题查摆材料
2014/08/25 职场文书
毕业论文致谢格式模板
2015/05/14 职场文书