IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> 探索发现:记一次深度图像处理的经历 -> 正文阅读

[人工智能]探索发现:记一次深度图像处理的经历

一、 前言

2021年底,领导给了个tof模块,要求基于此开发一个演示程序,实现3D人脸识别的功能。当时听他说出3D人脸识别就有点头疼,第一是想自己之前没接触这样的项目;第二是在想3D人脸数据相比于2D人脸数据,恐怕没后者那么多。基于快速开发出产品以及自身能力的想法,向领导建议使用2D+技术路线,即采用rgb图做人脸识别,采用深度图做真假脸识别,领导同意了。

rgb图用到的就是些网上开源、成熟的模型,如retinafacemobileface,这部分不是今天的主题,也没什么好说的,网上博客大把。主要说说深度图吧,简单把过程记录一下,方便自己且抛砖引玉,如果有错漏之处,还请指出,谢谢!

二、 过程

(一)图片预处理过程

先给大伙看看tof保存的深度图,16 bit png格式,每个像素值的实际物理意义是距离,单位是mm
在这里插入图片描述
我没有上传错,原图就是这样,看起来乌漆嘛黑的。因为它是16 bit,像素值范围是[0, 65536),下面给它映射到[0, 256),再给它像素反转一下。

import cv2
import numpy as np

def u16_to_u8(depth_image):
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(depth_image)
    
    alpha = 255 / (max_val - min_val)
    
    beta = -min_val
   
    result = ((depth_image + beta) * alpha).astype(np.uint8)
    
    return result

depth_image = cv2.imread(r"test.png", cv2.IMREAD_ANYDEPTH)
depth_image = u16_to_u8(depth_image)
depth_image = 255 - depth_image
cv2.imshow('depth_image', depth_image)
key = cv2.waitKey(0)

显示结果如下
在这里插入图片描述
可以看见也没什么卵区别,都是一片糊。如果要根据深度图来做分类,区分真假脸,这样的数据恐怕不好做,所以需要再做进一步处理,比如直方图均衡。先试试opencv自带的直方图均衡函数。

depth_image = cv2.imread(r"test.png", cv2.IMREAD_ANYDEPTH)
depth_image = u16_to_u8(depth_image)
cv_he = cv2.equalizeHist(depth_image)
cv2.imwrite(r"t1.png", cv_he)

在这里插入图片描述
看起来效果好了点,但还是有点不够。下面试试openni的直方图均衡函数。

def get_his_img(img, his_size = 65536):
    if len(img.shape) == 2:
        img = img[np.newaxis, :]
    _, h, w = img.shape
    hist = cv2.calcHist(img, [0], None, [his_size - 1], [1, his_size]) 
    
    num = np.sum(hist)
    
    hist = np.cumsum(hist.squeeze())
    
    for s in range(0, his_size - 1):
        hist[s, ] = int((1.0 - (hist[s, ] / num)) * his_size)

    for ii in range(h):
        for jj in range(w):
            if img[:, ii, jj] > 0:
                img[:, ii, jj] = hist[img[:, ii, jj], ]
           
    if len(img.shape) == 3:
        img = img.squeeze()
    return img
    
depth_image = cv2.imread(r"test.png", cv2.IMREAD_ANYDEPTH)
my_he = get_his_img(depth_image, his_size = 65536)
my_he = u16_to_u8(my_he)
cv2.imwrite(r"t1.png", my_he)

在这里插入图片描述
这样才算好,脸部轮廓明显,估计用个逻辑回归都可以很好拟合。仔细看代码,可以看见openni对原先像素值为0的像素是不做处理,它的处理对象是像素值为[1, 256)的像素。当然你们做个筛选,把近距离与远距离的像素值都置为0,再用opencv api来做,估计效果也不错。

(二)真假脸分类算法开发

先给大家看看真假脸的图片,看完会有更深的认识。出于减少运算量与降噪需要,我们取出face roi。下面分别是真人脸、图片脸、电子屏幕脸,根据需要缩放到112x112大小(使用letterbox方式)。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
一开始想无脑直接上机器学习,但是公司服务器没有,办公的PC太辣鸡(呵呵),不想用,所以想着用传统机器视觉来做。

1. 普通直方图比较
准备一张真人脸(随机抽取的一张正面人脸)与测试人脸(无论真假脸,预处理一致)做比较,看代码吧,一目了然。

def compare_img(true_face, fake_face):
    true_face = cv2.resize(true_face, (112, 112)).astype(np.float32)
    fake_face = cv2.resize(fake_face, (112, 112)).astype(np.float32)
    
    true_hist = cv2.calcHist([true_face], [0], None, [256], [0, 256])
    fake_hist = cv2.calcHist([fake_face], [0], None, [256], [0, 256])
    
    match1 = cv2.compareHist(true_hist, fake_hist, cv2.HISTCMP_BHATTACHARYYA)
    match1 = 1 - match1
    if (match1 < 0.75):  # 阈值是根据我的数据集统计而来,下同
        print(0)
        
    match2 = cv2.compareHist(true_hist, fake_hist, cv2.HISTCMP_CORREL)
    if (match2 < 0.965):
        print(1)
        
    match3 = cv2.compareHist(true_hist, fake_hist, cv2.HISTCMP_CHISQR)
    if (match3 > 8000):
        print(2)
        
    print("巴氏距离:%f, 相关性:%f, 卡方:%f\n" %(match1, match2, match3))

img_dir = r"C:\Users\Horizon-Robotics\Pictures"
fake_face_path = os.path.join(img_dir, "test.png")
true_face_path = os.path.join(img_dir, "H5.png")
print(os.path.basename(true_face_path), " vs ", os.path.basename(fake_face_path))

true_face = cv2.imread(true_face_path, cv2.IMREAD_ANYDEPTH)
fake_face = cv2.imread(fake_face_path, cv2.IMREAD_ANYDEPTH)

compare_img(true_face, fake_face)

该方法性能不够,后来采集了个小数据集(真假人脸各130张图片),利用该算法一测试,结果惨不忍睹。想了一下,失败的原因如下(自己瞎想的,如有大神有心得,还望不吝赐教)。
(1)人脸是随机抽取的,不具有代表性;
(2)该算法得到的直方图,只是对图片做了个总体地、粗略的估计。而在全局上,真假人脸可能具有相似的直方图分布。所以我们应该关注局部的特征?

2. LBP-直方图比较
出于更多关注局部特征,引入了LBP算法,正如它的介绍所说:“用于纹理特征提取,提取的特征是图像的局部的纹理特征。LBP就是一种局部信息,它反应的内容是每个像素与周围像素的关系。”
在这里插入图片描述

做了lbp的图片直方图如上,可以看见二者区别还是有的,而且很明显。后来跑了下上面的小数据集,结果准确率是100%,与上面方法相比,该方法是可行的。此处还有个考量:是否统计一下数据集里所有真人脸的lbp直方图,然后得到一张平均的人脸,之后拿这张平均人脸去做计算,防止其过拟合。代码如下:

def my_LBP(img):
    dst = np.zeros(img.shape, dtype=img.dtype)
    h, w = img.shape  # 参数-1为按原通道读入,不写的话默认读入三通道图片,这里获取高度和宽度。
    #print("h, w",h,w)  #
    """
    对于每个cell中的一个像素,将相邻的8个像素的灰度值与其进行比较,
    若周围像素值大于中心像素值,则该想点的位置被标记为1,否则标记为0.
    """
    for i in range(1, h - 1):
        for j in range(1, w - 1):
            center = img[i][j]
            code = 0
            # 邻域灰度值比较
            # code |= (img[i - 1][j - 1] >= center) << (np.uint8)(7)
            # print(code)
            code |= (img[i - 1][j - 1] >= center) << (np.uint8)(7)  # 首先对左上角的数进行0|1的判断,然后将其结果存入二进制数的第7位。
            code |= (img[i - 1][j] >= center) << (np.uint8)(6)
            code |= (img[i - 1][j + 1] >= center) << (np.uint8)(5)
            code |= (img[i][j + 1] >= center) << (np.uint8)(4)
            code |= (img[i + 1][j + 1] >= center) << (np.uint8)(3)
            code |= (img[i + 1][j] >= center) << (np.uint8)(2)
            code |= (img[i + 1][j - 1] >= center) << (np.uint8)(1)
            code |= (img[i][j - 1] >= center) << (np.uint8)(0)

            dst[i - 1][j - 1] = code
            #print("dst[i - 1][j - 1]",i,j,dst[i - 1][j - 1])
    return dst
fake_img = cv2.imread(r'D:\AOBI\0\0_26.png', cv2.IMREAD_GRAYSCALE)
true_img = cv2.imread(r'D:\AOBI\1\1_0.png', cv2.IMREAD_GRAYSCALE)
fake_img = my_LBP(fake_img)
true_img = my_LBP(true_img)

#cv2.imshow('fake_img', fake_img)
#cv2.imshow('true_img', true_img)
#key = cv2.waitKey(0)
plt.subplot(2,1,1)
plt.hist(fake_img.ravel(), 256, [0,256], facecolor='g', label = "fake")
plt.subplot(2,1,2)
plt.hist(true_img.ravel(), 256, [0,256], facecolor='r', label = "true")
plt.show()

3. 逻辑回归
在方法1遇挫后,还是真香定律地试了下逻辑回归。大致流程就是将face roi做直方图均衡预处理,再缩放至32x32,之后reshape成向量,喂入逻辑回归模型。最后的测试结果98.4%准确率。但是它有个问题就是,类间距离不够大,即预测的结果有一些在阈值0.5附近。还有就是那些错分样本的输出概率值都蛮离谱的。放张错分的假人脸图片,给大伙看下。
在这里插入图片描述
可以看见还是比较像人脸的,难怪会分类错误。对于这样的问题,想了下,可能是模型的拟合能力不够,对于一些类人脸的假脸图片就有点力不从心。

4. LBP-逻辑回归
对于方法3的问题,无脑的上CNN是我不想的,所以我选择提升输入图片的质量。刚好上面用了LBP,就显示看了下。
在这里插入图片描述
可以看出,对于真人脸,LBP处理后人脸轮廓还是有的。但对于假人脸,即使其本来像真人脸,但是已经不那么明显了。于是将其输入逻辑回归模型训练,最后测试结果的准确率是100%

三、 后语

近几年的感受就是,深度学习里要好好结合传统视觉,能取得让人惊喜的效果。以及多总结,多记录,多分享。

  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2022-03-10 22:31:02  更:2022-03-10 22:32:32 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 17:51:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码