文章目录

  • 0 背景与结果
  • 1 准备知识
  • 2 tensorflow进行人脸识别(AlexNet、视频/图像)
  • 3 pytorch进行人脸识别(fasterrcnn,图片)
  • 4 dlib库(face_recognition)进行人脸识别
  • 5 百度人脸搜索
  • 6 项目源代码
  • 参考文章

0 背景与结果

在上篇文章中,我们装了人脸识别的环境,这里我们使用安装的框架和库进行实际项目练习。

这篇文章的前两个模型都是摘录和总结自网上,文末附带的所有模型代码均可以运行。由于专业并不是该方向,但是项目中需要使用到该功能,只经过几天简短的学习,撰写了此篇文章。文中如有不对的地方,还望大佬指出。模型可以进行图片和视频的人脸验证。

下面附带识别结果:


1 准备知识

做人脸识别有四部,人脸检测(face detection)、人脸校对(face alignment)、人脸表征(face verification)、人脸鉴别(face identification)。

  • 人脸检测 :提取图像中的人脸区域;
  • 人脸对齐:根据人脸的特征点将倾斜或侧脸对齐;
  • 人脸表征:将人脸图像的像素值转换成紧凑且可判别的特征向量或模版;
  • 人脸匹配:对比两个人脸特征向量的相似度,进而判断是否是同一个人。

2 tensorflow进行人脸识别(AlexNet、视频/图像)

项目代码参考于此,源代码使用sklearnkeras等库。后经过此博文改写,本文又进行一些小修改,让程序可以运行。

模型特点:

  • 人脸检测 : 使用opencv的人脸识别分类器haarcascade_frontalface_alt2.xml(基于Haar特征)来检测人脸;
  • 人脸对齐:未进行人脸对齐,仅进行把人脸图像调整尺寸为正方形(防止缩放失真),然后把图像缩放成64 x 64作为后面训练的数据集;
  • 人脸表征:使用CNN卷积神经网络(三个卷积层、一个全连接层、一个输出层,AlexNet【2012 ImageNet竞赛冠军】)来训练输入的数据集,并存储为已知人脸数据库;
  • 人脸匹配:载入已知的人脸数据库,使用opencv人脸分类器识别出人脸后,再把图像像素调整缩放后,使用tensorflow的方法sess.run进行模型预测。

模型的关键代码:

人脸检测

# 人脸识别分类器地址
PATH_CLASSFIER_CV2_FRONTALFACE_ALT2 = "/Users/mac/PycharmProjects/tensorflowTest/src/haarcascade_frontalface_alt2.xml"# 告诉OpenCV使用人脸识别分类器
classfier = cv2.CascadeClassifier(PATH_CLASSFIER_CV2_FRONTALFACE_ALT2)# 人脸检测,scaleFactor和minNeighbors分别为图片缩放比例和需要检测的有效点数
face_rects = classfier.detectMultiScale(grey, scaleFactor=1.2, minNeighbors=3, minSize=(32, 32))# 得到人脸区域四个点的坐标
t, b, r, l = face_rects[0]

CNN模型:

x_data = tf.placeholder(tf.float32, [None, SIZE, SIZE, 3])y_data = tf.placeholder(tf.float32, [None, None])keep_prob_5 = tf.placeholder(tf.float32)
keep_prob_75 = tf.placeholder(tf.float32)def weightVariable(shape):'''定义Weight变量,输入shape,返回变量的参数。其中我们使用了tf.random_normal产生随机变量来进行初始化'''init = tf.random_normal(shape, stddev=0.01)#init = tf.truncated_normal(shape, stddev=0.01)return tf.Variable(init)def biasVariable(shape):''' 定义biase变量,输入shape,返回变量的一些参数。'''init = tf.random_normal(shape)#init = tf.truncated_normal(shape, stddev=0.01)return tf.Variable(init)def conv2d(x, W):'''定义卷积操作。tf.nn.conv2d函数是Tensorflow里面的二维的卷积函数,x是图片的所有参数,W是卷积层的权重,然后定义步长strides=[1,1,1,1]值。strides[0]和strides[3]的两个1是默认值,意思是不对样本个数和channel进行卷积,中间两个1代表padding是在x方向运动一步,y方向运动一步,padding采用的方式实“SAME”就是0填充。'''return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')def maxPool(x):'''定义池化操作。为了得到更多的图片信息,卷积时我们选择的是一次一步,也就是strides[1]=strides[2]=1,这样得到的图片尺寸没有变化,而我们希望压缩一下图片也就是参数能少一些从而减少系统的复杂度,因此我们采用pooling来稀疏化参数,也就是卷积神经网络中所谓的下采样层。'''return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')def dropout(x, keep):'''为了防止过拟合的问题,可以加一个dropout的处理。'''return tf.nn.dropout(x, keep)def cnnLayer(classnum):'''创建卷积层'''# 第一层W1 = weightVariable([3, 3, 3, 32]) # 卷积核大小(3,3), 输入通道(3), 输出通道(32)b1 = biasVariable([32])conv1 = tf.nn.relu(conv2d(x_data, W1) + b1)pool1 = maxPool(conv1)# 减少过拟合,随机让某些权重不更新drop1 = dropout(pool1, keep_prob_5) # 32 * 32 * 32 多个输入channel 被filter内积掉了# 第二层W2 = weightVariable([3, 3, 32, 64])b2 = biasVariable([64])conv2 = tf.nn.relu(conv2d(drop1, W2) + b2)pool2 = maxPool(conv2)drop2 = dropout(pool2, keep_prob_5) # 64 * 16 * 16# 第三层W3 = weightVariable([3, 3, 64, 64])b3 = biasVariable([64])conv3 = tf.nn.relu(conv2d(drop2, W3) + b3)pool3 = maxPool(conv3)drop3 = dropout(pool3, keep_prob_5) # 64 * 8 * 8# 全连接层Wf = weightVariable([8*16*32, 512])bf = biasVariable([512])drop3_flat = tf.reshape(drop3, [-1, 8*16*32])dense = tf.nn.relu(tf.matmul(drop3_flat, Wf) + bf)dropf = dropout(dense, keep_prob_75)# 输出层Wout = weightVariable([512, classnum])bout = weightVariable([classnum])resMat = tf.matmul(dropf, Wout)# out = tf.add(tf.matmul(dropf, Wout), bout) # 原始数据输出# 输出层归一化# Sigmoid函数可以用来解决多标签问题,Softmax函数用来解决单标签问题# out = tf.add(tf.sigmoid(resMat), bout) # [array([[0.0795017 , 0.03605248, 0.9799969 ]]out = tf.add(tf.nn.softmax(resMat), bout) # [array([[0.00744988, 0.03517907, 0.979998  ]]print(f'tf.matmul(dropf, Wout):{tf.sigmoid(tf.matmul(dropf, Wout))}')return out

填充图片方便缩放图片不失真:

def resizeImage(image, height, width):'''按照指定图像大小调整尺寸判断图片是不是正方形,如果不是,则增加短边的长度使之变成正方形;这样再调用cv2.resize()函数就可以实现等比例缩放了;因为我们指定缩放的比例就是64 x 64,只有缩放之前图像为正方形才能确保图像不失真。'''# 相应方向上的边框宽度top, bottom, left, right = (0, 0, 0, 0)# 获取图像尺寸h, w, _ = image.shape# 对于长宽不相等的图片,找到最长的一边longest_edge = max(h, w)# 计算短边需要增加多上像素宽度使其与长边等长if h < longest_edge: # 上下扩充dh = longest_edge - htop = dh // 2 # 因为上下都需要补齐,所以除以2,向下取整bottom = dh - topelif w < longest_edge: # 左右扩充dw = longest_edge - wleft = dw // 2right = dw - leftelse:passprint(top, bottom, left, right)# 把图像补全成长宽一样的图像# 给图像增加边界,是图片长、宽等长,cv2.BORDER_CONSTANT指定边界颜色由value指定constant = cv2.copyMakeBorder(image, top, bottom, left, right, cv2.BORDER_CONSTANT, value=RESIZE_FILL_COLOR)# cv2.imshow('constant',constant),cv2.waitKey(0),cv2.destroyAllWindows()# 调整图像大小并返回return cv2.resize(constant, (height, width))

模型改进点:

  • 1,使用opencv自带的人脸识别分类器识别人脸准确性;
  • 2,模型使用的比较基础的CNN模型( AlexNet),后期提升效果可以更换为其他CNN模型,如VGGNetResNet,如果应用于移动设备可以使用轻量级CNN模型,如MobileNetSqueezeNetShuffleNet等。

3 pytorch进行人脸识别(fasterrcnn,图片)

源代码参考自此博客,博主文章写了一系列机器学习的文章,内容很详细,非常建议详细学习一下。

模型特点:

  • 人脸检测 :使用训练过的fasterrcnn模型进行的人脸识别;
  • 人脸对齐:未进行人脸对齐;
  • 人脸表征: 根据已知的人脸图片生成人脸编码库;
  • 人脸匹配:载入已知的人脸数据库,使用fasterrcnn模型识别出人脸后,使用人脸认证模型来对计算出来的未知人脸和已知人脸库中人脸编码的欧几里德距离 (Euclidean Distance)或者余弦相似度 (Cosine Similarity)来判断是否是同一个人。

这里没有直接使用编码距离是否小于某个阈值来判断是否是同一个人,因为这个阈值一般很难定义。

人脸认证模型:模型只有一层线性模型,它会给编码中的每个指标乘以一个系数,然后加上偏移值,再交给 Sigmoid 转换到 0 ~ 1 之间的值,0 代表不是同一个人,1 代表是同一个人。

关键代码:

人脸认证模型:

class FaceRecognitionModel(nn.Module):"""人脸识别模型,计算用于寻找最接近人脸的编码 (基于 ResNet 的变种)"""# 编码长度EmbeddedSize = 32# 要求不同人物编码之间的距离 (平方值合计)ExclusiveMargin = 0.2def __init__(self):super().__init__()# Resnet 的实现self.resnet = torchvision.models.resnet18(num_classes=256)# 支持黑白图片if USE_GRAYSCALE:self.resnet.conv1 = nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3, bias=False)# 最终输出编码的线性模型# 因为 torchvision 的 resnet 最终会使用一个 Linear,这里省略掉第一个 Linearself.encode_model = nn.Sequential(nn.ReLU(inplace=True),nn.Linear(256, 128),nn.ReLU(inplace=True),nn.Linear(128, FaceRecognitionModel.EmbeddedSize))def forward(self, x):tmp = self.resnet(x)y = self.encode_model(tmp)return y@staticmethoddef loss_function(predicted):"""损失计算器"""losses = []verify_positive = torch.ones(1).to(device)verify_negative = torch.zeros(NEGATIVE_SAMPLES).to(device)for index in range(0, predicted.shape[0], 2 + NEGATIVE_SAMPLES):a = predicted[index]   # 基础人物的编码b = predicted[index+1] # 基础人物的编码 (另一张图片)c = predicted[index+2:index+2+NEGATIVE_SAMPLES] # 对比人物的编码# 计算编码相差值diff_positive = (a - b).pow(2).sum()diff_negative = (a - c).pow(2).sum(dim=1)# 计算损失# 使用 Triplet Loss,要求同一人物编码距离和不同人物编码距离至少相差 ExclusiveMarginloss = nn.functional.relu(diff_positive - diff_negative + FaceRecognitionModel.ExclusiveMargin).sum()losses.append(loss)loss_total = torch.stack(losses).mean()return loss_total@staticmethoddef calc_accuracy(predicted):"""正确率计算器"""total_count = 0correct_count = 0for index in range(0, predicted.shape[0], 2 + NEGATIVE_SAMPLES):a = predicted[index]   # 基础人物的编码b = predicted[index+1] # 基础人物的编码 (另一张图片)c = predicted[index+2:index+2+NEGATIVE_SAMPLES] # 对比人物的编码# 判断同一人物的编码是否小于不同人物的编码diff_positive = (a - b).pow(2).sum()diff_negative = (a - c).pow(2).sum(dim=1)if (diff_positive < diff_negative).sum() == diff_negative.shape[0]:correct_count += 1total_count += 1return correct_count / total_countclass FaceVerificationModel(nn.Module):"""人脸认证模型,判断是否同一个人,参数是编码相差值的平方"""# 判断是否同一个人的阈值,实际使用模型时可以用更高的值防止误判VerifyThreshold = 0.5def __init__(self):super().__init__()# 判断是否同一人物的线性模型self.verify_model = nn.Sequential(nn.Linear(FaceRecognitionModel.EmbeddedSize, 1),nn.Sigmoid())def forward(self, x):# 经过训练后 weight 应该是负数,bias 应该是正数y = self.verify_model(x)return y.view(-1)@staticmethoddef loss_function(predicted):"""损失计算器"""# 输出应该为 [ 同一人物, 不同人物, 不同人物, ..., 同一人物, 不同人物, 不同人物, ... ]# 这里需要分别计算正负损失,否则会因为负样本占多而引起 bias 被调整为负数positive_indexes = []negative_indexes = []for index in list(range(0, predicted.shape[0], 1+NEGATIVE_SAMPLES)):positive_indexes.append(index)negative_indexes += list(range(index+1, index+1+NEGATIVE_SAMPLES))positive_loss = nn.functional.mse_loss(predicted[positive_indexes], torch.ones(len(positive_indexes)).to(device))negative_loss = nn.functional.mse_loss(predicted[negative_indexes], torch.zeros(len(negative_indexes)).to(device))return (positive_loss + negative_loss) / 2@staticmethoddef calc_accuracy(predicted):"""正确率计算器"""positive_correct = 0positive_total = 0negative_correct = 0negative_total = 0for index in range(0, predicted.shape[0], 1+NEGATIVE_SAMPLES):positive_correct += (predicted[index] >=FaceVerificationModel.VerifyThreshold).sum().item()negative_correct += (predicted[index+1:index+1+NEGATIVE_SAMPLES] <FaceVerificationModel.VerifyThreshold).sum().item()positive_total += 1negative_total += NEGATIVE_SAMPLES# 因为负样本占大多数,这里返回正样本正确率和负样本正确率的平均值return (positive_correct / positive_total + negative_correct / negative_total) / 2

fasterrcnn模型比较长,这里只放一下部分代码:

class MyModel(nn.Module):"""Faster-RCNN (基于 ResNet 的变种)"""Anchors = None # 锚点列表,包含 锚点数量 * 形状数量 的范围AnchorSpan = 16 # 锚点之间的距离,应该等于原有长宽 / resnet 输出长宽AnchorScales = (1, 2, 4, 6, 8) # 锚点对应区域的缩放比例列表AnchorAspects = ((1, 1),) # 锚点对应区域的长宽比例列表AnchorBoxes = len(AnchorScales) * len(AnchorAspects) # 每个锚点对应的形状数量def __init__(self):super().__init__()# 抽取图片各个区域特征的 ResNet (除去 AvgPool 和全连接层)# 和 Fast-RCNN 例子不同的是输出的长宽会是原有的 1/16,后面会根据锚点与 affine_grid 截取区域# 此外,为了可以让模型跑在 4GB 显存上,这里减少了模型的通道数量# 注意:# RPN 使用的模型和标签分类使用的模型需要分开,否则会出现无法学习 (RPN 总是输出负) 的问题self.previous_channels_out = 4self.rpn_resnet = nn.Sequential(nn.Conv2d(3, self.previous_channels_out, kernel_size=3, stride=1, padding=1, bias=False),nn.BatchNorm2d(self.previous_channels_out),nn.ReLU(inplace=True),self._make_layer(BasicBlock, channels_out=8, num_blocks=2, stride=1),self._make_layer(BasicBlock, channels_out=16, num_blocks=2, stride=2),self._make_layer(BasicBlock, channels_out=32, num_blocks=2, stride=2),self._make_layer(BasicBlock, channels_out=64, num_blocks=2, stride=2),self._make_layer(BasicBlock, channels_out=128, num_blocks=2, stride=2))self.previous_channels_out = 4self.cls_resnet = nn.Sequential(nn.Conv2d(3, self.previous_channels_out, kernel_size=3, stride=1, padding=1, bias=False),nn.BatchNorm2d(self.previous_channels_out),nn.ReLU(inplace=True),self._make_layer(BasicBlock, channels_out=8, num_blocks=2, stride=1),self._make_layer(BasicBlock, channels_out=16, num_blocks=2, stride=2),self._make_layer(BasicBlock, channels_out=32, num_blocks=2, stride=2),self._make_layer(BasicBlock, channels_out=64, num_blocks=2, stride=2),self._make_layer(BasicBlock, channels_out=128, num_blocks=2, stride=2))self.features_channels = 128# 根据区域特征生成各个锚点对应的对象可能性的模型self.rpn_labels_model = nn.Sequential(nn.Linear(self.features_channels, self.features_channels),nn.ReLU(inplace=True),nn.Dropout(0.1),nn.Linear(self.features_channels, MyModel.AnchorBoxes*2))# 根据区域特征生成各个锚点对应的区域偏移的模型self.rpn_offsets_model = nn.Sequential(nn.Linear(self.features_channels, self.features_channels),nn.ReLU(inplace=True),nn.Dropout(0.1),nn.Linear(self.features_channels, MyModel.AnchorBoxes*4))# 选取可能出现对象的区域需要的最小可能性self.rpn_score_threshold = 0.9# 每张图片最多选取的区域列表self.rpn_max_candidates = 32# 根据区域截取特征后缩放到的大小self.pooling_size = 16# 根据区域特征判断分类的模型self.cls_labels_model = nn.Sequential(nn.Linear(self.features_channels * (self.pooling_size ** 2), self.features_channels),nn.ReLU(inplace=True),nn.Dropout(0.1),nn.Linear(self.features_channels, len(CLASSES)))# 根据区域特征再次生成区域偏移的模型,注意区域偏移会针对各个分类分别生成self.cls_offsets_model = nn.Sequential(nn.Linear(self.features_channels * (self.pooling_size ** 2), self.features_channels*4),nn.ReLU(inplace=True),nn.Dropout(0.1),nn.Linear(self.features_channels*4, len(CLASSES)*4))def _make_layer(self, block_type, channels_out, num_blocks, stride):"""创建 resnet 使用的层"""blocks = []# 添加第一个块blocks.append(block_type(self.previous_channels_out, channels_out, stride))self.previous_channels_out = channels_out * block_type.expansion# 添加剩余的块,剩余的块固定处理间隔为 1,不会改变长宽for _ in range(num_blocks-1):blocks.append(block_type(self.previous_channels_out, self.previous_channels_out, 1))self.previous_channels_out *= block_type.expansionreturn nn.Sequential(*blocks)

模型改进点:

  • 脸部特征提取的特征点比较少(就左、右眼、鼻尖、嘴巴左、右嘴角),导致后期人脸检测率不高;
  • 未进行人脸对齐。

4 dlib库(face_recognition)进行人脸识别

dlib是C++编写的一个跨平台机器学习开源库。而face_recognition是一个封装了dlib的人脸识别库。

模型特点:

  • 人脸检测 :进行人脸检测使用的网络架构是基于ResNet-34但是层数更少,过滤器数量减少了一半(在超过300万张图像上训练的);
  • 人脸对齐:找到人脸68个特征点后,通过图像的几何变换(仿射、旋转、缩放),使各个特征点对齐(将眼睛、嘴等部位移到相同位置);
  • 人脸表征:把检测出来的人脸进行编码并存储;
  • 人脸匹配:通过设定某个阈值(严格度,严格度越小,面部识别系统越严格),计算欧几里得距离是否小于阈值,来判定脸部编码是否属于同一个人。

关键代码:

使用模型API进行人脸载入、编码、识别:

   # 载入图片方式1img = cv2.imread(img_path)img_rgb = img[:, :, ::-1]# 载入图片方式2unknown_img = face_recognition.load_image_file(comparison_img_path)# 得到人脸位置face_loc = face_recognition.face_locations(unknown_img, number_of_times_to_upsample=1, model="hog")# 得到脸部轮廓face_marks = face_recognition.face_landmarks(img_rgb)# 得到人脸编码faces_encodings = face_recognition.face_encodings(unknown_img, num_jitters=NUM_JITTERS_INDEX)# 人脸对比face_recognition.compare_faces([coding], faces_encodings, tolerance=TOLERANCE_INDEX)# 训练knn模型X.append(face_recognition.face_encodings(image, known_face_locations=face_bounding_boxes)[0])y.append(class_dir)n_neighbors = int(round(math.sqrt(len(X))))knn_clf = neighbors.KNeighborsClassifier(n_neighbors=n_neighbors, algorithm=knn_algo, weights='distance')knn_clf.fit(X, y)# 使用knn模型进行人脸对比closest_distances = knn_clf.kneighbors(faces_encodings, n_neighbors=1)are_matches = [closest_distances[0][i][0] <= distance_threshold for i in range(len(X_face_locations))]

摄像头捕捉模版:

def cameraCatchComparison(known_img_model_file_path):"""使用摄像头进行人脸识别,速度比较慢(慢3-5s):param known_img_model_file_path: 已知模型的人脸识别:return: 无"""# 计算机摄像设备索引CAMERA_IDX = 0# 调用摄像头,conf.CAMERA_IDX为摄像头索引,默认为0,也可以这样写cap = cv2.VideoCapture(0)cap = cv2.VideoCapture(CAMERA_IDX)while True:# 读取一帧数据if cap.isOpened() == False:breakok, frame = cap.read()# Convert the image from BGR color (which OpenCV uses) to RGB color (which face_recognition uses)# OpenCV是BGR格式,PIL是RGB格式rgb_frame = frame[:, :, ::-1]if not ok:breakimg = cv2.resize(rgb_frame, (0, 0), fx=0.25, fy=0.25)predictions = predict(img, model_path="trained_knn_model.clf")frame = show_prediction_labels_on_image(frame, predictions, deal_pattern='video')# 显示图像cv2.imshow('Face Recognition Video', frame)# 监听输入,按q退出if cv2.waitKey(1) & 0xFF == ord('q'):break# 释放摄像头并销毁所有窗口cap.release()cv2.destroyAllWindows()

如果想知道更多的内容,可以查看此网页、网页2【翻译版本】。

如果想自己训练人脸识别的模型,可以查看dlib的API接口,dlib训练网络模型的示例。由于face_recognition使用的人脸训练图片为上百万张,如果自己想要重新训练人脸识别模型,需要建立一个包含来自许多不同地方的上千万按个人分组的个人数据集,否则无法重新训练模型。添加几千张自己的图像并没有真正的帮助。

模型目前存在的问题:

  • 由于模型训练的数据集大部分来自于欧洲,导致亚洲人识别率不是很高更多详细内容

5 百度人脸搜索

百度有现成的人脸搜索,相应的API文档。百度人脸搜索使用的技术是PyramidBox人脸检测算法,训练人脸识别时,不仅使用人脸的信息,还是用人脸旁边的背景信息来辅助人脸检测,在模糊,变形,部分的小人脸的情况下,效果不错。下面是图片使用PyramidBox算法识别的效果。

6 项目源代码

码云地址,欢迎大家star。

参考文章

tensorflow人脸:BossSensor

weird quirky的博客

老农的博客

人脸识别原理(以GitHub项目face_recognition为例)

人脸验证(图片/视频) tensorflow、pytorch框架、dlib库(face_recognition)和opencv库————附带详细步骤和代码,可实际运行相关推荐

  1. Mac/Linux安装人脸识别常用库(tensorflow、pytorch、dlib、face_recognition、opencv、CMake、gcc/g++)————所有环境一次性配置好

    文章目录 0 背景与准备 1 tensorflow环境[数值计算的开源软件库] 2 pytorch环境[数值计算的开源软件库] 3 face_recognition[基于dlib的人脸识别库] 4 o ...

  2. 使用PyTorch构建GAN生成对抗网络源码(详细步骤讲解+注释版)02 人脸识别 上

    文章目录 1 数据集描述 2 GPU设置 3 设置Dataset类 4 设置辨别器类 5 辅助函数与辅助类 1 数据集描述 此项目使用的是著名的celebA(CelebFaces Attribute) ...

  3. 使用PyTorch构建GAN生成对抗网络源码(详细步骤讲解+注释版)02 人脸识别 下

    文章目录 1 测试鉴别器 2 建立生成器 3 测试生成器 4 训练生成器 5 使用生成器 6 内存查看 上一节,我们已经建立好了模型所必需的鉴别器类与Dataset类. 使用PyTorch构建GAN生 ...

  4. Python人脸识别图片视频

    人脸识别技术发展现状及未来趋势 当前,随着人工智能.物联网等前沿技术的迅速发展,智能时代已悄然到来,"刷脸"逐渐成为了新的风潮.在人脸识别技术商业化应用领域不断扩张的趋势下,&qu ...

  5. 用gcc生成静态库和动态库和使用opencv库编写打开摄像头压缩视频

    文章目录 一.用gcc生成静态库和动态库 1.编辑生成程序hello.h.hello.c.main.c 2.将hello.c生成.o文件 3.使用静态库 4.动态库的使用 二.a与.so库文件的生成与 ...

  6. 基于SSM框架开发的网上图书商城系统 附带详细运行指导视频

    项目描述:这是一个基于SSM框架开发的网上图书商城系统.首先,这个项目页面简洁清爽,代码注释详尽,易于理解和学习.其次,这个项目涉及到Shiro整合JWT.秒杀功能所具备的基本要求(限流.乐观锁.接口 ...

  7. 使用PyTorch构建GAN生成对抗网络源码(详细步骤讲解+注释版)01 手写字体识别

    文章目录 1 生成对抗网络基本概念 2 生成对抗网络建模 2.1 建立MnistDataset类 2.2 建立鉴别器 2.3 测试鉴别器 2.4 Mnist生成器制作 3 模型的训练 4 模型表现的判 ...

  8. Spring框架之AOP详解(带实战详细步骤)

    Spring之AOP AOP简介: 解决的问题:解决了需求的改变,造成了原有没必要改变的代码,需要去改变它: 比如:书籍的增删改,本身只需要完成增删改的功能即可,这是如果需要添加日志功能,那么需要在原 ...

  9. 模式识别作业--人脸识别(python+PCA+pytorch神经网络)

    模式识别作业–人脸识别(python+PCA+pytorch) 1.实验原理 该实验通过PCA降维+BP神经网络的算法实现对人脸数据集中人脸数据的识别 2.实验步骤 1.图片预处理 首先将测试集和训练 ...

最新文章

  1. 网络安全渗透--判断网站使用何种网页语言,判断网站所用服务器
  2. C# 计时函数精度测试
  3. Spring Cloud中,Eureka常见问题总结
  4. Java基础-static 关键字解析
  5. 网络视频监控与人脸识别
  6. 计算机数学基础试题,计算机数学基础(A)综合练习
  7. 冲击波病毒内幕点滴(2) (转)
  8. Mixly-数位计及1602屏亮度显示
  9. webpack 图片压缩
  10. 计算机表格加减乘除符号,excel加减乘除-Excel表格最常用的37种符号,帮你整理齐了!...
  11. C++char数据类型
  12. FAST迅捷路由器设置
  13. 关于配置ssl证书后网页无法访问的原因
  14. 让设计师哭笑不得的文案
  15. 百度网盘直链下载助手(MacOSChrome)
  16. 构建docker镜像时ERROR: http://dl-cdn.alpinelinux.org/alpine/v3.12/main: network error
  17. 特征工程的准备:特征理解
  18. Flex布局实战:支付宝首页
  19. 北京防灾科技学院计算机怎么样,防灾科技学院
  20. git merge --no--ff 详解

热门文章

  1. Java编写三角形和平行四边形
  2. 【leetcode】557 反转字符串中的单词III(字符串)
  3. 「史诗级干货」新人up主B站运营炫酷玩法,轻松实现UP!UP!UP!
  4. 梦想起航商务工作PPT模板-优页文档
  5. 世界首富用 AI 开除混吃混喝的“兄弟”
  6. kaldi理解WFST,HCLG,lattice
  7. OSPF vlink
  8. SQL Server 备份还原单个数据表
  9. windows下搭建ITS运行环境
  10. 关于Dlink和ADSL不和谐的解决