tornado page deployment (YOLOV5)


foreword

This article will lead you to use tornado to build AI services. Compared with tornado and flask, I personally prefer tornado. For details, please refer to the following articles: Article 1
Article
2


1. Installation

The installation is very simple, just like flask, just pip directly, provided that you have a python environment on your computer

pip install tornado

2. Deployment service

Here we directly take YOLOV5 as an example. The official link is: YOLOV5 . The version I use may be a bit old, but it will basically not affect it, as long as the model you download corresponds to your code version. Then, rebuild a py file ( suggestion ) or comment all the code in detect.py in yolov5, and then add the following code:

import torch
import cv2,base64
import numpy as np
from utils.general import check_img_size, non_max_suppression,scale_coords
from utils.augmentations import letterbox
import os,time
from pathlib import Path
from utils.plots import Annotator,colors
from models.experimental import attempt_load
import sys,json
FILE = Path(__file__).resolve()
ROOT = FILE.parents[0]  # YOLOv5 root directory
if str(ROOT) not in sys.path:
    sys.path.append(str(ROOT))  # add ROOT to PATH
ROOT = Path(os.path.relpath(ROOT, Path.cwd()))  # relative

import tornado.web
import tornado.ioloop


#版面分析
def run(img,img_path,models,save_path,device,model_path,dnn=False):
    '''
    img: 图片数据
    img_path: 图片路径(便于储存结果)
    weights: 模型
    save_path: 结果保存路径
    device: 运行设备
    model_path: 模型路径
    dnn: 模型加载方式
    '''
    imgsz=640 #图片大小
    #阈值设置
    conf_thres=0.25
    iou_thres=0.45
    old_img=img.copy()

    half =device.type != "cpu" #当设备为cuda时,半精度推理

    w = str(models[0] if isinstance(models, list) else models) #onnx时会用
    model_suffixes=model_path.split(".")[-1] #当前模型的后缀名
    stride,names=64,[f'class{
      
      i}'for i in range(1000)]

    flag=True #为True表示pt模型,为Falase表示为onnx模型
    #用于控制模型后缀,模型后缀不同决定了输入尺寸的不同(onnx为(640,640))
    if model_suffixes=="pt":
        model=models
        stride = int(model.stride.max())  # model stride
        names = model.module.names if hasattr(model, 'module') else model.names  # get class names
        if half:
            model.half()  # to FP16
        flag=False
    elif model_suffixes=="onnx":
        if dnn:
            # check_requirements(('opencv-python>=4.5.4',))
            net = cv2.dnn.readNetFromONNX(w)
        else:
            # check_requirements(('onnx', 'onnxruntime-gpu' if torch.has_cuda else 'onnxruntime'))
            import onnxruntime
            session = onnxruntime.InferenceSession(w, None)
        flag=True
    imgsz=check_img_size(imgsz,s=stride)

    #resize_padding
    img=letterbox(img,imgsz,stride,auto=flag)[0]
    img = img.transpose((2, 0, 1))[::-1]  # HWC to CHW, BGR to RGB

    img = np.ascontiguousarray(img)

    if model_suffixes=="onnx":
        img=img.astype("float32")
    else:
        img=torch.from_numpy(img).to(device)
        img=img.half() if half else img.float()

    img /=255.0
    if len(img.shape)==3:
        img=img[None]

    if model_suffixes=="pt":
        pred=model(img)[0]
    elif model_suffixes=="onnx":
        if dnn:
            net.setInput(img)
            pred=torch.tensor(net.forward())
        else:
            pred=torch.tensor(session.run([session.get_outputs()[0].name],{
    
    session.get_inputs()[0].name:img}))
    pred=non_max_suppression(pred,conf_thres,iou_thres,classes=None,agnostic=False,max_det=1000)

    for i,det in enumerate(pred):
        im0=old_img.copy()
        annotator = Annotator(im0, line_width=3, example=str(names))
        if len(det):
            det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round()
            for *xyxy,conf,cls in reversed(det):
                c=int(cls)
                label =  f'{
      
      names[c]} {
      
      conf:.2f}'
                annotator.box_label(xyxy,label,color=colors(c,True))
        im0 = annotator.result()

        # cv2.imwrite(save_path+os.sep+Path(img_path).name,im0)

    return im0


class DetectImage(object):
    def __init__(self,model_path):
        '''
        :param  model_path: 模型路径
        '''
        self.model_path=model_path
        self.device= torch.device("cuda" if torch.cuda.is_available() else "cpu")
        self.model =  attempt_load(self.model_path, map_location=self.device)

        self.save_path=root_path+"/runs/layout_results"
        os.makedirs(self.save_path,exist_ok=True)


    def det(self,img_path,img_data):
        res=run(img_data,img_path,self.model,self.save_path,self.device,self.model_path)
        return res

def parse_parameters(byte_data):
    try:
        json_str = byte_data.decode('utf8')
        data = json.loads(json_str)
    except Exception as e:
        print("[parse_parameters]:error:", e)
        return None
    return data

def base64_to_cvimage(imgdata):
    try:
        imgstr = base64.b64decode(imgdata)
        nparr = np.fromstring(imgstr,np.uint8)
        image = cv2.imdecode(nparr,cv2.IMREAD_COLOR)
    except Exception as e:
        print("[base64_to_cvimage]:",e)
        return None
    return image

def cvimage_to_base64(image):
    try:
        image = cv2.imencode('.jpg', image)[1]
        image_base64 = str(base64.b64encode(image))[2:-1]
    except Exception as e:
        return None
    return image_base64


class MainHandler(tornado.web.RequestHandler):
    def post(self):
        s0=time.time()
        byte_data = self.request.body
        data = parse_parameters(byte_data)
        img_base64,imgpath,message=None,None,"success"
        if data==None:
            message="Data receiving error!"
        else:
            img_base64 = data["image"]
            imgpath=data["imgpath"]
        image=base64_to_cvimage(img_base64)
        if image.all()==None:
            message="base64_to_cvimage error!"

        try :
            result = detect.det(imgpath,image)
        except Exception as e:
            message="Detect error!"

        image_base64_=cvimage_to_base64(result)
        if image_base64_==None:
            message="cvimage2base64 error!"
        ocr_status={
    
    "imgpath":imgpath,"status":message,"result":image_base64_}
        json_res = json.dumps(ocr_status, ensure_ascii=False)
        self.write(json_res)


def main(port):
    app=tornado.web.Application([(r'/',MainHandler)],)
    app.listen(port)
    print("server start!")
    tornado.ioloop.IOLoop.instance().start()


if __name__ == '__main__':

    root_path=os.path.abspath(os.path.join(os.path.dirname(__file__),"."))
    detect=DetectImage(r"")#给定模型路径即可

    main(3080)

After the required dependencies are installed, just run the file directly. If server start appears , it means that the service has started successfully.

3. Call service

Create a new test.py and add the following code:

import cv2,base64
from pathlib import Path
import json,requests,glob,os
import numpy as np
def img_base64(img_path):
    with open(img_path, "rb") as f:
        base64_str = base64.b64encode(f.read())
    string = bytes.decode(base64_str)
    return string

def base64_to_cv(img_base64):
    try:
        imgstr = base64.b64decode(img_base64)
        nparr = np.fromstring(imgstr, np.uint8)
        image = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
    except Exception as e:
        return None
    return image


def test_once(path):
    img_data = img_base64(path)
    data = {
    
    "image": img_data, "imgpath": path}
    url = "http://ip:port" #指定ip:port
    res = requests.post(url, data=json.dumps(data))
    result=eval(res.text)
    if result["status"]=="success":
        image_base=result["result"]
        img=base64_to_cv(image_base)
        if img.all()==None:
            print("base64tocvimage Error !")
        else:
            return img
    else:
        print(result["status"])

if __name__ == '__main__':
    img_dir=r"" #图片文件夹 
    save_dir="./runs/det_res" #存储路径
    os.makedirs(save_dir,exist_ok=True)
    imglist=glob.glob(img_dir+os.sep+"*.jpg")
    for imgpath in imglist:
        res=test_once(imgpath)
        imgname=Path(imgpath).name
        savepath=os.path.join(save_dir,imgname)
        cv2.imwrite(savepath,res)
        print("Results saved to ",savepath)

Note: at line 24 of the file, the url in the test_once function gives your ip+port, and then run the file to call the service


Summarize

The above is the entire content of this article. Some of the content is not perfect. You need to add the functions you need. This is also a way to improve yourself. By the way, tell my friends, don't be proud of being able to run open source code (if it doesn't work, why do people hang it up), this should be the foundation of every algorithm engineer, and the real thing to be proud of is that your own open source project has been adopted by many people Use and star. Imagine that during your interview, the interviewer asks you: "You pull all these things from the Internet, and then train it, so where is your strength?", Would you say: "I can run through it quickly Open source code???” I personally think that we should always maintain a humble attitude and strive for progress. All of the above are based on feelings. If you have any questions, welcome to communicate in the comment area.

Guess you like

Origin blog.csdn.net/qq_55068938/article/details/128419758