传统人脸检测项目实战(Haar级联与手工特征分类器)

系列文章目录

本文使用两种方法来进行人脸检测
1.Haar特征 人脸检测
2.手工特征+分类器 人脸检测




一、Haar特征 人脸检测

Haar特征

Haar是一种用模板来描述图像变化的工具,所得到的结果可以作为图像特征。

根据目标不同,设计了多种不同的模板。

haar
这些特征,实际上就是卷积神经网络的灵感源泉之一。

在实际运算中,haar特征的精度并不高。但结合积分图,可以快速计算图像特征。

具体计算方法是,白色区域的和 减去 黑色区域的和.

本质上,白色区域的值为1,黑色区域的值为0。

haar级联人脸检测

可以使用opencv提供的事先训练好的模型直接进行推理。
这里直接下载opencv库即可

pip install opencv

或者也可以使用镜像下载 提高速度
下载好之后找到

Acondan\Lib\site-packages\cv2\data

文件夹下的训练好的模型,直接调用
在这里插入图片描述
附上代码:

import cv2
import matplotlib.pyplot as plt

face_detector = cv2.CascadeClassifier(r'D:\Acondan\Lib\site-packages\cv2\data\haarcascade_frontalface_default.xml')
img = cv2.imread('./lena.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_detector.detectMultiScale(img,1.1, 4 )
for (x,y, w, h) in faces:
    cv2.rectangle(img, pt1 = (x,y),pt2 = (x+w, y+h), color = (255,0,0),thickness =  3)
    roi_gray = gray[y:y+h,x:x+w]
    roi_color = img[y:y+h, x:x+w]

plt.imshow(img)

运行结果:
在这里插入图片描述
可以看到检测出了人脸。

二、手工特征+分类器

预准备

本文采用

要进行本项目的实战 首先需要安装如下几个包

pip install scikit-learn
pip install matplotlib
pip install numpy

数据集lfw,我们这里直接用scikit-learn库导入

faces = fetch_lfw_people(download_if_missing=true)

机器学习进行人脸预测可以大致分为两个步骤
1.特征提取
2.分类器训练

手工特征提取和分类器训练简介

HOG特征
hog, higtogram of oriented gradient, 是抓取图像轮廓的算法。

具体上,将一张图像切成很多个区域,并从每个区域中提取出方向梯度,作为特征。

其基本步骤包括:

图像预处理: 灰度化、归一化、平滑等
计算梯度: 用sobel计算梯度的赋值和方向
分割图像:将图像切割成大小相同的cell。并构建直方图
块归一化:将每个patch中的图直方图进行归一化,消除光影影响
将所有直方图组合成一个特征向量


分类器的大致训练过程如下

训练过程

grad = GridSearchCV(LinearSVC(dual=False), {'C': [1.0, 2.0, 4.0, 8.0]}, cv=3)

grad.fit(X_train, y_train)

print(grad.best_score_)

print(grad.best_params_)

model = grad.best_estimator_
model.fit(X_train, y_train)
//测试过程

labels = model.predict(patches_hog)

项目实战

导入库,并下载人脸数据集,设置正类

from sklearn.datasets import fetch_lfw_people
import matplotlib.pyplot as plt
import numpy as np
faces = fetch_lfw_people(download_if_missing=False)
positive_patches = faces.images
print(positive_patches.shape)
plt.imshow(positive_patches[0],cmap='gray')

运行结果
在这里插入图片描述

设置负类数据

from skimage import data, transform, color

imgs_to_use = ['hubble_deep_field', 'text', 'coins', 'moon',
               'page', 'clock', 'coffee', 'chelsea', 'horse']

images = []
for name in imgs_to_use:
    if len(np.array(getattr(data, name)()).shape) == 3:
        images.append(color.rgb2gray(getattr(data, name)()))
    else:
        images.append(getattr(data, name)())
from sklearn.feature_extraction.image import PatchExtractor

def extract_patches(img, N, scale=1.0, patch_size=positive_patches[0].shape):
    extract_patch_size = tuple((scale * np.array(patch_size)).astype(int))
    extractor = PatchExtractor(patch_size=extract_patch_size,
                               max_patches=N, random_state=0)

    patches = extractor.transform(img[np.newaxis])
    # patches = extractor.transform(img)

    if scale != 1:
        patches = np.array([transform.resize(patch, patch_size) for patch in patches])

    return patches
negative_patches = np.vstack([extract_patches(im, 1000, scale)
                              for im in images for scale in [0.5, 1.0, 2.0]])
print(negative_patches.shape)
count = 0
for i, x in enumerate(range(10000, 10024)):
    count += 1
    plt.subplot(4,6,count)
    plt.imshow(negative_patches[i], cmap='gray')
    plt.axis('off')

运行结果展示负类
在这里插入图片描述

手工标注 将正类赋值为1,负类为0

from skimage import feature
from itertools import chain

X_train = np.array([feature.hog(im) for im in chain(positive_patches, negative_patches)])

y_train = np.zeros(X_train.shape[0])

y_train[:positive_patches.shape[0]] = 1#正例都是1 负的是0

使用LinearSVC类来定义一个线性支持向量机分类器,然后使用GridSearchCV类来执行一个网格搜索,以找到最佳的超参数C的值。
搜索的参数空间是C的值为[1.0, 2.0, 4.0, 8.0]。在搜索期间,使用交叉验证(cv=3)来评估每个超参数的性能。
一旦找到了最佳的超参数C的值,就使用该值来构建一个新的LinearSVC对象,并使用训练数据集(X_train和y_train)来拟合该模型。最后,输出最佳得分和最佳参数,并将最佳估计器(即拟合了最佳超参数的LinearSVC对象)存储在model变量中。

from sklearn.svm import LinearSVC
from sklearn.model_selection import GridSearchCV

grad = GridSearchCV(LinearSVC(dual=False), {
    
    'C': [1.0, 2.0, 4.0, 8.0]}, cv=3)

grad.fit(X_train, y_train)

print(grad.best_score_, grad.best_params_)

model = grad.best_estimator_

model.fit(X_train, y_train)

这里可以看到参数为1.0时,效果最好
在这里插入图片描述
从图片库中找一个人像,用来做人脸检测

test_img = data.astronaut()
test_img = color.rgb2gray(test_img)
test_img = transform.rescale(test_img, 0.5)

test_img = test_img[:120, 60:160]

plt.imshow(test_img, cmap='gray')
plt.axis('off')

plt.show()

在这里插入图片描述
使用滑动窗口框出人脸

def sliding_window(img, patch_size=positive_patches[0].shape,                #滑动窗口的方式
                   istep=2, jstep=2, scale=1.0):
    Ni, Nj = (int(scale * s) for s in patch_size)
    for i in range(0, img.shape[0]- Ni, istep):
        for j in range(0, img.shape[1] - Ni, jstep):
            patch = img[i: i + Ni, j: j+Nj]

            if scale != 1:
                patch = transform.resize(patch, patch_size)
            yield (i, j), patch


# 使用滑动窗口计算每一视窗的HOG
indices, patches = zip(*sliding_window(test_img))
patches_hog = np.array([feature.hog(patch) for patch in patches])

labels = model.predict(patches_hog)
print(labels.sum())  # 检测到的窗口总数 55

fig, ax = plt.subplots()
ax.imshow(test_img, cmap='gray')
ax.axis('off')

Ni, Nj = positive_patches[0].shape
indices = np.array(indices)

for i, j in indices[labels == 1]:
    ax.add_patch(plt.Rectangle((j, i), Nj, Ni, edgecolor='red',
                               alpha=0.3, lw=2, facecolor='none'))

plt.show()

在这里插入图片描述
同样 我们可以更改特征提取器,这里给一个LBP特征的调用方法

# 使用滑动窗口计算每一视窗的 LBP 特征
Ni, Nj = positive_patches[0].shape
labels = np.zeros_like(test_img, dtype=bool)
for (i, j), patch in sliding_window(test_img, patch_size=(Ni, Nj)):
    patch_lbp = local_binary_pattern(patch, n_points, radius, method='uniform').ravel()
    patch_lbp_2d = patch_lbp.reshape(1, -1)
    pred = model.predict(patch_lbp_2d)
    if pred == 1:
        # 找到第一个检测到的目标,绘制一个框,并退出循环
        mid_i, mid_j = i + Ni // 2, j + Nj // 2  # 找到中间位置
        labels[mid_i, mid_j] = True  # 标记中间位置
        fig, ax = plt.subplots()
        ax.imshow(test_img, cmap='gray')
        ax.axis('off')
        ax.add_patch(plt.Rectangle((mid_j - Nj // 2, mid_i - Ni // 2), Nj, Ni, edgecolor='red',
                               alpha=0.3, lw=2, facecolor='none'))
        plt.show()
        break

大家可以使用LBP更改文中的hot特征


猜你喜欢

转载自blog.csdn.net/weixin_51672245/article/details/130723472