24、计算机视觉应用:从人脸识别到工业缺陷检测

计算机视觉应用:从人脸识别到工业缺陷检测

1. 人脸识别系统开发

1.1 模型训练参数与执行

在进行人脸识别模型训练时,有几个重要参数需要关注:
- weight_decay :防止权重变得过大。
- max_nrof_epochs :训练应运行的最大轮数。
- epoch_size :每一轮的批次数量。

在Colab中,点击“Run”按钮即可开始训练。根据训练规模和参数的不同,模型训练可能需要数小时甚至数天才能完成。训练成功后,检查点会保存在之前配置的 --model_base_dir 目录中。

1.2 模型评估

在模型运行期间,每一轮和每一批次的损失会打印到控制台,这有助于了解模型的学习情况。理想情况下,损失应该逐渐减小并稳定在接近零的低值。此外,还可以使用TensorBoard评估模型性能,通过以下命令启动TensorBoard仪表盘:

%tensorflow_version 2.x
%load_ext tensorboard
%tensorboard --logdir /content/logs/facenet

1.3 实时人脸识别系统组件

一个完整的人脸识别系统需要三个重要部分:
- 人脸检测模型
- 分类模型
- 图像或视频源

1.4 人脸检测模型选择

可以使用自己训练的人脸检测模型,也可以选择合适的预训练模型。以下是David Sandberg提供的免费预训练模型:
| 模型名称 | 训练数据集 | 下载位置 |
| — | — | — |
| 20180408 - 102900 | CASIA - WebFace | https://drive.google.com/open?id=1R77HmFADxe87GmoLwzfgMu_HY0IhcyBz |
| 20180402 - 114759 | VGGFace2 | https://drive.google.com/open?id=1EXPBSXwTaqrSC0OhUdXNmKSh9qJUQ55 - |

这些模型在Labeled Faces in the Wild (LFW)数据集上进行了评估,具体的模型架构和准确率如下:
| 模型名称 | LFW准确率 | 训练数据集 | 架构 |
| — | — | — | — |
| 20180408 - 102900 | 0.9905 | CASIA - WebFace | Inception ResNet v1 |
| 20180402 - 114759 | 0.9965 | VGGFace2 | Inception ResNet v1 |

在示例中,我们选择使用VGGFace2模型。

1.5 人脸分类器训练

为了识别人脸,我们将构建一个分类器模型,以识别乔治·W·布什、巴拉克·奥巴马和唐纳德·特朗普这三位美国前总统。具体步骤如下:
1. 下载三位总统的一些图像,并按图8 - 6所示的子目录结构进行组织。
2. 在个人电脑或笔记本上开发人脸检测器。在训练分类器之前,需要克隆FaceNet GitHub仓库:

git clone https://github.com/ansarisam/facenet.git
  1. 克隆完成后,设置 PYTHONPATH 环境变量:
export PYTHONPATH=$PYTHONPATH:/home/user/facenet/src

注意, src 目录的路径必须是你计算机上的实际目录路径。

1.6 人脸对齐

使用MTCNN模型进行人脸对齐,由于图像数量较少,使用单进程进行处理。以下是人脸对齐的脚本:

python facenet/src/align/align_dataset_mtcnn.py \
~/presidents/ \
~/presidents_aligned \
--image_size 182 \
--margin 44

在Mac电脑上,图像目录可能包含隐藏文件 .DS_Store ,需要确保从所有包含输入图像的子目录中删除该文件,并且子目录中只包含图像文件。

1.7 分类器训练脚本

完成上述步骤后,即可开始训练分类器,脚本如下:

python facenet/src/classifier.py TRAIN \
~/presidents_aligned \
~/20180402-114759/20180402-114759.pb \
~/presidents_aligned/face_classifier.pkl \
--batch_size 1000 \
--min_nrof_images_per_class 40 \
--nrof_train_images_per_class 35 \
--use_split_dataset

各参数说明如下:
- 第1行调用 classifier.py 并传递参数 TRAIN ,表示要训练分类器。
- 第2行是包含对齐人脸图像的输入基础目录。
- 第3行是预训练人脸检测模型的路径,可以是自己训练保存检查点的目录,也可以是从Google Drive下载的冻结模型( .pb 文件)。
- 第4行是分类器模型保存的路径,这是一个带有 .pkl 扩展名的Pickle文件。

1.8 视频流中的人脸识别

在之前的示例中,我们使用OpenCV的 cv2.VideoCapture() 函数从计算机内置摄像头、USB或IP摄像头读取视频帧。这里将介绍如何使用YouTube作为视频源。

首先,需要安装相关Python库:

pip install pafy
pip install youtube_dl

FaceNet仓库提供了用于视频人脸识别的源代码 real_time_face_recognition.py ,使用以下脚本调用该API:

python real_time_face_recognition.py \
--source youtube \
--url https://www.youtube.com/watch?v=ZYkxVbYxy-c \
--facenet_model_checkpoint ~/20180402-114759/20180402-114759.pb \
--classfier_model ~/presidents_aligned/face_classifier.pkl

各参数说明如下:
- 第2行设置 --source 参数为 youtube ,若省略该参数,默认使用计算机内置摄像头;也可以显式传递 webcam 来使用内置摄像头。
- 第3行是YouTube视频的URL,使用摄像头作为源时不需要该参数。
- 第4行是预训练FaceNet模型的路径,可以是检查点目录或冻结的 .pb 模型。
- 第5行是之前训练的分类器模型的文件路径。

执行上述脚本后,会读取YouTube视频帧并显示识别出的人脸及其边界框。

2. 工业实时缺陷检测系统开发

2.1 工业检测现状与计算机视觉应用

在工业制造中,传统的人工视觉检查存在诸多问题,如主观性强、准确性依赖检查员经验、劳动强度大等。一旦出现机器校准、环境设置或设备故障等问题,整批产品可能出现缺陷,事后人工检查成本高昂。而基于计算机视觉的视觉检查系统可以实时分析视频帧,检测表面缺陷,并在检测到缺陷时实时发出警报,避免生产损失。

2.2 数据集介绍

我们将使用东北大学(NEU)的K. Song和Y. Yan提供的数据集,该数据集包含热轧钢带的六种表面缺陷,分别为:
- 轧入氧化皮(Rolled - in scale,RS):通常在轧制过程中氧化皮轧入金属时产生。
- 斑块(Patches,Pa):可能是不规则的表面斑块。
- 龟裂(Crazing,Cr):表面的裂纹网络。
- 麻面(Pitted surface,PS):由许多小浅孔组成。
- 夹杂(Inclusion,In):嵌入钢中的复合材料。
- 划痕(Scratches,Sc)

数据集包含1800张带标签的灰度图像,每种缺陷类别有300个样本。可以从以下链接免费下载该数据集:https://drive.google.com/file/d/1qrdZlaDi272eA79b0uCwwqPrm2Q_WI3k/view 。下载并解压后,图像位于 IMAGES 子目录, ANNOTATIONS 子目录包含以PASCAL VOC注释格式标注的边界框和缺陷类别的XML文件。

2.3 Google Colab环境设置

在Google Colab中创建一个新的笔记本,例如命名为“Surface Defect Detection v1.0”。由于NEU数据集位于Google Drive上,可以直接将其复制到私人Google Drive中。在Colab上挂载私人Google Drive,解压数据集并设置开发环境,具体步骤如下:

# Code block 1: Mount Google Drive
from google.colab import drive
drive.mount('/content/drive')

# Code block 2: uncompress NEU data
%%shell
ls /content/drive/'My Drive'/NEU-DET.zip
unzip /content/drive/'My Drive'/NEU-DET.zip

# Code block 3: Clone github repository of Tensorflow model project
!git clone https://github.com/ansarisam/models.git

# Code block 4: Install Google protobuf compiler and other dependencies
!sudo apt-get install protobuf-compiler python-pil python-lxml python-tk

# Code block 4: Install dependencies
%%shell
cd models/research
pwd
protoc object_detection/protos/*.proto --python_out=.
pip install --user Cython
pip install --user contextlib2
pip install --user pillow
pip install --user lxml
pip install --user jupyter
pip install --user matplotlib

# Code block 5: Build models project
%%shell
export PYTHONPATH=$PYTHONPATH:/content/models/research:/content/models/research/slim
cd /content/models/research
python setup.py build
python setup.py install

2.4 数据转换为TFRecord格式

为了训练SSD模型,需要将NEU数据集转换为TFRecord格式。以下是TensorFlow代码,用于将图像和注释转换为TFRecord:

# File name: generic_xml_to_tf_record.py
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import hashlib
import io
import logging
import os

from lxml import etree
import PIL.Image
import tensorflow as tf

from object_detection.utils import dataset_util
from object_detection.utils import label_map_util
import random

flags = tf.app.flags
flags.DEFINE_string('data_dir', '', 'Root directory to raw PASCAL VOC dataset.')
flags.DEFINE_string('annotations_dir', 'annotations', '(Relative) path to annotations directory.')
flags.DEFINE_string('image_dir', 'images', '(Relative) path to images directory.')
flags.DEFINE_string('output_path', '', 'Path to output TFRecord')
flags.DEFINE_string('label_map_path', 'data/pascal_label_map.pbtxt', 'Path to label map proto')
flags.DEFINE_boolean('ignore_difficult_instances', False, 'Whether to ignore difficult instances')
FLAGS = flags.FLAGS

# This function generates a list of images for training and validation.
def create_trainval_list(data_dir):
    trainval_filename = os.path.abspath(os.path.join(data_dir,"trainval.txt"))
    trainval = open(os.path.abspath(trainval_filename), "w")
    files = os.listdir(os.path.join(data_dir, FLAGS.image_dir))
    for f in files:
        absfile = os.path.abspath(os.path.join(data_dir, FLAGS.image_dir, f))
        trainval.write(absfile+"\n")
        print(absfile)
    trainval.close()

def dict_to_tf_example(data,
                       dataset_directory,
                       label_map_dict,
                       ignore_difficult_instances=False,
                       image_subdirectory=FLAGS.image_dir):
    """Convert XML derived dict to tf.Example proto.
    Notice that this function normalizes the bounding box coordinates provided
    by the raw data.
    Args:
        data: dict holding PASCAL XML fields for a single image
        dataset_directory: Path to root directory holding PASCAL dataset
        label_map_dict: A map from string label names to integers ids.
        ignore_difficult_instances: Whether to skip difficult instances in the dataset (default: False).
        image_subdirectory: String specifying subdirectory within the PASCAL dataset directory holding the actual image data.
    Returns:
        example: The converted tf.Example.
    Raises:
        ValueError: if the image pointed to by data['filename'] is not a valid JPEG
    """
    filename = data['filename']
    if filename.find(".jpg") < 0:
        filename = filename+".jpg"
    img_path = os.path.join("",image_subdirectory, filename)
    full_path = os.path.join(dataset_directory, img_path)
    with tf.gfile.GFile(full_path, 'rb') as fid:
        encoded_jpg = fid.read()
    encoded_jpg_io = io.BytesIO(encoded_jpg)
    image = PIL.Image.open(encoded_jpg_io)
    if image.format != 'JPEG':
        raise ValueError('Image format not JPEG')
    key = hashlib.sha256(encoded_jpg).hexdigest()
    width = int(data['size']['width'])
    height = int(data['size']['height'])
    xmin = []
    ymin = []
    xmax = []
    ymax = []
    classes = []
    classes_text = []
    truncated = []
    poses = []
    difficult_obj = []
    if 'object' in data:
        for obj in data['object']:
            difficult = bool(int(obj['difficult']))
            if ignore_difficult_instances and difficult:
                continue
            difficult_obj.append(int(difficult))
            xmin.append(float(obj['bndbox']['xmin']) / width)
            ymin.append(float(obj['bndbox']['ymin']) / height)
            xmax.append(float(obj['bndbox']['xmax']) / width)
            ymax.append(float(obj['bndbox']['ymax']) / height)
            classes_text.append(obj['name'].encode('utf8'))
            classes.append(label_map_dict[obj['name']])
            truncated.append(int(obj['truncated']))
            poses.append(obj['pose'].encode('utf8'))
    example = tf.train.Example(features=tf.train.Features(feature={
        'image/height': dataset_util.int64_feature(height),
        'image/width': dataset_util.int64_feature(width),
        'image/filename': dataset_util.bytes_feature(data['filename'].encode('utf8')),
        'image/source_id': dataset_util.bytes_feature(data['filename'].encode('utf8')),
        'image/key/sha256': dataset_util.bytes_feature(key.encode('utf8')),
        'image/encoded': dataset_util.bytes_feature(encoded_jpg),
        'image/format': dataset_util.bytes_feature('jpeg'.encode('utf8')),
        'image/object/bbox/xmin': dataset_util.float_list_feature(xmin),
        'image/object/bbox/xmax': dataset_util.float_list_feature(xmax),
        'image/object/bbox/ymin': dataset_util.float_list_feature(ymin),
        'image/object/bbox/ymax': dataset_util.float_list_feature(ymax),
        'image/object/class/text': dataset_util.bytes_list_feature(classes_text),
        'image/object/class/label': dataset_util.int64_list_feature(classes),
        'image/object/difficult': dataset_util.int64_list_feature(difficult_obj),
        'image/object/truncated': dataset_util.int64_list_feature(truncated),
        'image/object/view': dataset_util.bytes_list_feature(poses),
    }))
    return example

def create_tf(examples_list, annotations_dir, label_map_dict, dataset_type):
    writer = None
    if not os.path.exists(FLAGS.output_path+"/"+dataset_type):
        os.mkdir(FLAGS.output_path+"/"+dataset_type)
    j = 0
    for idx, example in enumerate(examples_list):
        if idx % 100 == 0:
            logging.info('On image %d of %d', idx, len(examples_list))
            print((FLAGS.output_path + "/tf_training_" + str(j) + ".record"))
            writer = tf.python_io.TFRecordWriter(FLAGS.output_path + "/"+dataset_type+"/tf_training_" + str(j) + ".record")
            j = j + 1
        path = os.path.join(annotations_dir, os.path.basename(example).replace(".jpg", '.xml'))
        with tf.gfile.GFile(path, 'r') as fid:
            xml_str = fid.read()
        xml = etree.fromstring(xml_str)
        data = dataset_util.recursive_parse_xml_to_dict(xml)['annotation']
        tf_example = dict_to_tf_example(data, FLAGS.data_dir, label_map_dict, FLAGS.ignore_difficult_instances)
        writer.write(tf_example.SerializeToString())

def main(_):
    data_dir = FLAGS.data_dir
    create_trainval_list(data_dir)
    label_map_dict = label_map_util.get_label_map_dict(FLAGS.label_map_path)
    examples_path = os.path.join(data_dir,'trainval.txt')
    annotations_dir = os.path.join(data_dir, FLAGS.annotations_dir)
    examples_list = dataset_util.read_examples_list(examples_path)
    random.seed(42)
    random.shuffle(examples_list)
    num_examples = len(examples_list)
    num_train = int(0.7 * num_examples)
    train_examples = examples_list[:num_train]
    val_examples = examples_list[num_train:]
    create_tf(train_examples, annotations_dir, label_map_dict, "train")
    create_tf(val_examples, annotations_dir, label_map_dict, "val")

if __name__ == '__main__':
    tf.app.run()

该脚本的主要步骤如下:
1. 调用 create_trainval_list() 函数创建一个包含 IMAGES 子目录中所有图像绝对路径的文本文件。
2. 将图像路径列表按70:30的比例划分为训练集和验证集。
3. 对于训练集中的每个图像,使用 dict_to_tf_example() 函数创建TFRecord,其中包含图像字节、边界框、标注的类别名称和其他元数据,并将其序列化写入文件。根据图像总数和每个TFRecord文件包含的图像数量,会创建多个TFRecord文件。
4. 同样地,为验证集中的每个图像创建TFRecord并序列化到文件。
5. 训练集和验证集分别保存到输出目录下的 train val 子目录中。

如果克隆了Listing 9 - 1中提到的GitHub仓库, generic_xml_to_tf_record.py 文件已经包含在内;如果克隆的是官方TensorFlow模型仓库,则需要将上述代码保存为 generic_xml_to_tf_record.py 并上传到Colab环境(例如 /content 目录)。

2.5 标签映射文件

我们需要一个映射文件将类别索引与类别名称进行映射,该文件包含JSON内容,通常扩展名为 .pbtxt 。以下是手动编写的标签映射文件 steel_label_map.pbtxt

item {
  id: 1
  name: 'rolled-in_scale'
}
item {
  id: 2
  name: 'patches'
}
item {
  id: 3
  name: 'crazing'
}
item {
  id: 4
  name: 'pitted_surface'
}
item {
  id: 5
  name: 'inclusion'
}
item {
  id: 6
  name: 'scratches'
}

将该文件上传到Colab环境的 /content 目录(或其他指定目录,只要在后续脚本中提供正确路径即可)。

2.6 执行数据转换脚本

通过以下脚本执行 generic_xml_to_tf_record.py ,并提供相应参数:
- --label_map_path steel_label_map.pbtxt 的路径。
- --data_dir :包含图像和注释目录的根目录。
- --output_path :生成的TFRecord文件保存的路径,确保该目录存在,若不存在,需要在执行脚本前创建。

综上所述,本文详细介绍了人脸识别和工业实时缺陷检测两个计算机视觉应用的开发过程,包括模型训练、数据处理和系统搭建等方面,为相关领域的开发者提供了实用的参考。

2.7 训练SSD模型

在完成数据转换为TFRecord格式后,我们可以在Google Colab上训练SSD模型。这里我们将应用之前在目标检测中介绍的概念。以下是训练的大致流程:
1. 选择模型配置 :根据任务需求和数据集特点,选择合适的SSD模型配置文件。
2. 修改配置文件 :根据自己的数据集和任务,修改配置文件中的相关参数,如输入数据路径、类别数量等。
3. 启动训练 :在Colab中运行训练命令,开始训练模型。

2.8 模型评估与应用

训练完成后,需要对模型进行评估,以确定其性能。可以使用测试集数据,计算模型的准确率、召回率等指标。评估完成后,就可以将训练好的模型应用到实际的缺陷检测任务中。例如,将模型集成到工业生产线上,实时分析视频帧,检测表面缺陷,并在检测到缺陷时及时发出警报。

2.9 总结工业缺陷检测流程

为了更清晰地展示工业实时缺陷检测系统的开发流程,我们可以用mermaid流程图来表示:

graph LR
    A[获取数据集] --> B[设置Colab环境]
    B --> C[数据转换为TFRecord]
    C --> D[训练SSD模型]
    D --> E[模型评估]
    E --> F[应用模型进行缺陷检测]

3. 总结与展望

3.1 总结

本文详细介绍了两个重要的计算机视觉应用:人脸识别和工业实时缺陷检测。在人脸识别部分,我们从模型训练参数的设置开始,逐步完成了人脸检测模型的选择、分类器的训练、人脸对齐以及视频流中的人脸识别等步骤。在工业实时缺陷检测部分,我们介绍了传统工业检测的问题,引入了计算机视觉的解决方案,并详细阐述了数据集的使用、环境设置、数据转换、模型训练和评估等流程。

3.2 技术点分析

  • 人脸识别 :通过选择合适的预训练模型和训练自己的分类器,结合人脸对齐技术,可以实现高效准确的人脸识别。在视频流处理中,使用第三方库和API可以方便地获取视频源并进行实时识别。
  • 工业缺陷检测 :将数据集转换为TFRecord格式是训练SSD模型的关键步骤,通过合理划分训练集和验证集,可以提高模型的泛化能力。同时,使用标签映射文件可以准确地识别不同的缺陷类别。

3.3 展望未来应用

随着计算机视觉技术的不断发展,这两个应用领域有着广阔的发展前景。在人脸识别方面,可以应用于安防监控、门禁系统、智能考勤等更多场景。在工业缺陷检测方面,可以进一步扩展到更多的工业领域,如汽车制造、电子设备生产等,提高生产效率和产品质量。

3.4 建议与思考

  • 对于开发者 :在实际应用中,需要根据具体需求选择合适的模型和算法,同时注重数据的质量和数量。在训练过程中,合理调整参数,以获得更好的性能。
  • 对于企业 :引入计算机视觉技术可以提高生产效率和质量控制水平,但需要投入一定的资源进行技术研发和人才培养。

总之,计算机视觉在人脸识别和工业缺陷检测等领域有着巨大的潜力,通过不断的研究和实践,我们可以开发出更加高效、准确的应用系统,为社会和经济发展做出贡献。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值