当前位置:   article > 正文

基于pytorch与opencv简单做个人脸识别_pytorch 人脸识别

pytorch 人脸识别

环境准备

pytorch 2.0.0+cu117  (这个版本你们自己根据实际情况设置

opencv(注意不同版本的使用规则不同,一定要看官方文档,嫌麻烦跟我版本一致

opencv-contrib-python             4.7.0.72
opencv-python                     4.7.0.72

数据集

105_classes_pins_dataset

请在数据集中新建文件夹命名为,被训练的人名字与照片,图片样式(无遮挡)

请使用 jupyter notebook 

以上都准备好了,那就开始代码之旅叭~

代码

各类包导入

  1. import torch, torchvision
  2. import torchvision.transforms as transforms
  3. import torchvision.datasets as datasets
  4. import torchvision.models as models
  5. import torch.nn as nn
  6. import torch.optim as optim
  7. import torch.nn.init as init
  8. import torch.nn.functional as F
  9. import numpy as np
  10. from PIL import Image
  11. import matplotlib.pyplot as plt
  12. import torch.utils.data as D

数据集的读取与处理

  1. # 数据扩增方法(旋转、平移)一般都不会改变标签
  2. transformations = transforms.Compose([
  3. transforms.Resize((224, 224)),
  4. transforms.RandomHorizontalFlip(p=0.5),
  5. transforms.RandomRotation(5),
  6. transforms.ColorJitter(),
  7. transforms.ToTensor(),
  8. transforms.Normalize(mean=[0.485, 0.456, 0.406],
  9. std=[0.229, 0.224, 0.225])
  10. ])
  11. # 数据集获取并数据扩增
  12. trainfolder = datasets.ImageFolder('data/105_classes_pins_dataset/', transform=transformations)
  13. # 对数据集进行划分,每7个添加一次验证集
  14. train_idx = []
  15. val_idx = []
  16. for idx in range(len(trainfolder)):
  17. if idx % 7 == 0:
  18. val_idx.append(idx)
  19. else:
  20. train_idx.append(idx)
  21. # 图片的读取,(图片、类别)
  22. train_dataset = D.Subset(trainfolder, train_idx)
  23. val_dataset = D.Subset(trainfolder, val_idx)
  24. # 对应参数意思 一次 16 张图片,每个epoch重新打乱数据,多进程5个运行
  25. train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=16,
  26. shuffle=True, num_workers=5)
  27. test_loader = torch.utils.data.DataLoader(val_dataset, batch_size=16,
  28. num_workers=5)
  29. # 查看分了多少类
  30. trainfolder.classes

模型构建

  1. # res-net18做预训练模型
  2. model = models.resnet18(pretrained=True)
  3. # 将全连接层改为(512, cls_num) 根据预测类别个数实际填充,我的数据集裁剪过
  4. model.fc = nn.Linear(512, 6)
  5. # 启用gpu
  6. device = torch.device("cuda")
  7. # 将模型加载进gpu
  8. model = model.to(device)
  9. # res-net18模型采用交叉熵损失
  10. criterion = nn.CrossEntropyLoss()
  11. # 使用Adam优化器,lr学习率
  12. optimizer = optim.Adam(model.parameters(), lr=0.001)

模型训练与验证

  1. # 训练
  2. def train(model, device, train_loader, optimizer, epoch):
  3. model.train() # 转为训练,dropout起作用
  4. for batch_idx, (data, target) in enumerate(train_loader):
  5. # 如果在gpu运行,则需要将数据传输到GPU
  6. data, target = data.to(device), target.to(device)
  7. optimizer.zero_grad() # 清空梯度
  8. # 所有计算,都需要在相同的设备进行计算
  9. # 如果model 在gpu,则data也要在gpu
  10. output = model(data) # 正向传播
  11. loss = criterion(output, target) # 计算损失
  12. loss.backward() # 梯度计算
  13. optimizer.step() # 参数更新
  14. # 训练100个打印一次
  15. if batch_idx % 100 == 0:
  16. print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
  17. epoch,
  18. batch_idx * len(data), # 已经训练的样本个数
  19. len(train_loader.dataset), # 所有训练集样本个数
  20. 100. * batch_idx / len(train_loader), # 训练batch / 所有batch计数
  21. loss.item() # 当前batch的损失
  22. ))
  23. # 测试
  24. def test(model, device, test_loader):
  25. model.eval() # 转为预测,drop不起作用
  26. test_loss = 0
  27. correct = 0
  28. # 下面不需要计算梯度,只需要正向传播
  29. with torch.no_grad():
  30. for data, target in test_loader:
  31. data, target = data.to(device), target.to(device)
  32. output = model(data) # 原始输出的数值
  33. test_loss += criterion(output, target).sum(0).item()
  34. output = F.softmax(output) # 转为概率
  35. pred = output.argmax(dim=1, keepdim=True) # 获得最大值
  36. correct += pred.eq(target.view_as(pred)).sum().item() # 准确率
  37. # 每个样本的分类损失
  38. test_loss /= len(test_loader.dataset)
  39. print('Test set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
  40. test_loss, # 样本分类损失
  41. correct, # 分类正确的样本个数
  42. len(test_loader.dataset), # 测试集总共的样本的个数
  43. 100. * correct / len(test_loader.dataset) # 测试集样本的分类准确率
  44. ))
  45. # 学习率调整策略
  46. scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.3)
  47. # 开始训练模型
  48. for epoch in range(1, 10):
  49. train(model, device, train_loader, optimizer, epoch)
  50. test(model, device, test_loader)
  51. scheduler.step()

最后一步预测!(这里放个单张图片预测)

  1. # 读入图像(自己改)
  2. img = Image.open('data/test.jpg')
  3. # 读取类别
  4. trainfolder = datasets.ImageFolder('data/105_classes_pins_dataset/',transform=transformations)
  5. cls_img = trainfolder.classes
  6. print(cls_img)
  7. # 转换图像
  8. transformations = transforms.Compose([
  9. transforms.Resize((224, 224)),
  10. transforms.ToTensor(),
  11. transforms.Normalize(mean=[0.485, 0.456, 0.406],
  12. std=[0.229, 0.224, 0.225])
  13. ])
  14. img = transformations(img)
  15. img = img.unsqueeze(0) # 将数据增加一维,成为 1 x C x H x W 的格式
  16. img = img.to(device)
  17. # 预测结果输出
  18. output = model(img)
  19. _, predicted = torch.max(output.data, 1)
  20. # 类别打印
  21. print(cls_img[predicted.item()])

视频流识别

  1. # 读取类别
  2. trainfolder = datasets.ImageFolder('data/105_classes_pins_dataset/', transform=transformations)
  3. cls_img = trainfolder.classes
  4. print(cls_img)
  5. # 转换图像
  6. transformations = transforms.Compose([
  7. transforms.Resize((224, 224)),
  8. transforms.ToTensor(),
  9. transforms.Normalize(mean=[0.485, 0.456, 0.406],
  10. std=[0.229, 0.224, 0.225])
  11. ])
  12. # cv4.7 废弃:cv2.CascadeClassifier('./haarcascade_frontalface_alt2.xml')
  13. # 加载人脸识别模型
  14. face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml")
  15. # 打开摄像头
  16. cap = cv2.VideoCapture(r"data/face_test.mp4")
  17. while True:
  18. # 读取摄像头中的图像
  19. ret, frame = cap.read()
  20. if ret:
  21. # 对图像进行人脸检测
  22. height, width = frame.shape[:2]
  23. # 预测
  24. img = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
  25. img = transformations(img)
  26. img = img.unsqueeze(0) # 将数据增加一维,成为 1 x C x H x W 的格式
  27. img = img.to(device)
  28. output = model(img)
  29. _, predicted = torch.max(output.data, 1)
  30. # 将显示图像大小缩小一半
  31. new_height, new_width = int(height / 2), int(width / 2)
  32. frame = cv2.resize(frame, (new_width, new_height), interpolation=cv2.INTER_LINEAR)
  33. # 识别
  34. gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
  35. faces = face_cascade.detectMultiScale(gray, 1.3, 5)
  36. # 类别文本
  37. text = ""+str(cls_img[predicted])
  38. # 在图像中标记人脸区域
  39. for (x, y, w, h) in faces:
  40. cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 255), 2)
  41. cv2.putText(frame, text, (x, y), cv2.FONT_HERSHEY_SIMPLEX, 1.5, (0, 0, 255), 2)
  42. # 显示处理后的图像
  43. cv2.imshow('frame', frame)
  44. # 如果按下 q 键,则退出程序
  45. if cv2.waitKey(1) & 0xFF == ord('q'):
  46. break
  47. else:
  48. break
  49. # 释放摄像头资源
  50. cap.release()
  51. # 关闭所有窗口
  52. cv2.destroyAllWindows()

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/729928
推荐阅读
相关标签
  

闽ICP备14008679号