1.AidLux介紹
1.AidLux是基于ARM架構的跨生態(tài)(Android/鴻蒙+Linux)一站式AIoT應用快速開發(fā)和部署平臺APP
2.通過共享 Linux 內核實現(xiàn)Android 和 Linux 生態(tài)融合暖璧,為單一設備同時提供Android和Linux運行環(huán)境
3.集成國際主流AI框架和多種開發(fā)環(huán)境取胎、后臺服務程序、編譯器及圖形開發(fā)組件忌傻,無須配置開箱即用盔性,極大地簡化了開發(fā)步驟缓醋;自主研發(fā)的AI智能加速技術可實現(xiàn)CPU+GPU+NPU智能加速尽超,大幅提高AI應用運行效率般贼;平臺廣泛而深度的適配外設接口交洗,省去大量調試工作骑科;內置完整的跨平臺桌面和命令行終端連接(SSH),一個平臺完成多終端協(xié)同開發(fā)构拳、測試纵散、部署
4.可使用APK包安裝方式快速部署在ARM架構的手機、平板隐圾、電腦和板卡等智能終端上
5.AidLux能廣泛應用在智能工業(yè)伍掀、AI教育、智慧人居暇藏、智慧城市蜜笤、智慧物流、智慧交通盐碱、智慧零售和機器人等諸多場景中
博主覺得把兔,AidLux最大的優(yōu)勢在于:常規(guī)Al應用開發(fā)需要C++、Java瓮顽、Python县好、Linux等不同工程師相互配合,而在AidLux平臺暖混,開發(fā)者僅需使用Python一種編程語言即可進行開發(fā)缕贡,并支持將其他平臺(PC、服務器)上使用Python開發(fā)的AI應用直接遷移至AidLux調試運行。
也就是說我們只需要熟悉python語言即可晾咪,再也不用學令人頭疼的C++了收擦!
2.環(huán)境搭建
2.1 手機版AidLux的安裝
目前使用Aidlux主要有兩種方式:
1.邊緣設備的方式:阿加犀用高通芯片的S855,和S865制作了兩款邊緣設備谍倦,一款提供7T算力塞赂,一款提供15T算力。
2.手機設備的方式:沒有邊緣設備的情況下昼蛀,也可以使用手機版本的Aidlux宴猾,嘗試邊緣設備的所有功能。
并且目前Aidlux已對基本市面上所有的芯片都進行了適配叼旋,在手機上運行算法模型鳍置,也可以體驗優(yōu)化的效果。當然在使用過程中送淆,有個共同點,即手機設備和邊緣設備采用的Aidlux軟件怕轿,都是一樣的偷崩。因此可以先嘗試手機設備的方式,在后期需要更多算力的時候撞羽,使用邊緣設備阐斜,就可以無縫銜接。所以我們先下載一下手機Aidlux的APP軟件诀紊。打開安卓手機的應用商城谒出,搜索Aidlux即可下載安裝。
?打開手機版本的Aidlux軟件APP邻奠,第一次進入的時候笤喳,APP自帶的系統(tǒng)會進行初始化。
初始化好后碌宴,進入系統(tǒng)登錄頁面杀狡,這一步最好可以用手機注冊一下,當然也可以直接點擊“我已閱讀并同意”贰镣,然后點擊跳過登錄呜象。
注意:軟件獲取存儲權限后會有提示,如果是安卓版本12的手機碑隆,請點擊確認恭陡,跟著提示完成相關步驟,以便后續(xù)開發(fā)上煤。
?進入主頁面后休玩,可以點擊左上角的紅色叉號,將說明頁面關閉。
?為了方便編程哥捕,aidlux還提供了電腦接口(需要手機和電腦連接同一網絡):
?點擊下圖中的Cloud_ip牧抽,即可顯示電腦鏈接
在電腦中輸入第一個網址即可,登陸時需要密碼遥赚,默認密碼為:?aidlux
?登錄成功后可以發(fā)現(xiàn)扬舒,電腦的界面和手機端是同步的:
因此在開發(fā)的時候我們將寫好的代碼上傳到文件中,就可以利用VSCode運行和調試?.
2.2 Aidlux軟件設置默認后臺運行
這里列舉了多款手機設置的方式凫佛,大家可以參照相應的設置教程:
(1)小米手機和平板設置教程:https://community.aidlux.com/postDetail/832
(2)OPPO手機與平板設置教程:https://community.aidlux.com/postDetail/834
(3)vivo手機與平板設置教程:https://community.aidlux.com/postDetail/835
(4)華為鴻蒙/HarmonyOS 2.0設置教程:https://community.aidlux.com/postDetail/828
(5)華為鴻蒙/HarmonyOS 3.0設置教程:https://community.aidlux.com/postDetail/827
2.3 VSCode遠程連接
?新建遠程連接:config如圖所示讲坎,連接的密碼同樣是aidlux
HostName即上文提到的Cloud_ip地址,Port默認9022愧薛,連接成功后晨炕,打開我們上傳到aidlux中的文件夾:
注:打開文件夾的時候會再次輸入密碼 aidlux
接下來就可以通過vscode進行代碼調試了。
3 人流統(tǒng)計實戰(zhàn)
然后我們來看一個運行YOLOv5+目標追蹤bytetrack進行人流統(tǒng)計的案例毫炉,話不多說瓮栗,先上效果:
3.1 目錄結構:
其中yolov5n_best-fp16.tflite是從yolov5訓練好的best.pt權重文件轉換來的。
3.2 相關代碼:
yolov5_overstep.py:
# aidlux相關
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檢測模型
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)計打印人數(shù)流量
? ? ? ? # 填寫對應的喵碼
? ? ? ? id = 'tOqH04S'
? ? ? ? # 填寫喵提醒中瞄勾,發(fā)送的消息费奸,這里放上前面提到的圖片外鏈
? ? ? ? text = "人流統(tǒng)計數(shù):"+str(count_person)
? ? ? ? ts = str(time.time())? # 時間戳
? ? ? ? type = 'json'? # 返回內容格式
? ? ? ? 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
? ? # 預處理
? ? img = preprocess_img(frame, target_shape=(640, 640), div_num=255, means=None, stds=None)
? ? # 數(shù)據轉換:因為setTensor_Fp32()需要的是float32類型的數(shù)據,所以送入的input的數(shù)據需為float32,大多數(shù)的開發(fā)者都會忘記將圖像的數(shù)據類型轉換為float32
? ? aidlite.setInput_Float32(img, 640, 640)
? ? # 模型推理API
? ? aidlite.invoke()
? ? # 讀取返回的結果
? ? pred = aidlite.getOutput_Float32(0)
? ? # 數(shù)據維度轉換
? ? pred = pred.reshape(1, 25200, 6)[0]
? ? # 模型推理后處理
? ? pred = detect_postprocess(pred, frame.shape, [640, 640, 3], conf_thres=0.4, iou_thres=0.45)
? ? # 繪制推理結果
? ? res_img = draw_detect_res(frame, pred)
? ? # 目標追蹤相關功能
? ? 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 = []
? ? ? ? # 取出每個目標的追蹤信息
? ? ? ? for t in online_targets:
? ? ? ? ? ? # 目標的檢測框信息
? ? ? ? ? ? tlwh = t.tlwh
? ? ? ? ? ? # 目標的track_id信息
? ? ? ? ? ? tid = t.track_id
? ? ? ? ? ? online_tlwhs.append(tlwh)
? ? ? ? ? ? online_ids.append(tid)
? ? ? ? ? ? online_scores.append(t.score)
? ? ? ? ? ? # 針對目標繪制追蹤相關信息
? ? ? ? ? ? res_img = plot_tracking(res_img, online_tlwhs, online_ids, 0,0)
? ? ? ? ? ? ### 人流計數(shù)識別功能實現(xiàn) ###
? ? ? ? ? ? # 1.繪制直線
? ? ? ? ? ? lines = [[186,249],[1235,366]]
? ? ? ? ? ? cv2.line(res_img,(186,249),(1235,266),(255,255,0),3)
? ? ? ? ? ? # 2.計算得到人體下方中心點的位置(人體檢測監(jiān)測點調整)
? ? ? ? ? ? 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越界进陡,有的話保存成圖片
? ? ? ? ? ? # 當某個track_id的狀態(tài)愿阐,上一幀是-1,但是這一幀是1時趾疚,說明越界了
? ? ? ? ? ? if track_id_status[tid][-1] == 1 and len(track_id_status[tid]) >1:
? ? ? ? ? ? ? ? # 判斷上一個狀態(tài)是否是-1缨历,是否的話說明越界,為了防止繼續(xù)判別糙麦,隨機的賦了一個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]):
? ? '''
? ? 圖像預處理:
? ? target_shape: 目標shape
? ? div_num: 歸一化除數(shù)
? ? means: len(means)==圖像通道數(shù)辛孵,通道均值, None不進行zscore
? ? stds: len(stds)==圖像通道數(shù),通道方差, None不進行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):
? ? '''
? ? 轉化為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):
? ? '''
? ? 檢測輸出后處理
? ? prediction: aidlite模型預測輸出
? ? img0shape: 原始圖片shape
? ? img1shape: 輸入圖片shape
? ? conf_thres: 置信度閾值
? ? iou_thres: IOU閾值
? ? return: list[np.ndarray(N, 5)], 對應類別的坐標框信息, 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):
? ? '''
? ? 檢測結果繪制
? ? '''
? ? 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
? ? # 點映射在直線的高度
? ? 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喵提醒公眾號的使用
?在yolov5_overstep.py中我們可以看到觉吭,有這樣一段代碼:
它可以用來實現(xiàn)如下效果:
即:當我們預測完一段視頻,或者一個時段之后仆邓,通過公眾號通知我們人流量為多少鲜滩。
使用方法我們已經在上面給出,大家只需要把喵碼ID換成自己的节值,這樣才會發(fā)送到自己的微信上徙硅。
下面來介紹一下如何獲取喵碼id:
(1)關注“喵提醒”公眾號,關注成功后搞疗,公眾號會給我們發(fā)送一條消息嗓蘑,可以直接點擊注冊賬號须肆,或者給公眾號發(fā)送“注冊賬號”。
?(2)在底部菜單欄中桩皿,點擊提醒--新建
(3)填寫完標題和備注后豌汇,點擊保存,系統(tǒng)會自動生成喵碼id泄隔。
?(4)此時拒贱,我們只需要復制喵碼id,并且替換代碼中原有的id即可