全文共8470字,预计学习时长25分钟
来源:xaecong
HOG:梯度方向直方图(histogram of orientedgradients)是一种图片描述符格式,它能够汇总图像(例如人脸)的主要特征,从而与相似图像进行比较。
本文以及教程源于两年前,我决定更新源代码使其现代化并再次发布。
Java/C++ vs. Python
本演示将在C++程序中使用dlib库来比较两个面部图像的HOG矩阵,并返回它们之间的相似度。因为JNI(Java本机接口集成)是在进程内完成的,并且具有高性能,所以本演示还会使用Java来“封装”C++函数。
我已经看到了几种基于Python的图像处理解决方案,特别是关于面部比较甚至面部识别的方案。这些解决方案使用Python作为主要的编程语言,从dlib或OpenCV库中调用函数。实际上,所有这些解决方案都基于Github上提供的一些Python库,例如:
· https://github.com/ageitgey/face_recognition;
· https://github.com/chanddu/Face-Recognition;
尽管它们具有便于开发的优点,但这些库可能会损害图像处理解决方案的性能,尤其是在主机没有GPU的情况下。正如我在上一篇文章中提到的,众所周知,主要的Python解释器(例如CPython和PyPy)含有GIL(全局解释器锁)。此外,与Java应用程序相比,Python应用程序的性能可能是另一个问题。
因此,在C ++中实现识别功能并封装在Java代码中,将其作为RESTful服务公开更合理。毕竟,在C ++中这样做不会为解决方案增加价值,而只会增加复杂性。
根据TIOBE榜单(https://www.tiobe.com/tiobe-index/),Java除了具有最佳性能外,还是世界上最流行的编程语言。
HOG
来源:Pexels
回到这一技术,我们将看到如何从图像中提取HOG描述符并在不同图像描述符之间进行比较,这是面部比较应用程序的基础。
简单来说,提取出一个描述像素强度(梯度)变化方向和幅度的矩阵,并使用此数据生成直方图。虽然有几种方法可以从图像中提取HOG,但是原始文章使用的是下文的方法:
http://lear.inrialpes.fr/people/triggs/pubs/Dalal-cvpr05.pdf
方法
第一步是将原始图像转换为灰度图,然后过滤线条以删除背景和不感兴趣的其他特征。可以使用OpenCV或dlib等函数库,甚至使用Gimp来完成此操作:
在这张照片中,左上角是原始图像,其在之后被转换为单色图像,最后是带有边缘过滤器(可以是Sobel或其他突出显示线条的过滤器)的图像。为了获得更好的效果,建议仅切割和加工脸部,因为其余部分无关紧要且可能会干扰比较。
对于每个提取的梯度计算强度和幅度的变化方向。
然后,计算直方图,其中类别为倾斜角度(0.20、40、60、80、100、120、140、160),值(票数)为幅度(强度变化)。
绘制该图(这一步没什么意义,但展示效果更好