前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >太强了,竟然可以根据指纹图像预测性别!

太强了,竟然可以根据指纹图像预测性别!

作者头像
小白学视觉
发布2020-08-24 10:08:59
6410
发布2020-08-24 10:08:59
举报

重磅干货,第一时间送达

在进入神经网络世界之前,让我们先谈一谈指纹?众所周知,没有两个人具有相同的指纹,但是我们可以建立一个CNN模型来从指纹图像中预测性别吗?让我们看看……

在本文中,我们将创建一个可以根据指纹预测性别的卷积神经网络(CNN)模型。

实现步骤

• 了解数据集

• 重新构造数据集(以便使用keras 的Flow_from_directory函数)

• 定义一个简单的函数提取所需的特定标签

• 定义一个简单的函数读取图像、调整图像大小。

• 预处理训练和测试数据

• 从头开始构建简单的CNN模型

• 训练和测试模型

注:

如果你是CNN的新手?查看这篇文章以对它有一个很好的理解:

https://www.freecodecamp.org/news/an-intuitive-guide-to-convolutional-neural-networks-260c2de0a050/

•这篇文章假定您具有卷积神经网络(CNN)的知识。

•该代码是在kaggle内核中执行的。它提供免费的GPU和RAM,不足之处是空间有限,但您可以轻松删除不需要的变量。

数据集描述

来自Kaggle的数据集,包含约55,000张人类指纹图像:

https://www.kaggle.com/ruizgara/socofing

关于数据集的介绍:

• 它有两个主目录-Real目录和Altered目录

• Real目录包含真实人类指纹(无任何变化)

• Altered目录包含经过综合更改的指纹图像,包括用于遮盖、中央旋转和Z形切割的三种不同级别的更改。

• Altered目录进一步分为:Altered_Easy、Altered_hard和Altered_Medium目录

• Real图像的标签如下所示:“ 100__M_Left_thumb_finger.BMP”

• Altered图像的标签遵循以下格式:“ 100__M_Left_thumb_finger_CR.BMP”

格式化数据集

如果我们的数据集如上图所示那样构造,我们可以使用keras中的flow_from_directory()函数来加载数据集,这是从目录加载数据的一种非常简单的方法,它以目录名称作为类别。

话虽如此,数据中目录的名称并不是我们想要的类,因此我们将无法使用flow_from_directory函数。

另外,我们将不得不走更长的路来加载我们的数据——将图像转换为像素值,同时仅提取我们需要的标签“ F”和“ M”。然后我们才能使用数据进行训练、验证和测试。

请记住,Altered图像的格式应类似于:

“ 100__M_Left_thumb_finger_CR.BMP”

而Real图像的格式应类似于:

“ 100__M_Left_thumb_finger.BMP”

我们将基于“ M”和“ F”的性别进行分类。

第一步:从图像标签中提取性别。定义一个简单的函数来完成此任务:

代码语言:javascript
复制
#import necessary libraries
import numpy as np
import pandas as pd
import seaborn as sns
import tensorflow as tf
import os
import cv2
import matplotlib.pyplot as plt
#Function to extract labels for both real and altered images
def extract_label(img_path,train = True):
  filename, _ = os.path.splitext(os.path.basename(img_path))

  subject_id, etc = filename.split('__')
  #For Altered folder
  if train:
      gender, lr, finger, _, _ = etc.split('_')
  #For Real folder
  else:
      gender, lr, finger, _ = etc.split('_')
  
  gender = 0 if gender == 'M' else 1
  lr = 0 if lr == 'Left' else 1

  if finger == 'thumb':
      finger = 0
  elif finger == 'index':
      finger = 1
  elif finger == 'middle':
      finger = 2
  elif finger == 'ring':
      finger = 3
  elif finger == 'little':
      finger = 4
  return np.array([gender], dtype=np.uint16)

有了上面函数就可以帮助我们提取标签。此函数遍历分配给它的图像路径(img_path)内的图像标签,拆分图像标签以获得F和M,然后将0分配给M,将1分配给F,返回一个0和1的数组(0代表M,1代表F)。将上述函数应用到Real目录中的图像,设置train = False,同时对于Altered目录中的图像设置train= True。

第二步:加载数据。创建另一个简单的函数来帮助您:

代码语言:javascript
复制
img_size = 96
#Function to iterate through all the images
def loading_data(path,train):
    print("loading data from: ",path)
    data = []
    for img in os.listdir(path):
        try:
            img_array = cv2.imread(os.path.join(path, img), cv2.IMREAD_GRAYSCALE)
            img_resize = cv2.resize(img_array, (img_size, img_size))
            label = extract_label(os.path.join(path, img),train)
            data.append([label[0], img_resize ])
        except Exception as e:
            pass
    data
    return data

• 首先设定预期的图像尺寸 img_size = 96。

• 迭代:对路径(path)中的所有图像进行操作——读取图像并将它们转换为灰度图像(即黑白),然后将这些图像的像素值数组返回到img_array。

• img_resize包含已基于img_size调整大小的数组值。因此所有图像将具有相同的大小(96x96)。

• 调用extract_labels函数来获取标签,label中包含标签值。

• 所有标签和调整大小的图像数组添加到data列表 。

• 使用try, except块,传递异常

最后一步:分配各种目录,并在每个目录上使用loading_data 函数

代码语言:javascript
复制
Real_path = "../input/socofing/SOCOFing/Real"
Easy_path = "../input/socofing/SOCOFing/Altered/Altered-Easy"
Medium_path = "../input/socofing/SOCOFing/Altered/Altered-Medium"
Hard_path = "../input/socofing/SOCOFing/Altered/Altered-Hard"


Easy_data = loading_data(Easy_path, train = True)
Medium_data = loading_data(Medium_path, train = True)
Hard_data = loading_data(Hard_path, train = True)
test = loading_data(Real_path, train = False)

data = np.concatenate([Easy_data, Medium_data, Hard_data], axis=0)

del Easy_data, Medium_data, Hard_data

训练集data: Easy_data包含了loading_data函数作用在Altered_Easy文件夹的结果,Medium_data、Hard_data分别对应了loading_data函数作用于Altered_Medium和Altered_hard文件夹的结果,注意函数设置设置train = True,将这些结果连接(串联)在一起,以便所有Altered图像都在单个变量data中。

测试集test:test包含loading_data函数作用于Real文件夹的结果,需要设定train = False。

注意:由于kaggle内核上的内存有限,不需要的变量将不断被删除。Easy_data,Medium_data和Hard_data被删除以创建空间。

数据预处理

必须先打乱我们的数据,然后再继续,这是为什么呢?因为在训练我们的模型时,如果神经网络不断看到1类型,它将很快假设所有数据是1类型。当它看到0时将很难学习,并且使用测试数据进行测试时会表现糟糕。因此需要将数据随机化(打乱)。

(1)随机化训练数据data和测试数据test数组。并查看data的格式

代码语言:javascript
复制
import random
random.shuffle(data)
random.shuffle(test)

上图显示了data 包含的内容。对于第一个数组,标签值为0,然后是图像的像素值数组(像素值的范围是0到255)。

(2)分离图像数组和标签

代码语言:javascript
复制
img, labels = [], []
for label, feature in data:
    labels.append(label)
    img.append(feature)
train_data = np.array(img).reshape(-1, img_size, img_size, 1)
train_data = train_data / 255.0
from keras.utils.np_utils import to_categorical
train_labels = to_categorical(labels, num_classes = 2)
del data

• 使用for循环,将图像数组和标签分成单独的列表

• img包含图像数组,labels包含标签值

• img和 labels是列表

• img中的值在重新调整之前再次转换为数组

• 图像的像素值的范围是0到255,通过除以255.0,像素值将按比例缩小到0到1,变为train_data。

• 标签也从列表转换为分类值,我们有两个类F和M类,分配给train_labels

让我们看看处理后的训练图像train_data和训练图像标签train_labels最后的样子

(3)最后一步,使用训练、验证和测试数据集来训练模型。已经有了训练和测试数据,我们仍然需要验证数据(test),因此我们可以使用来自sklearn库的train_test_splitfrom或使用keras的validation_split设置验证数据。

总而言之,我们将在Altered指纹图像(train_data,train_labels)上训练和验证模型然后在Real指纹图像(test)上测试模型。

建立CNN模型

(1)构建模型网络结构

• 使用tensorflow来构建我们的模型

• 从头开始构建一个简单的CNN模型,在每层都有两个卷积层之后将通过relu激活函数添加一个max pooling层

• 之后添加一个flatten层、一个隐藏密集层,然后是一个输出层。

• input_shape = [96,96,1](1是我们的灰度图像的结果)

• 类别数量是2

代码语言:javascript
复制
#Import necessary libraries
from tensorflow.keras import Sequential 
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Dense, Flatten
from tensorflow.keras import layers
from tensorflow.keras import optimizers

model = Sequential([
                    Conv2D(32, 3, padding='same', activation='relu',kernel_initializer='he_uniform', input_shape = [96, 96, 1]),
                    MaxPooling2D(2),
                    Conv2D(32, 3, padding='same', kernel_initializer='he_uniform', activation='relu'),
                    MaxPooling2D(2),
                    Flatten(),
                    Dense(128, kernel_initializer='he_uniform',activation = 'relu'),
                    Dense(2, activation = 'softmax'),
                    ])

• 每个卷积层(Conv2D)包含32个大小为3(即3 x 3)的过滤器,仅在第一层中设置输入形状

• Max pooling(MaxPooling2D)的池化大小为2

• 只有一个具有128个神经单元的隐藏层(Dense),激活函数是relu

• 分类:将使用Dense大小为2(类编号)的输出层和softmax激活来结束网络。

下图是“FrançoisChollet(keras的作者)的python深度学习”一书中的图片,详细说明了如何选择正确的最后一层激活和损失函数。

模型结构总结如下:

代码语言:javascript
复制
model.compile(optimizer = optimizers.Adam(1e-3), loss = 'categorical_crossentropy', metrics = ['accuracy'])
early_stopping_cb = tf.keras.callbacks.EarlyStopping(monitor='val_loss', patience=10)

(2)编译模型:

使用Adam、学习率为0.001的优化器,categorical_crossentropy作为损失函数,准确性为metrics。使用early_stopping_call回调以防止过拟合。它会监视“val_loss”,如果10个epoch内“val_loss”没有增加,停止训练模型。

(3)拟合模型:

代码语言:javascript
复制
history = model.fit(train_data, train_labels, batch_size = 128, epochs = 30, 
          validation_split = 0.2, callbacks = [early_stopping_cb], verbose = 1)

训练模型30个epoch(如果愿意,您可以训练更长的时间),我们设定validation_split = 0.2告诉模型将训练数据的20%用于验证。

如上图所示的图像表明我们的模型正在训练中,它给出了训练损失和准确度的值,以及每个时期的验证损失和准确度的值。我们成功地训练了模型,训练准确度为99%,val准确度为98 %。还不错!

(4)绘制训练和验证数据的准确性和损失曲线:

代码语言:javascript
复制
import pandas as pd
import matplotlib.pyplot as plt
pd.DataFrame(history.history).plot(figsize = (8,5))
plt.grid(True)
plt.gca().set_ylim(0,1)

从上图可以看出,一切进展顺利。在我们的模型训练过程中没有重大的过拟合,两条损失曲线都随着精度的提高而逐渐减小。

测试模型

训练完模型后,想在以前未见过的数据上对其进行测试,以查看其性能如何。如前所述,在Real指纹图像上测试模型,我们已经有了 test数据。

就像我们对训练数据所做的一样,我们将标签和图像阵列分开,整形并除以255.0

代码语言:javascript
复制
test_images, test_labels = [], []

for label, feature in test:
    test_images.append(feature)
    test_labels.append(label)
    
test_images = np.array(test_images).reshape(-1, img_size, img_size, 1)
test_images = test_images / 255.0
del test
test_labels  = to_categorical(test_labels, num_classes = 2)

我们得到了与训练数据(train_data,train_labels)类似的结果

最后,我们通过对模型进行测试来评估测试数据,并给出准确性和损失值:

代码语言:javascript
复制
model.evaluate(test_images, test_labels)

验证集的准确度为99.72%,损失值为0.0126。太好了,您刚刚成功建立了指纹性别分类模型!

结论

总而言之,我们从头开始构建一个简单的CNN,基于指纹图像来预测性别。我们提取了特定标签,将图像转换为数组,预处理了我们的数据集,还预留了训练数据供我们的模型进行训练。在测试数据上测试了我们的模型,并达到了99%的准确性。

最后说明

只要您有足够的图像来训练,使用CNN就能对几乎所有图像进行分类只是神经网络的众多奇迹之一。有很多东西需要学习和探索,我们只是不准备好迎接令人惊奇的事情。

参考

https://www.kaggle.com/abolarinbukola/fingerprint-gender-classification-cnn

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-08-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小白学视觉 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
图像标签
图像标签采用腾讯云前沿图片分类和物体检测算法,可识别图片中出现的各种物体或场景等,返回具体名称和所属类别,覆盖日常物品、场景、动物、植物、食物、饮品、交通工具等多个大类,数百个细分类目,数千个具体标签。广泛应用于拍照识物、场景分析、内容推荐与审核、智能相册分类等场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档