日萌社

人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度学习实战(不定时更新)


# ArcFace
class ArcMarginProduct(nn.Module):r"""Implement of large margin arc distance: :Args:in_features: size of each input sampleout_features: size of each output samples: norm of input featurem: margincos(theta + m)"""def __init__(self, in_features, out_features, s=30.0, m=0.50, easy_margin=False):super(ArcMarginProduct, self).__init__()self.in_features = in_featuresself.out_features = out_featuresself.s = sself.m = m# 初始化权重self.weight = Parameter(torch.FloatTensor(out_features, in_features))nn.init.xavier_uniform_(self.weight)self.easy_margin = easy_marginself.cos_m = math.cos(m)self.sin_m = math.sin(m)self.th = math.cos(math.pi - m)self.mm = math.sin(math.pi - m) * mdef forward(self, input, label):# cos(theta) & phi(theta)# torch.nn.functional.linear(input, weight, bias=None)# y=x*W^T+bcosine = F.linear(F.normalize(input), F.normalize(self.weight))sine = torch.sqrt(1.0 - torch.pow(cosine, 2))# cos(a+b)=cos(a)*cos(b)-size(a)*sin(b)phi = cosine * self.cos_m - sine * self.sin_mif self.easy_margin:# torch.where(condition, x, y) → Tensor# condition (ByteTensor) – When True (nonzero), yield x, otherwise yield y# x (Tensor) – values selected at indices where condition is True# y (Tensor) – values selected at indices where condition is False# return:# A tensor of shape equal to the broadcasted shape of condition, x, y# cosine>0 means two class is similar, thus use the phi which make itphi = torch.where(cosine > 0, phi, cosine)else:phi = torch.where(cosine > self.th, phi, cosine - self.mm)# convert label to one-hot# one_hot = torch.zeros(cosine.size(), requires_grad=True, device='cuda')# 将cos(\theta + m)更新到tensor相应的位置中one_hot = torch.zeros(cosine.size(), device='cuda')# scatter_(dim, index, src)one_hot.scatter_(1, label.view(-1, 1).long(), 1)# torch.where(out_i = {x_i if condition_i else y_i) output = (one_hot * phi) + ((1.0 - one_hot) * cosine)output *= self.sreturn output

from PIL import Image
from detector import detect_faces
from visualization_utils import show_resultsimg = Image.open('some_img.jpg') # modify the image path to yours
bounding_boxes, landmarks = detect_faces(img) # detect bboxes and landmarks for all faces in the image
show_results(img, bounding_boxes, landmarks) # visualize the results
from PIL import Image
from face_dect_recong.align.detector import detect_faces
from face_dect_recong.align.visualization_utils import show_results
%matplotlib inlineimg = Image.open('./data/other_my_face/my/my/myf112.jpg')
bounding_boxes, landmarks = detect_faces(img) # detect bboxes and landmarks for all faces in the image
show_results(img, bounding_boxes, landmarks) # visualize the results

from PIL import Image
from face_dect_recong.align.detector import detect_faces
from face_dect_recong.align.visualization_utils import show_results
%matplotlib inlineimg = Image.open('./data/other_my_face/others/Woody_Allen/Woody_Allen_0001.jpg')
bounding_boxes, landmarks = detect_faces(img)
show_results(img, bounding_boxes, landmarks)

#对其他人的图像进行检测
%run face_dect_recong/align/face_align.py -source_root './data/other_my_face/others/' -dest_root './data/other_my_face_align/others' -crop_size 128#对我的图像进行检测
%run face_dect_recong/align/face_align.py -source_root './data/other_my_face/my/' -dest_root './data/other_my_face_align/others/' -crop_size 128
import matplotlib.pyplot as plt
from matplotlib.image import imread
%matplotlib inlineimg=imread('./data/other_my_face_align/others/my/myf112.jpg')
plt.imshow(img)
plt.show

img=imread('./data/other_my_face_align/others/Woody_Allen/Woody_Allen_0002.jpg')
plt.imshow(img)
plt.show

#删除小于4张的一些人
%run face_dect_recong/balance/remove_lowshot.py -root './data/other_my_face_align/others' -min_num 4img=imread('./data/dataset/lfw/lfw-align-128/Zico/Zico_0001.jpg')
plt.imshow(img)
plt.show

class Config(object):env = 'default'backbone = 'resnet18'classify = 'softmax'metric = 'arc_margin'easy_margin = False#是否使用压缩奖惩网络模块(Squeeze-and-Excitation Blocks)use_se = Falseloss = 'focal_loss'display = Falsefinetune = Falselfw_root = '/home/wumg/data/data/other_my_face_align/others'lfw_test_list = '/home/wumg/data/data/other_my_face_align/others_test_pair.txt'test_model_path = '/home/wumg/data/data/dataset/lfw/resnet18_110.pth'save_interval = 10train_batch_size = 16  # batch sizetest_batch_size = 60input_shape = (1, 128, 128)optimizer = 'sgd'use_gpu = True  # use GPU or notgpu_id = '0, 1'num_workers = 4  # how many workers for loading datamax_epoch = 2lr = 1e-1  # initial learning ratelr_step = 10lr_decay = 0.95  # when val_loss increase, lr = lr*lr_decayweight_decay = 5e-4
from __future__ import print_function
import os
import cv2
from models import *
import torch
import torch.nn as nn
import numpy as np
import time
from torch.nn import DataParallel
import torch.utils.model_zoo as model_zoo
import torch.nn.functional as Fmodel_urls = {'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth','resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth'}device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")def conv3x3(in_planes, out_planes, stride=1):"""3x3 convolution with padding"""return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,padding=1, bias=False)class BasicBlock(nn.Module):expansion = 1def __init__(self, inplanes, planes, stride=1, downsample=None):super(BasicBlock, self).__init__()self.conv1 = conv3x3(inplanes, planes, stride)self.bn1 = nn.BatchNorm2d(planes)self.relu = nn.ReLU(inplace=True)self.conv2 = conv3x3(planes, planes)self.bn2 = nn.BatchNorm2d(planes)self.downsample = downsampleself.stride = stridedef forward(self, x):residual = xout = self.conv1(x)out = self.bn1(out)out = self.relu(out)out = self.conv2(out)out = self.bn2(out)if self.downsample is not None:residual = self.downsample(x)out += residualout = self.relu(out)return outclass IRBlock(nn.Module):expansion = 1def __init__(self, inplanes, planes, stride=1, downsample=None, use_se=True):super(IRBlock, self).__init__()self.bn0 = nn.BatchNorm2d(inplanes)self.conv1 = conv3x3(inplanes, inplanes)self.bn1 = nn.BatchNorm2d(inplanes)self.prelu = nn.PReLU()self.conv2 = conv3x3(inplanes, planes, stride)self.bn2 = nn.BatchNorm2d(planes)self.downsample = downsampleself.stride = strideself.use_se = use_seif self.use_se:self.se = SEBlock(planes)def forward(self, x):residual = xout = self.bn0(x)out = self.conv1(out)out = self.bn1(out)out = self.prelu(out)out = self.conv2(out)out = self.bn2(out)if self.use_se:out = self.se(out)if self.downsample is not None:residual = self.downsample(x)out += residualout = self.prelu(out)return outclass ResNetFace(nn.Module):def __init__(self, block, layers, use_se=True):self.inplanes = 64self.use_se = use_sesuper(ResNetFace, self).__init__()self.conv1 = nn.Conv2d(1, 64, kernel_size=3, padding=1, bias=False)self.bn1 = nn.BatchNorm2d(64)self.prelu = nn.PReLU()self.maxpool = nn.MaxPool2d(kernel_size=2, stride=2)self.layer1 = self._make_layer(block, 64, layers[0])self.layer2 = self._make_layer(block, 128, layers[1], stride=2)self.layer3 = self._make_layer(block, 256, layers[2], stride=2)self.layer4 = self._make_layer(block, 512, layers[3], stride=2)self.bn4 = nn.BatchNorm2d(512)self.dropout = nn.Dropout()self.fc5 = nn.Linear(512 * 8 * 8, 512)self.bn5 = nn.BatchNorm1d(512)for m in self.modules():if isinstance(m, nn.Conv2d):nn.init.xavier_normal_(m.weight)elif isinstance(m, nn.BatchNorm2d) or isinstance(m, nn.BatchNorm1d):nn.init.constant_(m.weight, 1)nn.init.constant_(m.bias, 0)elif isinstance(m, nn.Linear):nn.init.xavier_normal_(m.weight)nn.init.constant_(m.bias, 0)def _make_layer(self, block, planes, blocks, stride=1):downsample = Noneif stride != 1 or self.inplanes != planes * block.expansion:downsample = nn.Sequential(nn.Conv2d(self.inplanes, planes * block.expansion,kernel_size=1, stride=stride, bias=False),nn.BatchNorm2d(planes * block.expansion),)layers = []layers.append(block(self.inplanes, planes, stride, downsample, use_se=self.use_se))self.inplanes = planesfor i in range(1, blocks):layers.append(block(self.inplanes, planes, use_se=self.use_se))return nn.Sequential(*layers)def forward(self, x):x = self.conv1(x)x = self.bn1(x)x = self.prelu(x)x = self.maxpool(x)x = self.layer1(x)x = self.layer2(x)x = self.layer3(x)x = self.layer4(x)x = self.bn4(x)x = self.dropout(x)x = x.view(x.size(0), -1)x = self.fc5(x)x = self.bn5(x)return xclass ResNet(nn.Module):def __init__(self, block, layers):self.inplanes = 64super(ResNet, self).__init__()# self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3,#                        bias=False)self.conv1 = nn.Conv2d(1, 64, kernel_size=3, stride=1, padding=1,bias=False)self.bn1 = nn.BatchNorm2d(64)self.relu = nn.ReLU(inplace=True)# self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)self.layer1 = self._make_layer(block, 64, layers[0], stride=2)self.layer2 = self._make_layer(block, 128, layers[1], stride=2)self.layer3 = self._make_layer(block, 256, layers[2], stride=2)self.layer4 = self._make_layer(block, 512, layers[3], stride=2)self.fc5 = nn.Linear(512 * 8 * 8, 512)for m in self.modules():if isinstance(m, nn.Conv2d):nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')elif isinstance(m, nn.BatchNorm2d):nn.init.constant_(m.weight, 1)nn.init.constant_(m.bias, 0)def _make_layer(self, block, planes, blocks, stride=1):downsample = Noneif stride != 1 or self.inplanes != planes * block.expansion:downsample = nn.Sequential(nn.Conv2d(self.inplanes, planes * block.expansion,kernel_size=1, stride=stride, bias=False),nn.BatchNorm2d(planes * block.expansion),)layers = []layers.append(block(self.inplanes, planes, stride, downsample))self.inplanes = planes * block.expansionfor i in range(1, blocks):layers.append(block(self.inplanes, planes))return nn.Sequential(*layers)def forward(self, x):x = self.conv1(x)x = self.bn1(x)x = self.relu(x)# x = self.maxpool(x)x = self.layer1(x)x = self.layer2(x)x = self.layer3(x)x = self.layer4(x)# x = nn.AvgPool2d(kernel_size=x.size()[2:])(x)# x = self.avgpool(x)x = x.view(x.size(0), -1)x = self.fc5(x)return xdef resnet18(pretrained=False, **kwargs):"""Constructs a ResNet-18 model.Args:pretrained (bool): If True, returns a model pre-trained on ImageNet"""model = ResNet(BasicBlock, [2, 2, 2, 2], **kwargs)if pretrained:model.load_state_dict(model_zoo.load_url(model_urls['resnet18']))return modeldef resnet_face18(use_se=True, **kwargs):model = ResNetFace(IRBlock, [2, 2, 2, 2], use_se=use_se, **kwargs)return model
def get_lfw_list(pair_list):with open(pair_list, 'r') as fd:pairs = fd.readlines()data_list = []for pair in pairs:splits = pair.split()if splits[0] not in data_list:data_list.append(splits[0])if splits[1] not in data_list:data_list.append(splits[1])return data_listdef load_image(img_path):image = cv2.imread(img_path, 0)if image is None:return Noneimage = np.dstack((image, np.fliplr(image)))image = image.transpose((2, 0, 1))image = image[:, np.newaxis, :, :]image = image.astype(np.float32, copy=False)image -= 127.5image /= 127.5return imagedef get_featurs(model, test_list, batch_size=10):images = Nonefeatures = Nonecnt = 0for i, img_path in enumerate(test_list):image = load_image(img_path)if image is None:print('read {} error'.format(img_path))if images is None:images = imageelse:images = np.concatenate((images, image), axis=0)if images.shape[0] % batch_size == 0 or i == len(test_list) - 1:cnt += 1data = torch.from_numpy(images)data = data.to(device)output = model(data)output = output.data.cpu().numpy()fe_1 = output[::2]fe_2 = output[1::2]feature = np.hstack((fe_1, fe_2))# print(feature.shape)if features is None:features = featureelse:features = np.vstack((features, feature))images = Nonereturn features, cntdef load_model(model, model_path):model_dict = model.state_dict()pretrained_dict = torch.load(model_path)pretrained_dict = {k: v for k, v in pretrained_dict.items() if k in model_dict}model_dict.update(pretrained_dict)model.load_state_dict(model_dict)def get_feature_dict(test_list, features):fe_dict = {}for i, each in enumerate(test_list):# key = each.split('/')[1]fe_dict[each] = features[i]return fe_dictdef cosin_metric(x1, x2):return np.dot(x1, x2) / (np.linalg.norm(x1) * np.linalg.norm(x2))def cal_accuracy(y_score, y_true):y_score = np.asarray(y_score)y_true = np.asarray(y_true)best_acc = 0best_th = 0for i in range(len(y_score)):th = y_score[i]y_test = (y_score >= th)acc = np.mean((y_test == y_true).astype(int))if acc > best_acc:best_acc = accbest_th = threturn (best_acc, best_th)def test_performance(fe_dict, pair_list):with open(pair_list, 'r') as fd:pairs = fd.readlines()sims = []labels = []for pair in pairs:splits = pair.split()fe_1 = fe_dict[splits[0]]fe_2 = fe_dict[splits[1]]label = int(splits[2])sim = cosin_metric(fe_1, fe_2)sims.append(sim)labels.append(label)acc, th = cal_accuracy(sims, labels)return acc, thdef lfw_test(model, img_paths, identity_list, compair_list, batch_size):s = time.time()features, cnt = get_featurs(model, img_paths, batch_size=batch_size)#print(features.shape)t = time.time() - s#print('共用时间 {}, average time is {}'.format(t, t / cnt))fe_dict = get_feature_dict(identity_list, features)acc, th = test_performance(fe_dict, compair_list)print('准确率: ', acc, '阀值: ', th)return acc
opt = Config()
model = resnet_face18(opt.use_se)
#采用多GPU的数据并行处理机制
model = DataParallel(model)
#装载预训练模型
model.load_state_dict(torch.load(opt.test_model_path))
model.to(device)identity_list = get_lfw_list(opt.lfw_test_list)
img_paths = [os.path.join(opt.lfw_root, each) for each in identity_list]model.eval()
lfw_test(model, img_paths, identity_list, opt.lfw_test_list, opt.test_batch_size)

#img_path='/home/wumg/data/data/other_my_face_align/others/Wen_Jiabao/Wen_Jiabao_0002.jpg'
img_path='/home/wumg/data/data/other_my_face_align/others/my/myf241.jpg'
#img_path='/home/wumg/data/data/dataset/lfw/lfw-align-128/Wen_Jiabao/Wen_Jiabao_0002.jpg'
image = cv2.imread(img_path, 0)
if image is None:print("ok")image = np.dstack((image, np.fliplr(image)))
image = image.transpose((2, 0, 1))
image = image[:, np.newaxis, :, :]
image = image.astype(np.float32, copy=False)
image -= 127.5
image /= 127.5image.shape

from __future__ import print_function
import os
import cv2
from models import *
import torch
import numpy as np
import time
#from config import Config
from torch.nn import DataParalleldef get_lfw_list(pair_list):with open(pair_list, 'r') as fd:pairs = fd.readlines()data_list = []for pair in pairs:splits = pair.split()if splits[0] not in data_list:data_list.append(splits[0])if splits[1] not in data_list:data_list.append(splits[1])return data_listdef load_image(img_path):image = cv2.imread(img_path, 0)if image is None:return Noneimage = np.dstack((image, np.fliplr(image)))image = image.transpose((2, 0, 1))image = image[:, np.newaxis, :, :]image = image.astype(np.float32, copy=False)image -= 127.5image /= 127.5return imagedef get_featurs(model, test_list, batch_size=10):images = Nonefeatures = Nonecnt = 0for i, img_path in enumerate(test_list):image = load_image(img_path)if image is None:print('read {} error'.format(img_path))if images is None:images = imageelse:images = np.concatenate((images, image), axis=0)if images.shape[0] % batch_size == 0 or i == len(test_list) - 1:cnt += 1data = torch.from_numpy(images)data = data.to(torch.device("cuda"))output = model(data)output = output.data.cpu().numpy()fe_1 = output[::2]fe_2 = output[1::2]feature = np.hstack((fe_1, fe_2))# print(feature.shape)if features is None:features = featureelse:features = np.vstack((features, feature))images = Nonereturn features, cntdef load_model(model, model_path):model_dict = model.state_dict()pretrained_dict = torch.load(model_path)pretrained_dict = {k: v for k, v in pretrained_dict.items() if k in model_dict}model_dict.update(pretrained_dict)model.load_state_dict(model_dict)def get_feature_dict(test_list, features):fe_dict = {}for i, each in enumerate(test_list):# key = each.split('/')[1]fe_dict[each] = features[i]return fe_dictdef cosin_metric(x1, x2):return np.dot(x1, x2) / (np.linalg.norm(x1) * np.linalg.norm(x2))def cal_accuracy(y_score, y_true):y_score = np.asarray(y_score)y_true = np.asarray(y_true)best_acc = 0best_th = 0for i in range(len(y_score)):th = y_score[i]y_test = (y_score >= th)acc = np.mean((y_test == y_true).astype(int))if acc > best_acc:best_acc = accbest_th = threturn (best_acc, best_th)def test_performance(fe_dict, pair_list):with open(pair_list, 'r') as fd:pairs = fd.readlines()sims = []labels = []for pair in pairs:splits = pair.split()fe_1 = fe_dict[splits[0]]fe_2 = fe_dict[splits[1]]label = int(splits[2])sim = cosin_metric(fe_1, fe_2)sims.append(sim)labels.append(label)acc, th = cal_accuracy(sims, labels)return acc, thdef lfw_test(model, img_paths, identity_list, compair_list, batch_size):s = time.time()features, cnt = get_featurs(model, img_paths, batch_size=batch_size)print(features.shape)t = time.time() - sprint('total time is {}, average time is {}'.format(t, t / cnt))fe_dict = get_feature_dict(identity_list, features)acc, th = test_performance(fe_dict, compair_list)print('lfw face verification accuracy: ', acc, 'threshold: ', th)return accif __name__ == '__main__':opt = Config()if opt.backbone == 'resnet18':model = resnet_face18(opt.use_se)elif opt.backbone == 'resnet34':model = resnet34()elif opt.backbone == 'resnet50':model = resnet50()model = DataParallel(model)# load_model(model, opt.test_model_path)model.load_state_dict(torch.load(opt.test_model_path))model.to(torch.device("cuda"))identity_list = get_lfw_list(opt.lfw_test_list)img_paths = [os.path.join(opt.lfw_root, each) for each in identity_list]model.eval()lfw_test(model, img_paths, identity_list, opt.lfw_test_list, opt.test_batch_size)

人脸检测、人脸定位、人脸对齐、MTCNN、人脸识别(衡量人脸的相似或不同:softmax、三元组损失Triplet Loss、中心损失Center Loss、ArcFace)相关推荐

  1. AI人工智能分析-人脸识别和分析(人脸检测跟踪、获取特征长度、提取用于人脸特征、比较相似度)

             AI人工智能分析-人脸识别和分析(人脸检测跟踪.获取特征长度.提取用于人脸特征.比较相似度) 人工智能(Artificial Intelligence),英文缩写为AI.它是研究.开 ...

  2. 人脸检测(十四)--MTCNN

    本文来自于中国科学院深圳先进技术研究院,目前发表在arXiv上,是2016年4月份的文章,算是比较新的文章.红色表示我在复现测试时的重要点. 论文地址: https://kpzhang93.githu ...

  3. 《数字图像处理》dlib人脸检测获取关键点,delaunay三角划分,实现人脸的几何变换warpping,接着实现两幅人脸图像之间的渐变合成morphing

    这学期在上<数字图像处理>这门课程,老师布置了几个大作业,自己和同学一起讨论完成后,感觉还挺有意思的,就想着把这个作业整理一下 : 目录 1.实验任务和要求 2.实验原理 3.实验代码 3 ...

  4. Python人工智能实例 │ 使用Haar级联进行人脸检测、使用CAMShift算法、光流法进行人脸追踪

    使用Haar级联进行人脸检测 使用CAMShift算法进行人脸追踪 使用光流法进行人脸追踪 01.背景知识 1.1●Haar级联简介 Haar级联是基于Haar特征的级联分类器.那么级联分类器是什么? ...

  5. AI人脸检测智能分析网关新增车辆检测/车牌识别,支持车辆违停告警

    AI人脸检测/口罩检测智能分析网关是一款基于AI边缘计算的智能分析硬件设备,内置多种AI深度学习算法,支持对视频监控场景中的人.车.物.行为等进行抓拍.检测与识别,对异常情况进行实时告警等,可广泛应用 ...

  6. 第十七天 MTCNN 人脸检测+关键点定位 从0开始搭建 (补充中)

    源码下载:这里采用的MTCNND的tensorflow的源码 <作者是用caffe做的,下面的是修改版的> git clone https://github.com/AITTSMD/MTC ...

  7. 人脸检测颜值源代码python_50行Python代码识别杨超越的颜值

    行哥又又又又拿杨超越做封面了,只因为昨天群里有小伙伴想学下人脸识别 但是如果要详细介绍的话,那这个故事得从opencv的那个夏天说起,对于python小白来说,门槛有点高.所以行哥今天先给大家介绍一个 ...

  8. 人脸系列:人脸检测、人脸关键点定位、人脸优选、人脸对齐、人脸特征提取、人脸跟踪、人脸活体检测

    一.一点想法 缘由:最近想整理下从事人脸方向的所有查阅过的论文,做过的相关实验,因为随着时间的推移,自己总会遗忘当初的一些想法,所以想好好整理下自己的学习笔记. 过程:本系列包括从人脸检测.人脸关键点 ...

  9. 家庭服务机器人的人脸检测、跟踪与识别研究

    摘要:本文介绍了一个用于家庭服务机器人完成人脸检测.跟踪.识别的双目视觉系统.该系统首先采用人脸肤色模型结合相似度来检测人脸:然后通过基于颜色信息的CAMSHIFT算法跟踪运动的人脸:最后利用嵌入式隐 ...

最新文章

  1. VS2008中配置 Windows SDK v7
  2. [Electron]仿写一个课堂随机点名小项目
  3. nginx 电子书_13本免费的电子书,拿走,不谢
  4. php如何查看上传的文件大小,PHP设置最大上传文件大小
  5. c++ opencv mat_实战 | OpenCV 实现多张图像拼接
  6. 驾驭大数据,全民打飞机(转)
  7. Spring核心——MessageSource实现国际化
  8. 免校准的电量计量芯片_电能计量芯片应用心得之选型篇
  9. shardingsphere5.0 解决第一次执行sql慢的问题
  10. CPU卡指令文件读取算法
  11. win10 软路由_超小软路由Nanopi R2S折腾记
  12. php取微信名字和头像,微信小程序如何获取用户头像和昵称
  13. Coinversation Protocol (铸币协议)简版白皮书及网站
  14. Sap Program 自动创建供应商资料,BP
  15. STM32(六)——串口通信原理
  16. 【Altium designer】走线、线条绘制多边形如何切换直角 / 45度 / 圆弧
  17. C/C++数学计算库
  18. C盘不够用-删除D盘空间贡献给C盘的简单方法
  19. 忆阻器课题 读书笔记(二)
  20. 华为服务器系统蓝屏,云服务器蓝屏

热门文章

  1. 2-系统配置与性能评价
  2. 凝思操作系统ip配置文件interfaces与实际IP不符
  3. android:添加usb键盘+按键布局和映射的修改
  4. 如何解决Chrome浏览器无法安装插件的问题
  5. 通过CubeMX实现STM32的USB支持
  6. “数据泄露事件频发”折射数据安全问题,分布式数据存储势在必行
  7. Linux动态资源监控工具 glances
  8. 少轻狂电子图书制作教程之三:用软景HTML制造机生成网页文件
  9. 从Cortex-M33内核认识TrustZone
  10. 微信小程序内嵌h5页面或者跳转至外部链接,及在webview页面添加元素