1.AidLux介紹
1.AidLux是基于ARM架構(gòu)的跨生態(tài)(Android/鴻蒙+Linux)一站式AIoT應(yīng)用快速開(kāi)發(fā)和部署平臺(tái)APP
2.通過(guò)共享 Linux 內(nèi)核實(shí)現(xiàn)Android 和 Linux 生態(tài)融合田巴,為單一設(shè)備同時(shí)提供Android和Linux運(yùn)行環(huán)境
3.集成國(guó)際主流AI框架和多種開(kāi)發(fā)環(huán)境攀甚、后臺(tái)服務(wù)程序静陈、編譯器及圖形開(kāi)發(fā)組件僧免,無(wú)須配置開(kāi)箱即用,極大地簡(jiǎn)化了開(kāi)發(fā)步驟法希;自主研發(fā)的AI智能加速技術(shù)可實(shí)現(xiàn)CPU+GPU+NPU智能加速,大幅提高AI應(yīng)用運(yùn)行效率;平臺(tái)廣泛而深度的適配外設(shè)接口油啤,省去大量調(diào)試工作冗锁;內(nèi)置完整的跨平臺(tái)桌面和命令行終端連接(SSH)擂错,一個(gè)平臺(tái)完成多終端協(xié)同開(kāi)發(fā)子房、測(cè)試乎莉、部署
4.可使用APK包安裝方式快速部署在ARM架構(gòu)的手機(jī)健盒、平板、電腦和板卡等智能終端上
5.AidLux能廣泛應(yīng)用在智能工業(yè)、AI教育操骡、智慧人居炫彩、智慧城市、智慧物流、智慧交通低飒、智慧零售和機(jī)器人等諸多場(chǎng)景中
博主覺(jué)得田藐,AidLux最大的優(yōu)勢(shì)在于:常規(guī)Al應(yīng)用開(kāi)發(fā)需要C++、Java蜓肆、Python早芭、Linux等不同工程師相互配合武翎,而在AidLux平臺(tái)屠阻,開(kāi)發(fā)者僅需使用Python一種編程語(yǔ)言即可進(jìn)行開(kāi)發(fā)蝇闭,并支持將其他平臺(tái)(PC死嗦、服務(wù)器)上使用Python開(kāi)發(fā)的AI應(yīng)用直接遷移至AidLux調(diào)試運(yùn)行狼渊。
也就是說(shuō)我們只需要熟悉python語(yǔ)言即可尘执,再也不用學(xué)令人頭疼的C++了救崔!
2.環(huán)境搭建
2.1 手機(jī)版AidLux的安裝
目前使用Aidlux主要有兩種方式:
1.邊緣設(shè)備的方式:阿加犀用高通芯片的S855散怖,和S865制作了兩款邊緣設(shè)備惑申,一款提供7T算力具伍,一款提供15T算力。
2.手機(jī)設(shè)備的方式:沒(méi)有邊緣設(shè)備的情況下圈驼,也可以使用手機(jī)版本的Aidlux沿猜,嘗試邊緣設(shè)備的所有功能。
并且目前Aidlux已對(duì)基本市面上所有的芯片都進(jìn)行了適配碗脊,在手機(jī)上運(yùn)行算法模型啼肩,也可以體驗(yàn)優(yōu)化的效果。當(dāng)然在使用過(guò)程中衙伶,有個(gè)共同點(diǎn)祈坠,即手機(jī)設(shè)備和邊緣設(shè)備采用的Aidlux軟件,都是一樣的矢劲。因此可以先嘗試手機(jī)設(shè)備的方式赦拘,在后期需要更多算力的時(shí)候,使用邊緣設(shè)備芬沉,就可以無(wú)縫銜接躺同。所以我們先下載一下手機(jī)Aidlux的APP軟件。打開(kāi)安卓手機(jī)的應(yīng)用商城丸逸,搜索Aidlux即可下載安裝蹋艺。
?打開(kāi)手機(jī)版本的Aidlux軟件APP,第一次進(jìn)入的時(shí)候黄刚,APP自帶的系統(tǒng)會(huì)進(jìn)行初始化捎谨。
初始化好后,進(jìn)入系統(tǒng)登錄頁(yè)面,這一步最好可以用手機(jī)注冊(cè)一下涛救,當(dāng)然也可以直接點(diǎn)擊“我已閱讀并同意”畏邢,然后點(diǎn)擊跳過(guò)登錄。
注意:軟件獲取存儲(chǔ)權(quán)限后會(huì)有提示检吆,如果是安卓版本12的手機(jī)舒萎,請(qǐng)點(diǎn)擊確認(rèn),跟著提示完成相關(guān)步驟蹭沛,以便后續(xù)開(kāi)發(fā)逆甜。
?進(jìn)入主頁(yè)面后,可以點(diǎn)擊左上角的紅色叉號(hào)致板,將說(shuō)明頁(yè)面關(guān)閉交煞。
?為了方便編程,aidlux還提供了電腦接口(需要手機(jī)和電腦連接同一網(wǎng)絡(luò)):
?點(diǎn)擊下圖中的Cloud_ip斟或,即可顯示電腦鏈接
在電腦中輸入第一個(gè)網(wǎng)址即可素征,登陸時(shí)需要密碼,默認(rèn)密碼為:?aidlux
?登錄成功后可以發(fā)現(xiàn)萝挤,電腦的界面和手機(jī)端是同步的:
因此在開(kāi)發(fā)的時(shí)候我們將寫好的代碼上傳到文件中御毅,就可以利用VSCode運(yùn)行和調(diào)試?.
2.2 Aidlux軟件設(shè)置默認(rèn)后臺(tái)運(yùn)行
這里列舉了多款手機(jī)設(shè)置的方式,大家可以參照相應(yīng)的設(shè)置教程:
(1)小米手機(jī)和平板設(shè)置教程:https://community.aidlux.com/postDetail/832
(2)OPPO手機(jī)與平板設(shè)置教程:https://community.aidlux.com/postDetail/834
(3)vivo手機(jī)與平板設(shè)置教程:https://community.aidlux.com/postDetail/835
(4)華為鴻蒙/HarmonyOS 2.0設(shè)置教程:https://community.aidlux.com/postDetail/828
(5)華為鴻蒙/HarmonyOS 3.0設(shè)置教程:https://community.aidlux.com/postDetail/827
2.3 VSCode遠(yuǎn)程連接
?新建遠(yuǎn)程連接:config如圖所示怜珍,連接的密碼同樣是aidlux
HostName即上文提到的Cloud_ip地址端蛆,Port默認(rèn)9022,連接成功后酥泛,打開(kāi)我們上傳到aidlux中的文件夾:
注:打開(kāi)文件夾的時(shí)候會(huì)再次輸入密碼 aidlux
接下來(lái)就可以通過(guò)vscode進(jìn)行代碼調(diào)試了今豆。
3 人流統(tǒng)計(jì)實(shí)戰(zhàn)
然后我們來(lái)看一個(gè)運(yùn)行YOLOv5+目標(biāo)追蹤bytetrack進(jìn)行人流統(tǒng)計(jì)的案例,話不多說(shuō)柔袁,先上效果:
3.1 目錄結(jié)構(gòu):
其中yolov5n_best-fp16.tflite是從yolov5訓(xùn)練好的best.pt權(quán)重文件轉(zhuǎn)換來(lái)的呆躲。
3.2 相關(guān)代碼:
yolov5_overstep.py:
# aidlux相關(guān)
from cvs import *
import aidlite_gpu
from utils import detect_postprocess, preprocess_img, draw_detect_res,is_passing_line
import cv2
# bytetrack
from track.tracker.byte_tracker import BYTETracker
from track.utils.visualize import plot_tracking
import requests
import time
# 加載模型
model_path = '/home/lesson5_codes/aidlux/yolov5n_best-fp16.tflite'
in_shape = [1 * 640 * 640 * 3 * 4]
out_shape = [1 * 25200 * 6 * 4]
# 載入模型
aidlite = aidlite_gpu.aidlite()
# 載入yolov5檢測(cè)模型
aidlite.ANNModel(model_path, in_shape, out_shape, 4, 0)
tracker = BYTETracker(frame_rate=30)
track_id_status = {}
cap = cvs.VideoCapture("/home/lesson5_codes/aidlux/video.mp4")
frame_id = 0
count_person = 0
while True:
? ? frame = cap.read()
? ? if frame is None:
? ? ? ? print('camera is over!')
? ? ? ? # 統(tǒng)計(jì)打印人數(shù)流量
? ? ? ? # 填寫對(duì)應(yīng)的喵碼
? ? ? ? id = 'tOqH04S'
? ? ? ? # 填寫喵提醒中,發(fā)送的消息捶索,這里放上前面提到的圖片外鏈
? ? ? ? text = "人流統(tǒng)計(jì)數(shù):"+str(count_person)
? ? ? ? ts = str(time.time())? # 時(shí)間戳
? ? ? ? type = 'json'? # 返回內(nèi)容格式
? ? ? ? request_url = "http://miaotixing.com/trigger?"
? ? ? ? headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.67 Safari/537.36 Edg/87.0.664.47'}
? ? ? ? result = requests.post(request_url + "id=" + id + "&text=" + text + "&ts=" + ts + "&type=" + type,headers=headers)
? ? ? ? break
? ? frame_id += 1
? ? if frame_id % 3 != 0:
? ? ? ? continue
? ? # 預(yù)處理
? ? img = preprocess_img(frame, target_shape=(640, 640), div_num=255, means=None, stds=None)
? ? # 數(shù)據(jù)轉(zhuǎn)換:因?yàn)閟etTensor_Fp32()需要的是float32類型的數(shù)據(jù)插掂,所以送入的input的數(shù)據(jù)需為float32,大多數(shù)的開(kāi)發(fā)者都會(huì)忘記將圖像的數(shù)據(jù)類型轉(zhuǎn)換為float32
? ? aidlite.setInput_Float32(img, 640, 640)
? ? # 模型推理API
? ? aidlite.invoke()
? ? # 讀取返回的結(jié)果
? ? pred = aidlite.getOutput_Float32(0)
? ? # 數(shù)據(jù)維度轉(zhuǎn)換
? ? pred = pred.reshape(1, 25200, 6)[0]
? ? # 模型推理后處理
? ? pred = detect_postprocess(pred, frame.shape, [640, 640, 3], conf_thres=0.4, iou_thres=0.45)
? ? # 繪制推理結(jié)果
? ? res_img = draw_detect_res(frame, pred)
? ? # 目標(biāo)追蹤相關(guān)功能
? ? det = []
? ? # Process predictions
? ? for box in pred[0]:? # per image
? ? ? ? box[2] += box[0]
? ? ? ? box[3] += box[1]
? ? ? ? det.append(box)
? ? if len(det):
? ? ? ? # Rescale boxes from img_size to im0 size
? ? ? ? online_targets = tracker.update(det, [frame.shape[0], frame.shape[1]])
? ? ? ? online_tlwhs = []
? ? ? ? online_ids = []
? ? ? ? online_scores = []
? ? ? ? # 取出每個(gè)目標(biāo)的追蹤信息
? ? ? ? for t in online_targets:
? ? ? ? ? ? # 目標(biāo)的檢測(cè)框信息
? ? ? ? ? ? tlwh = t.tlwh
? ? ? ? ? ? # 目標(biāo)的track_id信息
? ? ? ? ? ? tid = t.track_id
? ? ? ? ? ? online_tlwhs.append(tlwh)
? ? ? ? ? ? online_ids.append(tid)
? ? ? ? ? ? online_scores.append(t.score)
? ? ? ? ? ? # 針對(duì)目標(biāo)繪制追蹤相關(guān)信息
? ? ? ? ? ? res_img = plot_tracking(res_img, online_tlwhs, online_ids, 0,0)
? ? ? ? ? ? ### 人流計(jì)數(shù)識(shí)別功能實(shí)現(xiàn) ###
? ? ? ? ? ? # 1.繪制直線
? ? ? ? ? ? lines = [[186,249],[1235,366]]
? ? ? ? ? ? cv2.line(res_img,(186,249),(1235,266),(255,255,0),3)
? ? ? ? ? ? # 2.計(jì)算得到人體下方中心點(diǎn)的位置(人體檢測(cè)監(jiān)測(cè)點(diǎn)調(diào)整)
? ? ? ? ? ? pt = [tlwh[0]+1/2*tlwh[2],tlwh[1]+tlwh[3]]
? ? ? ? ? ? # 3. 人體和違規(guī)區(qū)域的判斷(人體狀態(tài)追蹤判斷)
? ? ? ? ? ? track_info = is_passing_line(pt, lines)
? ? ? ? ? ? if tid not in track_id_status.keys():
? ? ? ? ? ? ? ? track_id_status.update( {tid:[track_info]})
? ? ? ? ? ? else:
? ? ? ? ? ? ? ? if track_info != track_id_status[tid][-1]:
? ? ? ? ? ? ? ? ? ? track_id_status[tid].append(track_info)
? ? ? ? ? ? # 4. 判斷是否有track_id越界,有的話保存成圖片
? ? ? ? ? ? # 當(dāng)某個(gè)track_id的狀態(tài)腥例,上一幀是-1辅甥,但是這一幀是1時(shí),說(shuō)明越界了
? ? ? ? ? ? if track_id_status[tid][-1] == 1 and len(track_id_status[tid]) >1:
? ? ? ? ? ? ? ? # 判斷上一個(gè)狀態(tài)是否是-1燎竖,是否的話說(shuō)明越界璃弄,為了防止繼續(xù)判別,隨機(jī)的賦了一個(gè)3的值
? ? ? ? ? ? ? ? if? track_id_status[tid][-2] == -1:
? ? ? ? ? ? ? ? ? ? track_id_status[tid].append(3)
? ? ? ? ? ? ? ? ? ? count_person+=1
? ? cv2.putText(res_img,"-1 to 1 person_count:? "+str(count_person),(50,105),cv2.FONT_HERSHEY_SIMPLEX,1,(0,255,255),2)
? ? cvs.imshow(res_img)? ? ? ? ? ? ?
utils.py:
import time
import cv2
import numpy as np
coco_class = ['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']
def xywh2xyxy(x):
? ? '''
? ? Box (center x, center y, width, height) to (x1, y1, x2, y2)
? ? '''
? ? y = np.copy(x)
? ? y[:, 0] = x[:, 0] - x[:, 2] / 2? # top left x
? ? y[:, 1] = x[:, 1] - x[:, 3] / 2? # top left y
? ? y[:, 2] = x[:, 0] + x[:, 2] / 2? # bottom right x
? ? y[:, 3] = x[:, 1] + x[:, 3] / 2? # bottom right y
? ? return y
def xyxy2xywh(box):
? ? '''
? ? Box (left_top x, left_top y, right_bottom x, right_bottom y) to (left_top x, left_top y, width, height)
? ? '''
? ? box[:, 2:] = box[:, 2:] - box[:, :2]
? ? return box
def NMS(dets, thresh):
? ? '''
? ? 單類NMS算法
? ? dets.shape = (N, 5), (left_top x, left_top y, right_bottom x, right_bottom y, Scores)
? ? '''
? ? x1 = dets[:,0]
? ? y1 = dets[:,1]
? ? x2 = dets[:,2]
? ? y2 = dets[:,3]
? ? areas = (y2-y1+1) * (x2-x1+1)
? ? scores = dets[:,4]
? ? keep = []
? ? index = scores.argsort()[::-1]
? ? while index.size >0:
? ? ? ? i = index[0]? ? ? # every time the first is the biggst, and add it directly
? ? ? ? keep.append(i)
? ? ? ? x11 = np.maximum(x1[i], x1[index[1:]])? ? # calculate the points of overlap
? ? ? ? y11 = np.maximum(y1[i], y1[index[1:]])
? ? ? ? x22 = np.minimum(x2[i], x2[index[1:]])
? ? ? ? y22 = np.minimum(y2[i], y2[index[1:]])
? ? ? ? w = np.maximum(0, x22-x11+1)? ? # the weights of overlap
? ? ? ? h = np.maximum(0, y22-y11+1)? ? # the height of overlap
? ? ? ? overlaps = w*h
? ? ? ? ious = overlaps / (areas[i]+areas[index[1:]] - overlaps)
? ? ? ? idx = np.where(ious<=thresh)[0]
? ? ? ? index = index[idx+1]? # because index start from 1
? ? return dets[keep]
def letterbox(img, new_shape=(640, 640), color=(114, 114, 114), auto=True, scaleFill=False, scaleup=True, stride=32):
? ? # Resize and pad image while meeting stride-multiple constraints
? ? shape = img.shape[:2]? # current shape [height, width]
? ? if isinstance(new_shape, int):
? ? ? ? new_shape = (new_shape, new_shape)
? ? # Scale ratio (new / old)
? ? r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])
? ? if not scaleup:? # only scale down, do not scale up (for better test mAP)
? ? ? ? r = min(r, 1.0)
? ? # Compute padding
? ? ratio = r, r? # width, height ratios
? ? new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r))
? ? dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1]? # wh padding
? ? if auto:? # minimum rectangle
? ? ? ? dw, dh = np.mod(dw, stride), np.mod(dh, stride)? # wh padding
? ? elif scaleFill:? # stretch
? ? ? ? dw, dh = 0.0, 0.0
? ? ? ? new_unpad = (new_shape[1], new_shape[0])
? ? ? ? ratio = new_shape[1] / shape[1], new_shape[0] / shape[0]? # width, height ratios
? ? dw /= 2? # divide padding into 2 sides
? ? dh /= 2
? ? if shape[::-1] != new_unpad:? # resize
? ? ? ? img = cv2.resize(img, new_unpad, interpolation=cv2.INTER_LINEAR)
? ? top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1))
? ? left, right = int(round(dw - 0.1)), int(round(dw + 0.1))
? ? img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color)? # add border
? ? return img, ratio, (dw, dh)
def preprocess_img(img, target_shape:tuple=None, div_num=255, means:list=[0.485, 0.456, 0.406], stds:list=[0.229, 0.224, 0.225]):
? ? '''
? ? 圖像預(yù)處理:
? ? target_shape: 目標(biāo)shape
? ? div_num: 歸一化除數(shù)
? ? means: len(means)==圖像通道數(shù)底瓣,通道均值, None不進(jìn)行zscore
? ? stds: len(stds)==圖像通道數(shù)谢揪,通道方差, None不進(jìn)行zscore
? ? '''
? ? img_processed = np.copy(img)
? ? # resize
? ? if target_shape:
? ? ? ? # img_processed = cv2.resize(img_processed, target_shape)
? ? ? ? img_processed = letterbox(img_processed, target_shape, stride=None, auto=False)[0]
? ? img_processed = img_processed.astype(np.float32)
? ? img_processed = img_processed/div_num
? ? # z-score
? ? if means is not None and stds is not None:
? ? ? ? means = np.array(means).reshape(1, 1, -1)
? ? ? ? stds = np.array(stds).reshape(1, 1, -1)
? ? ? ? img_processed = (img_processed-means)/stds
? ? # unsqueeze
? ? img_processed = img_processed[None, :]
? ? return img_processed.astype(np.float32)
def convert_shape(shapes:tuple or list, int8=False):
? ? '''
? ? 轉(zhuǎn)化為aidlite需要的格式
? ? '''
? ? if isinstance(shapes, tuple):
? ? ? ? shapes = [shapes]
? ? out = []
? ? for shape in shapes:
? ? ? ? nums = 1 if int8 else 4
? ? ? ? for n in shape:
? ? ? ? ? ? nums *= n
? ? ? ? out.append(nums)
? ? return out
def scale_coords(img1_shape, coords, img0_shape, ratio_pad=None):
? ? # Rescale coords (xyxy) from img1_shape to img0_shape
? ? if ratio_pad is None:? # calculate from img0_shape
? ? ? ? gain = min(img1_shape[0] / img0_shape[0], img1_shape[1] / img0_shape[1])? # gain? = old / new
? ? ? ? pad = (img1_shape[1] - img0_shape[1] * gain) / 2, (img1_shape[0] - img0_shape[0] * gain) / 2? # wh padding
? ? else:
? ? ? ? gain = ratio_pad[0][0]
? ? ? ? pad = ratio_pad[1]
? ? coords[:, [0, 2]] -= pad[0]? # x padding
? ? coords[:, [1, 3]] -= pad[1]? # y padding
? ? coords[:, :4] /= gain
? ? clip_coords(coords, img0_shape)
? ? return coords
def clip_coords(boxes, img_shape):
? ? # Clip bounding xyxy bounding boxes to image shape (height, width)
? ? boxes[:, 0].clip(0, img_shape[1], out=boxes[:, 0])? # x1
? ? boxes[:, 1].clip(0, img_shape[0], out=boxes[:, 1])? # y1
? ? boxes[:, 2].clip(0, img_shape[1], out=boxes[:, 2])? # x2
? ? boxes[:, 3].clip(0, img_shape[0], out=boxes[:, 3])? # y2
def detect_postprocess(prediction, img0shape, img1shape, conf_thres=0.25, iou_thres=0.45):
? ? '''
? ? 檢測(cè)輸出后處理
? ? prediction: aidlite模型預(yù)測(cè)輸出
? ? img0shape: 原始圖片shape
? ? img1shape: 輸入圖片shape
? ? conf_thres: 置信度閾值
? ? iou_thres: IOU閾值
? ? return: list[np.ndarray(N, 5)], 對(duì)應(yīng)類別的坐標(biāo)框信息, xywh、conf
? ? '''
? ? h, w, _ = img1shape
? ? cls_num = prediction.shape[-1] - 5
? ? valid_condidates = prediction[prediction[..., 4] > conf_thres]
? ? valid_condidates[:, 0] *= w
? ? valid_condidates[:, 1] *= h
? ? valid_condidates[:, 2] *= w
? ? valid_condidates[:, 3] *= h
? ? valid_condidates[:, :4] = xywh2xyxy(valid_condidates[:, :4])
? ? valid_condidates = valid_condidates[(valid_condidates[:, 0] > 0) & (valid_condidates[:, 1] > 0) & (valid_condidates[:, 2] > 0) & (valid_condidates[:, 3] > 0)]
? ? box_cls = valid_condidates[:, 5:].argmax(1)
? ? cls_box = []
? ? for i in range(cls_num):
? ? ? ? temp_boxes = valid_condidates[box_cls == i]
? ? ? ? if(len(temp_boxes) == 0):
? ? ? ? ? ? cls_box.append([])
? ? ? ? ? ? continue
? ? ? ? temp_boxes = NMS(temp_boxes, iou_thres)
? ? ? ? temp_boxes[:, :4] = scale_coords([h, w], temp_boxes[:, :4] , img0shape).round()
? ? ? ? temp_boxes[:, :4] = xyxy2xywh(temp_boxes[:, :4])
? ? ? ? cls_box.append(temp_boxes[:, :5])
? ? return cls_box
def draw_detect_res(img, all_boxes):
? ? '''
? ? 檢測(cè)結(jié)果繪制
? ? '''
? ? img = img.astype(np.uint8)
? ? color_step = int(255/len(all_boxes))
? ? for bi in range(len(all_boxes)):
? ? ? ? if len(all_boxes[bi]) == 0:
? ? ? ? ? ? continue
? ? ? ? for box in all_boxes[bi]:
? ? ? ? ? ? x, y, w, h = [int(t) for t in box[:4]]
? ? ? ? ? ? score = str(box[4:5][0])
? ? ? ? ? ? cv2.putText(img, str(round(float(score),2)), (x, y-5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)
? ? ? ? ? ? cv2.rectangle(img, (x,y), (x+w, y+h),(0, bi*color_step, 255-bi*color_step),thickness = 2)
? ? return img
def process_points(img,points,color_light_green):
? ? points = np.array([points], dtype=np.int32)
? ? ###繪制mask
? ? zeros = np.zeros((img.shape), dtype=np.uint8)
? ? mask = cv2.fillPoly(zeros, points, color=color_light_green)? ####填充顏色
? ? ##繪制輪廓
? ? cv2.drawContours(img, points, -1, (144, 238, 144), 5)? ###繪制輪廓
? ? ##疊加mask和普通圖片
? ? mask_img = 0.01 * mask + img
? ? return mask_img
def is_in_poly(p, poly):
? ? """
? ? :param p: [x, y]
? ? :param poly: [[], [], [], [], ...]
? ? :return:
? ? """
? ? px, py = p
? ? is_in = False
? ? for i, corner in enumerate(poly):
? ? ? ? next_i = i + 1 if i + 1 < len(poly) else 0
? ? ? ? x1, y1 = corner
? ? ? ? x2, y2 = poly[next_i]
? ? ? ? if (x1 == px and y1 == py) or (x2 == px and y2 == py):? # if point is on vertex
? ? ? ? ? ? is_in = True
? ? ? ? ? ? break
? ? ? ? if min(y1, y2) < py <= max(y1, y2):? # find horizontal edges of polygon
? ? ? ? ? ? x = x1 + (py - y1) * (x2 - x1) / (y2 - y1)
? ? ? ? ? ? if x == px:? # if point is on edge
? ? ? ? ? ? ? ? is_in = True
? ? ? ? ? ? ? ? break
? ? ? ? ? ? elif x > px:? # if point is on left-side of line
? ? ? ? ? ? ? ? is_in = not is_in
? ? if is_in == True:
? ? ? ? person_status = 1
? ? else:
? ? ? ? person_status = -1
? ? return person_status
def is_passing_line(point, polyline):
? ? # 在直線下方,status =-1
? ? # 在直線上方,status =1
? ? status = 1
? ? # 點(diǎn)映射在直線的高度
? ? poly_y = ((polyline[1][1] - polyline[0][1]) * (point[0] - polyline[0][0])) / (polyline[1][0] - polyline[0][0]) + \
? ? ? ? ? ? ? polyline[0][1]
? ? if point[1] > poly_y:
? ? ? ? status = -1
? ? return status
3.3喵提醒公眾號(hào)的使用
?在yolov5_overstep.py中我們可以看到捐凭,有這樣一段代碼:
它可以用來(lái)實(shí)現(xiàn)如下效果:
即:當(dāng)我們預(yù)測(cè)完一段視頻拨扶,或者一個(gè)時(shí)段之后,通過(guò)公眾號(hào)通知我們?nèi)肆髁繛槎嗌佟?/p>
使用方法我們已經(jīng)在上面給出茁肠,大家只需要把喵碼ID換成自己的患民,這樣才會(huì)發(fā)送到自己的微信上。
下面來(lái)介紹一下如何獲取喵碼id:
(1)關(guān)注“喵提醒”公眾號(hào)垦梆,關(guān)注成功后匹颤,公眾號(hào)會(huì)給我們發(fā)送一條消息,可以直接點(diǎn)擊注冊(cè)賬號(hào)托猩,或者給公眾號(hào)發(fā)送“注冊(cè)賬號(hào)”印蓖。
?(2)在底部菜單欄中,點(diǎn)擊提醒--新建
(3)填寫完標(biāo)題和備注后京腥,點(diǎn)擊保存赦肃,系統(tǒng)會(huì)自動(dòng)生成喵碼id。
?(4)此時(shí)公浪,我們只需要復(fù)制喵碼id他宛,并且替換代碼中原有的id即可