文章目录
1. 系统的环境
需要的环境
- python 3.6+
- 相关的库
https://github.com/zk2ly/Smoke_Fire_Detection
用于火焰检测的三方库文件- opencv-python 3.4.4.19 这个版本不宜过高,否则可能报错
- torch 1.8.1
- numpy 版本无所谓
- 数据库使用项目自带的sqlite(mysql部分使用麻烦,没使用)
- 其他环境
- 百度AI的人脸识别接口
- 正版pycharm (没有也可以直接修改文件,使用命令行运行)
2. 项目的结构
使用了Django进行开发(比spring boot什么的简单多了),项目结构即经典的Django项目结构,最常用的几个文件如下:
- view.py 相当于controller,如果没有三层结构里面可以写数据操作和逻辑代码
- url 相当于xml的映射文件,把前端的请求url映射到view.py中的类或者方法中。
- model 建立数据库的entity
- settings 系统的配置文件,包括数据库的选用,一些默认路径的映射等。
其他结构介绍
- utils 就是自己写的方法包括人脸识别、用户验证码和火焰检测的代码
- static和template是网页的相关内容
- migration 是数据库迁移的内容,建表后自动生成
- service 是自己写的文件夹,但是只作为测试使用,并未真正的前后端分离
static 中的fire和img 是系统保存火焰图片和系统录像的文件夹
3. 部署
由于本人的懒惰,把项目放在带有中文名的文件夹中不想移动,所以使用了不少绝对路径,如果有需要可以进行修改。
接下来先说使用pycharm运行项目的过程,然后是一些路径问题
3.1 pycharm 导入项目
- 使用pycharm打开项目
- 配置项目的解释器 file -> settings ->搜索project Interpreter
- 点击设置 -> add -> 选择自己的python.exe,(new 还是 exit都可以)
4. 如果没有自动导入Django就手动导入
5. 手动导入时候按照以下步骤,其中4 url可以修改成http://127.0.0.1:8000/firstWEB/login
直接进入登录页面,不改也可以,这个是项目默认的运行地址。
到这pycharm 的导入就完成了。剩下说一下需要修改的绝对路径问题
3.2 路径问题
3.2.1 人脸识别登录方面
- 在项目中utils 中的faceRecgnize中需要百度AI的账户信息
def createCli():
""" 你的 APPID AK SK """
APP_ID = ''
API_KEY = ''
SECRET_KEY = ''
client = AipFace(APP_ID, API_KEY, SECRET_KEY)
return client
- 这个方法中需要个人头像照片,其路径为
imgpath
def faceRcn(face):
client = createCli()
# img = open('1.jpeg', 'rb').read()
# bimg1 = base64.b64encode(img)
# jimg1 = str(bimg1,'utf-8')
# img = open('2.jpeg', 'rb').read()
# bimg2 = base64.b64encode(img)
# jimg2 = str(bimg2,'utf-8')
imgpath = 'F:\\各种文件\\pythonFile\\Web\\web\\firstWEB\\utils\\1.jpg'
这种是单人登录,如果想要多人登录,可以写一个数组放入图片路径,
循环来进行调用接口,判断是否有图片与采取到的用户人脸的相似度大于某一个特定
值,如果有则登录成功。
这里只写想法,由于只是一个demo性的系统所以没有实现。
3.2.2 火焰检测方面
由于将第三方库直接放入项目中会编译出错,所以使用了系统调用的方法来进行火焰的识别。流程为:
- 先将视频提取的图片存入img_name
- 使用系统调用传递 img_name,之后第三方库读取、识别图片存回
为了简单起见,此处这两个路径我都写的绝对路径
注意1
由于第三方库文件中我使用了imread读取内容,所以img_name一定不能有中文名
注意2
如果不想修改此处,需要在f盘下建立fireD文件夹
注意3
cmd python后面是第三方库文件的绝对路径
def getSolveImg(img, name) : # 图片就是前端的图片, img_name是刚获取图片之后的保存路径(文件读取路径),新的保存路径应该放在fire里面
# img = cv2.imread(img_name) #要么直接读取,要么经过编码,这里是直接读取
# 想一想怎么改成相对路径
img_name = 'F:\\fireD\\' + str(name) + '.jpg' #读取路径
cmd = "python F:\\各种文件\\pythonFile\\Web\\Smoke_Fire_Detection-main\\smoke_file_obj.py --img_name " + img_name
# print(cmd)
a = os.popen(cmd)
第三方库文件 smoke_file_obj.py需要把第一行中的weight修改成绝对路径,否则有可能找不到文件,可以有中文名
default=r'F:\各种文件\pythonFile\Web\Smoke_Fire_Detection-main\weights\smoke.pt'
另外,第三方库的修改文件代码
我使用了系统调用,所以需要main和solve函数
另外电脑GPU掉用不成功修改成这个代码det = det.to(device).data.cpu().numpy()
import argparse
import base64
from models.experimental import *
from utils.datasets import *
from utils.general import *
from utils import torch_utils
import sys
class Smoke_File_Detector():
def __init__(self):
parser = argparse.ArgumentParser()
parser.add_argument('--weights', nargs='+', type=str, default=r'F:\各种文件\pythonFile\Web\Smoke_Fire_Detection-main\weights\smoke.pt', help='model.pt path(s)')
parser.add_argument('--source', type=str, default='inference/images', help='source') # file/folder, 0 for webcam
parser.add_argument('--img-size', type=int, default=640, help='inference size (pixels)')
parser.add_argument('--conf-thres', type=float, default=0.25, help='object confidence threshold')
parser.add_argument('--iou-thres', type=float, default=0.45, help='IOU threshold for NMS')
parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --class 0, or --class 0 2 3')
parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS')
parser.add_argument('--augment', action='store_true', help='augmented inference')
parser.add_argument('--img_name', type=str)
self.opt = parser.parse_args()
self.device = torch_utils.select_device(self.opt.device)
# Initialize
self.half = self.device.type != 'cpu' # half precision only supported on CUDA
# Load models
self.model = attempt_load(self.opt.weights, map_location=self.device)
self.imgsz = check_img_size(self.opt.img_size, s=self.model.stride.max())
if self.half:
self.model.half()
# 本地调用
def detect_test(self,test_list):
for i,img in enumerate(test_list):
im0 = img
img = letterbox(img, new_shape=self.opt.img_size)[0]
img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416
img = np.ascontiguousarray(img) # faster
# Run inference
img = torch.from_numpy(img).to(self.device)
img = img.half() if self.half else img.float() # uint8 to fp16/32
img /= 255.0 # 0 - 255 to 0.0 - 1.0
if img.ndimension() == 3:
img = img.unsqueeze(0)
if i == 0:
batch_img = img
else:
batch_img = torch.cat([batch_img,img],axis = 0)
pred = self.model(batch_img, augment=self.opt.augment)[0]
# Apply NMS
pred = non_max_suppression(pred, self.opt.conf_thres, self.opt.iou_thres, classes=self.opt.classes, agnostic=self.opt.agnostic_nms)
# Process detections
names = self.model.module.names if hasattr(self.model, 'module') else self.model.names
batch_results = []
for i, det in enumerate(pred): # detections per image
results = []
if det is not None and len(det):
# Rescale boxes from img_size to im0 size
det[:, :4] = scale_coords(batch_img.shape[2:], det[:, :4], im0.shape).round()
device = ('cuda' if torch.cuda.is_available() else 'cpu')
det = det.to(device).data.cpu().numpy()
for *xyxy, conf, cls in det:
w = xyxy[2]-xyxy[0]
h = xyxy[3]-xyxy[1]
result = {'bbox':xyxy, 'label':names[int(cls)], 'conf':conf}
results.append(result)
batch_results.append(results)
# print(batch_results)
return batch_results
# server调用
def detect(self, **kwargs):
params = kwargs
test_list = [params["img"]]
for i,img in enumerate(test_list):
im0 = img
img = letterbox(img, new_shape=self.opt.img_size)[0]
img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416
img = np.ascontiguousarray(img)
# Run inference
img = torch.from_numpy(img).to(self.device)
img = img.half() if self.half else img.float() # uint8 to fp16/32
img /= 255.0 # 0 - 255 to 0.0 - 1.0
if img.ndimension() == 3:
img = img.unsqueeze(0)
if i == 0:
batch_img = img
else:
batch_img = torch.cat([batch_img,img],axis = 0)
pred = self.model(batch_img, augment=self.opt.augment)[0]
# Apply NMS
pred = non_max_suppression(pred, self.opt.conf_thres, self.opt.iou_thres, classes=self.opt.classes, agnostic=self.opt.agnostic_nms)
# Process detections
names = self.model.module.names if hasattr(self.model, 'module') else self.model.names
batch_results = []
for i, det in enumerate(pred): # detections per image
results = []
if det is not None and len(det):
# Rescale boxes from img_size to im0 size
det[:, :4] = scale_coords(batch_img.shape[2:], det[:, :4], im0.shape).round()
device = ('cuda' if torch.cuda.is_available() else 'cpu')
det = det.to(device).data.cpu().numpy()
for *xyxy, conf, cls in det:
w = xyxy[2]-xyxy[0]
h = xyxy[3]-xyxy[1]
result = {'bbox':xyxy, 'label':names[int(cls)], 'conf':conf}
results.append(result)
batch_results.append(results)
# print(batch_results)
return batch_results
# 返回框好的图片
def solveFireImg(self, img, img_name):
ls = self.detect_test([img])[0]
# print(ls)
flag = False
for dic in ls:
flag = True
if(dic['label'] == 'fire'):
rec = dic['bbox']
cv2.rectangle(img, (int(rec[0]), int(rec[1])), (int(rec[2]), int(rec[3])), (0, 255, 0), 3)
if(dic['label'] == 'smoke'):
rec = dic['bbox']
cv2.rectangle(img, (int(rec[0]), int(rec[1])), (int(rec[2]), int(rec[3])), (0, 0, 255), 3)
if(flag) : #有火焰,保存图片
cv2.imwrite(img_name, img) # 使用传入的参数自动覆盖原来的图片
return img
if __name__ == "__main__":
import cv2
img_name = sys.argv[2]
img = cv2.imread(img_name)
det = Smoke_File_Detector()
arr = det.detect_test([img])[0]
print(arr)
# content = det.solveFireImg(img, img_name)
# # cv2.imshow('test', content)
# # cv2.waitKey(0)
# # 保存图片
# t = time.time()
# # name = int(round(t * 1000))
# # img_name='F:\\img\\'+str(name)+'.jpg'
# img1 = cv2.imencode('.jpg', content)[1]
# back_2 = base64.b64encode(img1)
# back_3 = str(back_2, encoding="utf-8")
# print(back_3, end="")
"""以下的内容一定要注释掉"""
#测试保存的明亮航参数保存图片
# img_name = sys.argv[2]
# print(type(back_2))
# print("图片")
# print(img_name)
# cv2.imwrite(img_name, content)
# 测试如果直接输出会怎么样
另外火焰图片存储在了static/fire文件夹中,如果修改此处,需要修改许多地方,不建议修改,同时使用了相对路径,也无需修改。
3.3.3 视频回放的存储路径
由于此处使用了相对路径,所以不进行过多的叙述,同火焰图片存放有相同的道理,不建议修改。