1.server.py
from Nanodet import Predictor
from Nanodet import overlay_bbox_cv
import numpy as np
import os
import torch
import cv2
from nanodet.util import cfg, load_config, Logger
import flask
from flask import Flask, jsonify
app = Flask(__name__)
os.environ["CUDA_DEVICE_ORDER"]="PCI_BUS_ID"
os.environ["CUDA_VISIBLE_DEVICES"]="0"
device = torch.device('cuda')
torch.backends.cudnn.enabled = True
torch.backends.cudnn.benchmark = True
config_path = './config/nanodet-m-416.yml' # 更改为自己的yml文件路径
model_path = './nanodet/nanodet_m.pth' # 更改文自己的权重路径
load_config(cfg, config_path)
logger = Logger(-1, use_tensorboard=False)
predictor = Predictor(cfg, model_path, logger,device)
@app.route("/predict", methods=["POST"])
def predict():
result = {"success": False}
# 判断请求方式是否为post
if flask.request.method == "POST":
# 获取图片数据
if flask.request.files.get("image") is not None:
print("非空: ::::::::")
try:
input_image = flask.request.files["image"].read()
imBytes = np.frombuffer(input_image, np.uint8)
iImage = cv2.imdecode(imBytes, cv2.IMREAD_COLOR)
meta, res = predictor.inference(iImage)
allboxes = overlay_bbox_cv(res,score_thresh=0.35)
if (allboxes is None):
result["success"] = False
result['success'] = True
result["allboxes"] = allboxes
except Exception:
pass
return jsonify(result)
if __name__ == "__main__":
print(("* Loading Nanodet model and Flask starting server..."
"please wait until server has fully started"))
app.run(host='0.0.0.0', port=5000)
2.Nanodet.py
import os
import time
import torch
from nanodet.util import cfg, load_config, Logger
from nanodet.model.arch import build_model
from nanodet.util import load_model_weight
from nanodet.data.transform import Pipeline
os.environ["CUDA_DEVICE_ORDER"]="PCI_BUS_ID"
os.environ["CUDA_VISIBLE_DEVICES"]="0"
device = torch.device('cuda')
torch.backends.cudnn.enabled = True
torch.backends.cudnn.benchmark = True
class Predictor(object):
def __init__(self, cfg, model_path, logger, device='cuda:0'):
self.cfg = cfg
self.device = device
model = build_model(cfg.model)
ckpt = torch.load(model_path, map_location=lambda storage, loc: storage)
load_model_weight(model, ckpt, logger)
if cfg.model.arch.backbone.name == 'RepVGG':
deploy_config = cfg.model
deploy_config.arch.backbone.update({'deploy': True})
deploy_model = build_model(deploy_config)
from nanodet.model.backbone.repvgg import repvgg_det_model_convert
model = repvgg_det_model_convert(model, deploy_model)
self.model = model.to(device).eval()
self.pipeline = Pipeline(cfg.data.val.pipeline, cfg.data.val.keep_ratio)
def inference(self, img):
img_info = {}
img_info['file_name'] = None
height, width = img.shape[:2]
img_info['height'] = height
img_info['width'] = width
meta = dict(img_info=img_info,
raw_img=img,
img=img)
meta = self.pipeline(meta, self.cfg.data.val.input_size)
meta['img'] = torch.from_numpy(meta['img'].transpose(2, 0, 1)).unsqueeze(0).to(self.device)
with torch.no_grad():
results = self.model.inference(meta)
return meta, results
def overlay_bbox_cv(dets,score_thresh):
all_box = []
for label in dets:
for bbox in dets[label]:
score = bbox[-1]
if score>score_thresh:
x0, y0, x1, y1 = [int(i) for i in bbox[:4]]
all_box.append([label, x0, y0, x1, y1, score])
return all_box
client.py
import cv2
import requests
import numpy as np
from PIL import Image
def pros(all_box, img):
all_box.sort(key=lambda v: v[5])
for box in all_box:
label, x0, y0, x1, y1, score = box
# color = self.cmap(i)[:3]
color = (_COLORS[label] * 255).astype(np.uint8).tolist()
text = '{}:{:.1f}%'.format(class_names[label], score * 100)
txt_color = (0, 0, 0) if np.mean(_COLORS[label]) > 0.5 else (255, 255, 255)
font = cv2.FONT_HERSHEY_SIMPLEX
txt_size = cv2.getTextSize(text, font, 0.5, 2)[0]
cv2.rectangle(img, (x0, y0), (x1, y1), color, 2)
cv2.rectangle(img,
(x0, y0 - txt_size[1] - 1),
(x0 + txt_size[0] + txt_size[1], y0 - 1), color, -1)
cv2.putText(img, text, (x0, y0 - 1),
font, 0.5, txt_color, thickness=1)
return img
_COLORS = np.array(
[
0.000, 0.447, 0.741,
0.850, 0.325, 0.098,
0.929, 0.694, 0.125,
0.494, 0.184, 0.556,
0.466, 0.674, 0.188,
0.301, 0.745, 0.933,
0.635, 0.078, 0.184,
0.300, 0.300, 0.300,
0.600, 0.600, 0.600,
1.000, 0.000, 0.000,
1.000, 0.500, 0.000,
0.749, 0.749, 0.000,
0.000, 1.000, 0.000,
0.000, 0.000, 1.000,
0.667, 0.000, 1.000,
0.333, 0.333, 0.000,
0.333, 0.667, 0.000,
0.333, 1.000, 0.000,
0.667, 0.333, 0.000,
0.667, 0.667, 0.000,
0.667, 1.000, 0.000,
1.000, 0.333, 0.000,
1.000, 0.667, 0.000,
1.000, 1.000, 0.000,
0.000, 0.333, 0.500,
0.000, 0.667, 0.500,
0.000, 1.000, 0.500,
0.333, 0.000, 0.500,
0.333, 0.333, 0.500,
0.333, 0.667, 0.500,
0.333, 1.000, 0.500,
0.667, 0.000, 0.500,
0.667, 0.333, 0.500,
0.667, 0.667, 0.500,
0.667, 1.000, 0.500,
1.000, 0.000, 0.500,
1.000, 0.333, 0.500,
1.000, 0.667, 0.500,
1.000, 1.000, 0.500,
0.000, 0.333, 1.000,
0.000, 0.667, 1.000,
0.000, 1.000, 1.000,
0.333, 0.000, 1.000,
0.333, 0.333, 1.000,
0.333, 0.667, 1.000,
0.333, 1.000, 1.000,
0.667, 0.000, 1.000,
0.667, 0.333, 1.000,
0.667, 0.667, 1.000,
0.667, 1.000, 1.000,
1.000, 0.000, 1.000,
1.000, 0.333, 1.000,
1.000, 0.667, 1.000,
0.333, 0.000, 0.000,
0.500, 0.000, 0.000,
0.667, 0.000, 0.000,
0.833, 0.000, 0.000,
1.000, 0.000, 0.000,
0.000, 0.167, 0.000,
0.000, 0.333, 0.000,
0.000, 0.500, 0.000,
0.000, 0.667, 0.000,
0.000, 0.833, 0.000,
0.000, 1.000, 0.000,
0.000, 0.000, 0.167,
0.000, 0.000, 0.333,
0.000, 0.000, 0.500,
0.000, 0.000, 0.667,
0.000, 0.000, 0.833,
0.000, 0.000, 1.000,
0.000, 0.000, 0.000,
0.143, 0.143, 0.143,
0.286, 0.286, 0.286,
0.429, 0.429, 0.429,
0.571, 0.571, 0.571,
0.714, 0.714, 0.714,
0.857, 0.857, 0.857,
0.000, 0.447, 0.741,
0.314, 0.717, 0.741,
0.50, 0.5, 0
]
).astype(np.float32).reshape(-1, 3)
class_names = ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic_light', 'fire_hydrant', 'stop_sign', 'parking_meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard', 'sports_ball', 'kite', 'baseball_bat', 'baseball_glove', 'skateboard', 'surfboard', 'tennis_racket', 'bottle', 'wine_glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', 'hot_dog', 'pizza', 'donut', 'cake', 'chair', 'couch', 'potted_plant', 'bed', 'dining_table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell_phone', 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy_bear', 'hair_drier', 'toothbrush']
# 将图像以jpg编码,并转换为字节流
def get_img_bytes(img):
img_str = cv2.imencode('.jpg', img)[1].tobytes() if img is not None else None
return img_str
def cv2_imshow(a, convert_bgr_to_rgb=True):
"""A replacement for cv2.imshow() for use in Jupyter notebooks.
Args:
a: np.ndarray. shape (N, M) or (N, M, 1) is an NxM grayscale image. shape
(N, M, 3) is an NxM BGR color image. shape (N, M, 4) is an NxM BGRA color
image.
convert_bgr_to_rgb: switch to convert BGR to RGB channel.
"""
a = a.clip(0, 255).astype('uint8')
# cv2 stores colors as BGR; convert to RGB
if convert_bgr_to_rgb and a.ndim == 3:
if a.shape[2] == 4:
a = cv2.cvtColor(a, cv2.COLOR_BGRA2RGBA)
else:
a = cv2.cvtColor(a, cv2.COLOR_BGR2RGB)
# display(Image.fromarray(a))
# cv2.imshow("", np.uint8(Image.fromarray(a)))
# cv2.waitKey(0)
return np.uint8(Image.fromarray(a))
def main(image_path,URL = 'http://xxx.xxx.x.xx:5000/predict'):
'''
image_path:图片的路径
URL:服务器的IP地址
'''
image = open(image_path, 'rb').read()
# Opencv读取方便展示结果
img = cv2.imread(image_path)
payload = {'image': image}
# Post请求获取预测结果
result = requests.post(URL,files=payload).json()
if not result['success']:
print("没有发现目标,请输入一张正确的图片!!!")
else:
allboxes= result["allboxes"]
results = pros(allboxes,img)
img = cv2_imshow(results, False)
cv2.imshow("", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == '__main__':
#import os
#import time
#img_dir = "imgs"
# for img in os.listdir(img_dir):
# img_path = os.path.join(img_dir, img)
# main(img_path)
# # time.sleep(5)
image_path = "./1.jpg"
main(image_path)
预测结果:
参考资料: