Hardware components | ||||||
![]() |
| × | 1 | |||
![]() |
| × | 1 | |||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
![]() |
| × | 1 | |||
Software apps and online services | ||||||
| ||||||
![]() |
| |||||
| ||||||
![]() |
| |||||
![]() |
| |||||
| ||||||
| ||||||
![]() |
| |||||
![]() |
|
Summary:
I want to turn the traditional claw machine into an AI-based game. My idea is touch object bonding box, and then robot-arm will move to specific coordinate to grab object. But need to give coordinate some random value. Make this game more challenge. Just for fun!! Because AI not only for professional guy. This is also why chatGPT become popular. We need to make end-user have interest on it in first. When this topic become popular. More investors and start-up will pay attention to the future development of AI And then push the development of AI in the world.
KR260 Initial Setup:
Follow document to build KR260 image
download Ubuntu for KR260
link: https://ubuntu.com/download/amd
When image build finish, power-on with this SD card
I have a DP issue, it's kr260 not support HDMI to DP, need DP to DP
Train Model:
Prepare image for training model.
Inference Server and Client Device Setup:
Because this ASUS AMD 7840U laptop is my personal pc. So I use it as inference PC and client PC in same time. in inference server. It will get image from webcam and inference it, send result by mqtt message to service server. In client device, just open browser to use client service.
Follow this document to setup RyzenAI v1.1
link: https://ryzenai.docs.amd.com/en/1.1/inst.html
Make sure AI Inference can be work on NPU.
Service Server setup:
Use iEi Tank XM811 as web/app server
link: https://www.ieiworld.com/tw/product-ns/model.php?II=12
3rd-party AIOT tools:
Install node-red/influxDB/Grafana 3in1 tools
link: https://github.com/IEI-dev/Smart-Meter-Reader/tree/main/server/docker
Simple Mqtt test, it will output object{xmin,ymin,xmax,ymax}
Robot-Arm AIOT control in node-red
Grafana make a simple UI as traditional button, ex: joystick, 1 grab button, 1 cancel button. Base on these information to build UI for client user.
Grafana UI for simulate 1 grab button, 1 cancel button.
In AI base game, we don't need to use joystick, only need to touch detection object. But I also try to build arduino base joystick, if customer need it.
Basic hardware health and status
Robot Arm Setup:
Install WLkata Python SDK
link: https://github.com/wlkata/WLKATA-Python-SDK-wlkatapython
WLkata example:
link: https://lin-nice.github.io/mirobot_gitbook/8-wlkata.html
I spend to more time on AI, still unable to flexibly grab objects at specified coordinates. So I only prepare 3 move script for WLkaka mirobot. Make sure this demo can be keep going.
Winner-Zone:
Define winner-zone, ex: you need to grab toy to specific zone.
But this box is too tall my robo-arm cannot good to do it.
So I use different color as winner zone.
AiEi Winner Zone editor:
Flexible modification of visual detection area
TeleAI Claw Machine Demo:
It's a simple demo, because only 3 robot-arm move script. When robot-arm grab toy into winner-zone, bounding box will become blue color. And send mqtt message to client.
[
{
"id": "07d0ce7f4519a9a8",
"type": "tab",
"label": "IEI Demo",
"disabled": false,
"info": "",
"env": []
},
{
"id": "cd1a6b92333e4f44",
"type": "ui_group",
"name": "Default",
"tab": "beecae290db7caf0",
"order": 1,
"disp": false,
"width": "10",
"collapse": false,
"className": ""
},
{
"id": "dd83c5fc2dff1910",
"type": "mqtt-broker",
"name": "",
"broker": "mqtt-broker",
"port": "1883",
"clientid": "",
"autoConnect": true,
"usetls": false,
"protocolVersion": "4",
"keepalive": "60",
"cleansession": true,
"birthTopic": "",
"birthQos": "0",
"birthPayload": "",
"birthMsg": {},
"closeTopic": "",
"closeQos": "0",
"closePayload": "",
"closeMsg": {},
"willTopic": "",
"willQos": "0",
"willPayload": "",
"willMsg": {},
"userProps": "",
"sessionExpiry": ""
},
{
"id": "beecae290db7caf0",
"type": "ui_tab",
"name": "Robot Arm Demo",
"icon": "dashboard",
"disabled": false,
"hidden": false
},
{
"id": "e9e9f8b3dd64ee36",
"type": "ui_base",
"theme": {
"name": "theme-dark",
"lightTheme": {
"default": "#0094CE",
"baseColor": "#0094CE",
"baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif",
"edited": true,
"reset": false
},
"darkTheme": {
"default": "#097479",
"baseColor": "#097479",
"baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif",
"edited": true,
"reset": false
},
"customTheme": {
"name": "Untitled Theme 1",
"default": "#4B7930",
"baseColor": "#4B7930",
"baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif"
},
"themeState": {
"base-color": {
"default": "#097479",
"value": "#097479",
"edited": false
},
"page-titlebar-backgroundColor": {
"value": "#097479",
"edited": false
},
"page-backgroundColor": {
"value": "#111111",
"edited": false
},
"page-sidebar-backgroundColor": {
"value": "#333333",
"edited": false
},
"group-textColor": {
"value": "#0eb8c0",
"edited": false
},
"group-borderColor": {
"value": "#555555",
"edited": false
},
"group-backgroundColor": {
"value": "#333333",
"edited": false
},
"widget-textColor": {
"value": "#eeeeee",
"edited": false
},
"widget-backgroundColor": {
"value": "#097479",
"edited": false
},
"widget-borderColor": {
"value": "#333333",
"edited": false
},
"base-font": {
"value": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif"
}
},
"angularTheme": {
"primary": "indigo",
"accents": "blue",
"warn": "red",
"background": "grey",
"palette": "light"
}
},
"site": {
"name": "Node-RED Dashboard",
"hideToolbar": "false",
"allowSwipe": "false",
"lockMenu": "false",
"allowTempTheme": "true",
"dateFormat": "DD/MM/YYYY",
"sizes": {
"sx": 48,
"sy": 48,
"gx": 6,
"gy": 6,
"cx": 6,
"cy": 6,
"px": 0,
"py": 0
}
}
},
{
"id": "48b27f784758d43f",
"type": "http request",
"z": "07d0ce7f4519a9a8",
"name": "RobotArm Control",
"method": "PUT",
"ret": "txt",
"paytoqs": "ignore",
"url": "http://core-command:59882/api/v2/device/name/Robot-Arm/ControlMode",
"tls": "",
"persist": false,
"proxy": "",
"insecureHTTPParser": false,
"authType": "",
"senderr": false,
"headers": [],
"x": 590,
"y": 300,
"wires": [
[
"b8720fd86ffa788e",
"5de3508058bd8ef3"
]
]
},
{
"id": "931e21036fb8ec15",
"type": "function",
"z": "07d0ce7f4519a9a8",
"name": "Pause",
"func": "\nlet button = msg.payload\nmsg.payload = {}\n\nlet status = flow.get (\"ARM_STATUS\")\n\nif ((status != \"Pause\" && msg.confirmedPeople >= 1) || button === true)\n{\n msg.payload [\"ControlMode\"] = \"1\"\n flow.set (\"ARM_STATUS\", \"Pause\")\n\n return msg\n}\nelse\n return null",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 250,
"y": 180,
"wires": [
[
"48b27f784758d43f",
"3777d3f26a62c566",
"c65d1a7f90d0f971"
]
]
},
{
"id": "954ee578fbad7d70",
"type": "inject",
"z": "07d0ce7f4519a9a8",
"name": "",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "true",
"payloadType": "bool",
"x": 110,
"y": 140,
"wires": [
[
"931e21036fb8ec15"
]
]
},
{
"id": "b8720fd86ffa788e",
"type": "debug",
"z": "07d0ce7f4519a9a8",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 1010,
"y": 380,
"wires": []
},
{
"id": "812abf5af4cbc2a3",
"type": "function",
"z": "07d0ce7f4519a9a8",
"name": "Run",
"func": "msg.payload = {}\nmsg.payload [\"ControlMode\"] = \"0\"\nflow.set (\"ARM_STATUS\", \"Run\")\n\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 250,
"y": 220,
"wires": [
[
"48b27f784758d43f",
"03817a9ebcab3c2d"
]
]
},
{
"id": "62b35717e40ca1d8",
"type": "inject",
"z": "07d0ce7f4519a9a8",
"name": "",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "true",
"payloadType": "bool",
"x": 110,
"y": 260,
"wires": [
[
"812abf5af4cbc2a3"
]
]
},
{
"id": "d34f744b58bc027f",
"type": "http request",
"z": "07d0ce7f4519a9a8",
"name": "Read ControlMode Status",
"method": "GET",
"ret": "obj",
"paytoqs": "ignore",
"url": "http://core-command:59882/api/v2/device/name/Robot-Arm/ControlMode",
"tls": "",
"persist": false,
"proxy": "",
"insecureHTTPParser": false,
"authType": "",
"senderr": false,
"headers": [],
"x": 270,
"y": 420,
"wires": [
[
"17c75db1668514a6",
"6b82117fc3e91a8a"
]
]
},
{
"id": "b801827d68cedd01",
"type": "debug",
"z": "07d0ce7f4519a9a8",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 410,
"y": 520,
"wires": []
},
{
"id": "f5932ce3910cc2db",
"type": "inject",
"z": "07d0ce7f4519a9a8",
"name": "",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": "20",
"topic": "",
"payload": "",
"payloadType": "date",
"x": 130,
"y": 480,
"wires": [
[
"d34f744b58bc027f"
]
]
},
{
"id": "17c75db1668514a6",
"type": "function",
"z": "07d0ce7f4519a9a8",
"name": "Parsing Value",
"func": "let controlMode = msg.payload[\"event\"][\"readings\"][0][\"value\"]\n\nif (controlMode == \"1\") {\n msg.reason = \"Pause\"\n msg.payload = false\n \n} else if (controlMode == \"0\") {\n msg.reason = \"Running\"\n msg.payload = true\n} else {\n msg.reason = \"Unknow\"\n msg.payload = false\n}\n\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 340,
"y": 480,
"wires": [
[
"b801827d68cedd01",
"c1632763464f42e6",
"ea065af748048810",
"47e8b0788487f8e0"
]
]
},
{
"id": "c1632763464f42e6",
"type": "ui_led",
"z": "07d0ce7f4519a9a8",
"order": 2,
"group": "cd1a6b92333e4f44",
"width": 5,
"height": 5,
"label": "Robot Arm Status",
"labelPlacement": "left",
"labelAlignment": "left",
"colorForValue": [
{
"color": "#ff0000",
"value": "false",
"valueType": "bool"
},
{
"color": "#008000",
"value": "true",
"valueType": "bool"
}
],
"allowColorForValueInMessage": false,
"shape": "circle",
"showGlow": true,
"name": "",
"x": 470,
"y": 560,
"wires": []
},
{
"id": "f4e44246d14aa015",
"type": "mqtt in",
"z": "07d0ce7f4519a9a8",
"name": "",
"topic": "IR-Topic",
"qos": "2",
"datatype": "json",
"broker": "dd83c5fc2dff1910",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 100,
"y": 60,
"wires": [
[
"992307387b07f07e"
]
]
},
{
"id": "1cffeb71f8872dd1",
"type": "debug",
"z": "07d0ce7f4519a9a8",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 510,
"y": 60,
"wires": []
},
{
"id": "fafbb367721fe5af",
"type": "ui_text",
"z": "07d0ce7f4519a9a8",
"group": "cd1a6b92333e4f44",
"order": 1,
"width": 5,
"height": 5,
"name": "Text",
"label": "",
"format": "{{msg.reason}}",
"layout": "row-center",
"className": "font-size: 80px",
"x": 470,
"y": 600,
"wires": []
},
{
"id": "ea065af748048810",
"type": "function",
"z": "07d0ce7f4519a9a8",
"name": "",
"func": "msg.reason = '<font size=20px color=\\\"#097479\\\"><b>' + msg.reason + '</b></font>'\n\n\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 340,
"y": 600,
"wires": [
[
"fafbb367721fe5af"
]
]
},
{
"id": "5de3508058bd8ef3",
"type": "delay",
"z": "07d0ce7f4519a9a8",
"name": "",
"pauseType": "delay",
"timeout": "500",
"timeoutUnits": "milliseconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 130,
"y": 360,
"wires": [
[
"d34f744b58bc027f"
]
]
},
{
"id": "7d3314a1763f80f5",
"type": "ui_button",
"z": "07d0ce7f4519a9a8",
"name": "",
"group": "cd1a6b92333e4f44",
"order": 4,
"width": 5,
"height": 1,
"passthru": false,
"label": "Pause",
"tooltip": "",
"color": "",
"bgcolor": "",
"className": "",
"icon": "",
"payload": "true",
"payloadType": "bool",
"topic": "topic",
"topicType": "msg",
"x": 110,
"y": 180,
"wires": [
[
"931e21036fb8ec15"
]
]
},
{
"id": "f18e61ece814b0b4",
"type": "ui_button",
"z": "07d0ce7f4519a9a8",
"name": "",
"group": "cd1a6b92333e4f44",
"order": 3,
"width": 5,
"height": 1,
"passthru": false,
"label": "Run",
"tooltip": "",
"color": "",
"bgcolor": "",
"className": "",
"icon": "",
"payload": "",
"payloadType": "str",
"topic": "topic",
"topicType": "msg",
"x": 110,
"y": 220,
"wires": [
[
"812abf5af4cbc2a3"
]
]
},
{
"id": "46166018e459fb9f",
"type": "http request",
"z": "07d0ce7f4519a9a8",
"name": "LED Control",
"method": "POST",
"ret": "txt",
"paytoqs": "ignore",
"url": "http://led-server:8000/submit",
"tls": "",
"persist": false,
"proxy": "",
"insecureHTTPParser": false,
"authType": "",
"senderr": false,
"headers": [],
"x": 1130,
"y": 160,
"wires": [
[]
]
},
{
"id": "3777d3f26a62c566",
"type": "debug",
"z": "07d0ce7f4519a9a8",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 710,
"y": 80,
"wires": []
},
{
"id": "c65d1a7f90d0f971",
"type": "function",
"z": "07d0ce7f4519a9a8",
"name": "Status Alarm",
"func": "msg.payload = [{ \"status\": \"Alarm\" }]\n\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 790,
"y": 180,
"wires": [
[
"46166018e459fb9f"
]
]
},
{
"id": "03817a9ebcab3c2d",
"type": "function",
"z": "07d0ce7f4519a9a8",
"name": "Status Normal",
"func": "msg.payload = [{ \"status\": \"Normal\" }]\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 780,
"y": 220,
"wires": [
[
"46166018e459fb9f"
]
]
},
{
"id": "992307387b07f07e",
"type": "function",
"z": "07d0ce7f4519a9a8",
"name": "People Detection",
"func": "\nmsg.confirmedPeople = msg.payload.count\n\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 290,
"y": 60,
"wires": [
[
"931e21036fb8ec15",
"1cffeb71f8872dd1"
]
]
},
{
"id": "6b82117fc3e91a8a",
"type": "debug",
"z": "07d0ce7f4519a9a8",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 510,
"y": 420,
"wires": []
},
{
"id": "47e8b0788487f8e0",
"type": "debug",
"z": "07d0ce7f4519a9a8",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 570,
"y": 480,
"wires": []
}
]
import cv2
import numpy as np
from openvino.runtime import Core
import datetime
from shapely.geometry import Polygon
import paho.mqtt.publish as publish
def draw_bbox(bgr_image, resized_image, boxes,confidence):
colors = {"blue": (255, 0, 0), "green": (0, 255, 0), "red":(0, 0, 255)}
(real_y, real_x), (resized_y, resized_x) = bgr_image.shape[:2], resized_image.shape[:2]
ratio_x, ratio_y = real_x / resized_x, real_y / resized_y
#rgb_image = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2RGB)
rgb_image = bgr_image
#roi
video_xmax, video_ymax,video_size = 1920-250, 1080-50,500
roi_point=[[video_xmax, video_ymax], [video_xmax, video_ymax-video_size], [video_xmax-video_size, video_ymax-video_size], [video_xmax-video_size, video_ymax]]
roi = Polygon(roi_point)
points = np.array(roi_point, np.int32)
rgb_image = cv2.polylines(rgb_image, pts=[points], isClosed=True, color=colors["blue"], thickness=3)
rgb_image = cv2.putText(rgb_image, "winner-zone", (video_xmax-video_size, video_ymax-video_size-10), cv2.FONT_HERSHEY_SIMPLEX, 1,colors["blue"] , 2, cv2.LINE_AA)
for box in boxes:
conf = box[-1]
if conf > confidence:
(x_min, y_min, x_max, y_max) = [
int(max(corner_position * ratio_y, 10)) if idx % 2
else int(corner_position * ratio_x)
for idx, corner_position in enumerate(box[:-1])
]
if roi.intersects(Polygon([(x_min,y_max),(x_max, y_max),(x_max,y_min),(x_min, y_min)])):
rgb_image = cv2.rectangle(rgb_image, (x_min, y_min), (x_max, y_max), colors["blue"], 3)
rgb_image = cv2.putText(rgb_image, str(int(conf*100))+"%", (x_min, y_min-5), cv2.FONT_HERSHEY_SIMPLEX, 1,colors["blue"] , 2, cv2.LINE_AA)
rgb_image = cv2.putText(rgb_image, "amd yes!!", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1,colors["blue"] , 2, cv2.LINE_AA)
payload = str([x_min, y_min, x_max, y_max])
publish.single(topic, payload, qos=1, hostname=host)
else:
rgb_image = cv2.rectangle(rgb_image, (x_min, y_min), (x_max, y_max), colors["green"], 3)
rgb_image = cv2.putText(rgb_image, str(int(conf*100))+"%", (x_min, y_min-5), cv2.FONT_HERSHEY_SIMPLEX, 1,colors["green"] , 2, cv2.LINE_AA)
#if x_max>1500 and y_max <800:
#rgb_image = cv2.rectangle(rgb_image, (x_min, y_min), (x_max, y_max), colors["blue"], 3)
#rgb_image = cv2.putText(rgb_image, str(int(conf*100))+"%", (x_min, y_min-5), cv2.FONT_HERSHEY_SIMPLEX, 1,colors["blue"] , 2, cv2.LINE_AA)
#else:
#rgb_image = cv2.rectangle(rgb_image, (x_min, y_min), (x_max, y_max), colors["green"], 3)
#rgb_image = cv2.putText(rgb_image, str(int(conf*100))+"%", (x_min, y_min-5), cv2.FONT_HERSHEY_SIMPLEX, 1,colors["green"] , 2, cv2.LINE_AA)
return rgb_image
host = "localhost"
topic = "test"
payload = "amdyes"
ie = Core()
model_xml_path = "model/openvino/openvino.xml"
model = ie.read_model(model=model_xml_path)
model.reshape([1,3,736,992])
compiled_model = ie.compile_model(model=model, device_name="GPU")
input_layer_ir = compiled_model.input(0)
N, C, H, W = (1,3,736,992)
#fourcc = cv2.VideoWriter_fourcc(*'MP4V')
#out = cv2.VideoWriter('result/output_WIN_20240716_16_52_14_Pro.mp4', fourcc, 30.0, (1920,1080))
cap = cv2.VideoCapture('image/WIN_20240716_16_52_14_Pro.mp4')
while cap.isOpened():
ret, image = cap.read()
if not ret:
print("Can't receive frame (stream end?). Exiting ...")
break
resized_image = cv2.resize(image, (W, H))
resized_image = cv2.cvtColor(resized_image, cv2.COLOR_BGR2RGB)
input_image = np.expand_dims(resized_image.transpose(2, 0, 1), 0)
result = compiled_model([input_image])
boxes = result[0][0]
image_detection = draw_bbox(image, resized_image, boxes,0.3)
#out.write(image_detection)
image_detection = cv2.resize(image_detection, (W, H))
cv2.imshow('amd yes', image_detection)
if cv2.waitKey(1) == ord('q'):
break
#out.release()
cap.release()
cv2.destroyAllWindows()
import torch
import torch.nn as nn
import onnxruntime
import numpy as np
import argparse
from utils import (
LoadImages,
non_max_suppression,
plot_images,
output_to_target,
)
import sys
import pathlib
CURRENT_DIR = pathlib.Path(__file__).parent
sys.path.append(str(CURRENT_DIR))
def preprocess(img):
img = torch.from_numpy(img)
img = img.float() # uint8 to fp16/32
img /= 255 # 0 - 255 to 0.0 - 1.0
return img
class DFL(nn.Module):
# Integral module of Distribution Focal Loss (DFL) proposed in Generalized Focal Loss https://ieeexplore.ieee.org/document/9792391
def __init__(self, c1=16):
super().__init__()
self.conv = nn.Conv2d(c1, 1, 1, bias=False).requires_grad_(False)
x = torch.arange(c1, dtype=torch.float)
self.conv.weight.data[:] = nn.Parameter(x.view(1, c1, 1, 1))
self.c1 = c1
def forward(self, x):
b, c, a = x.shape # batch, channels, anchors
return self.conv(x.view(b, 4, self.c1, a).transpose(2, 1).softmax(1)).view(
b, 4, a
)
def dist2bbox(distance, anchor_points, xywh=True, dim=-1):
"""Transform distance(ltrb) to box(xywh or xyxy)."""
lt, rb = torch.split(distance, 2, dim)
x1y1 = anchor_points - lt
x2y2 = anchor_points + rb
if xywh:
c_xy = (x1y1 + x2y2) / 2
wh = x2y2 - x1y1
return torch.cat((c_xy, wh), dim) # xywh bbox
return torch.cat((x1y1, x2y2), dim) # xyxy bbox
def post_process(x):
dfl = DFL(16)
anchors = torch.tensor(
np.load(
"./anchors.npy",
allow_pickle=True,
)
)
strides = torch.tensor(
np.load(
"./strides.npy",
allow_pickle=True,
)
)
box, cls = torch.cat([xi.view(x[0].shape[0], 144, -1) for xi in x], 2).split(
(16 * 4, 80), 1
)
dbox = dist2bbox(dfl(box), anchors.unsqueeze(0), xywh=True, dim=1) * strides
y = torch.cat((dbox, cls.sigmoid()), 1)
return y, x
def make_parser():
parser = argparse.ArgumentParser("onnxruntime inference sample")
parser.add_argument(
"-m",
"--onnx_model",
type=str,
default="./yolov8m.onnx",
help="input your onnx model.",
)
parser.add_argument(
"-i",
"--image_path",
type=str,
default='./demo.jpg',
help="path to your input image.",
)
parser.add_argument(
"-o",
"--output_path",
type=str,
default='./demo_infer.jpg',
help="path to your output directory.",
)
parser.add_argument(
"--ipu", action='store_true', help='flag for ryzen ai'
)
parser.add_argument(
"--provider_config", default='', type=str, help='provider config for ryzen ai'
)
return parser
classnames = ['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']
names = {k: classnames[k] for k in range(80)}
imgsz = [640, 640]
if __name__ == '__main__':
args = make_parser().parse_args()
print(args)
source = args.image_path
dataset = LoadImages(
source, imgsz=imgsz, stride=32, auto=False, transforms=None, vid_stride=1
)
onnx_weight = args.onnx_model
if args.ipu:
providers = ["VitisAIExecutionProvider"]
provider_options = [{"config_file": args.provider_config}]
onnx_model = onnxruntime.InferenceSession(onnx_weight, providers=providers, provider_options=provider_options)
else:
onnx_model = onnxruntime.InferenceSession(onnx_weight)
for batch in dataset:
path, im, im0s, vid_cap, s = batch
im = preprocess(im)
if len(im.shape) == 3:
im = im[None]
# outputs = onnx_model.run(None, {onnx_model.get_inputs()[0].name: im.cpu().numpy()})
# outputs = [torch.tensor(item) for item in outputs]
outputs = onnx_model.run(None, {onnx_model.get_inputs()[0].name: im.permute(0, 2, 3, 1).cpu().numpy()})
outputs = [torch.tensor(item).permute(0, 3, 1, 2) for item in outputs]
preds = post_process(outputs)
preds = non_max_suppression(
preds, 0.25, 0.7, agnostic=False, max_det=300, classes=None
)
plot_images(
im,
*output_to_target(preds, max_det=15),
source,
fname=args.output_path,
names=names,
)
import uuid
import requests
from flask import request, jsonify
from flask.views import MethodView
from flask_smorest import Blueprint, abort
from sqlalchemy.exc import SQLAlchemyError,IntegrityError
from db import db
#from modules.inference import Inference
import json
from schemas import EventSchema,InferenceJobEventSchema
from models import EventModel
import datetime
from shapely.geometry import Polygon
#from multiprocessing import Process
import threading
from threading import Event
import time
from sqlalchemy.exc import SQLAlchemyError, IntegrityError
from db import db
from models import EventModel,InferenceJobModel
import cv2
import grpc
import numpy as np
from tensorflow import make_tensor_proto, make_ndarray
from tensorflow_serving.apis import predict_pb2
from tensorflow_serving.apis import prediction_service_pb2_grpc
from openvino.runtime import Core
from socket_io import socket_io
blp = Blueprint("SIS","sis", description="Stream inference server")
processes = []
check = True
new_process = None
new_socket = None
temp_data = None
exit_event = Event()
last_time = None
class SocketMessage:
def socket_send(self):
global temp_data, exit_event, last_time
while True:
if exit_event.is_set():
exit_event.clear()
break
if last_time == None:
data =[{
"event_type": {
"description": "Alert when detected trespassing",
"id": 1,
"name": "Human detection Alert"
},
"image_shot": {"image":"image"},
"inference_result": [],
"source_media_id_offset": {"media": "media"},
"time": datetime.datetime.now().isoformat()
}]
return data
data =[{
"event_type": {
"description": "Alert when detected trespassing",
"id": 1,
"name": "Human detection Alert"
},
"image_shot": {"image":"image"},
"inference_result": temp_data["inference_result"],
"source_media_id_offset": {"media": "media"},
"time": temp_data["time"]
}]
this_time = data[0]["time"]
print(this_time)
print(last_time)
if last_time == this_time:
data[0]["time"] = datetime.datetime.now().isoformat()
data[0]["inference_result"] = []
else:
last_time = this_time
socket_io.emit('event', data)
socket_io.sleep(1)
def start_inference(self):
socket_io.start_background_task(target=self.socket_send)
def stop_inference(self):
global exit_event
exit_event.set()
@blp.route("/api/inference/start/<int:inference_job_id>")
class Inference_start(MethodView):
def post(self, inference_job_id):
global check, new_process, new_socket
if check == True:
new_process = Inference(inference_job_id)
new_process.start_inference()
processes.append(new_process)
new_socket = SocketMessage()
new_socket.start_inference()
processes.append(new_socket)
print("Start Success!!")
check = False
return ("Success")
else:
return("Error, can only start 1 job")
@blp.route("/api/inference/stop")
class Inference_stop(MethodView):
def post(self):
global check, new_process, new_socket
if not processes:
return("nothing is running")
else:
for p in processes:
p.stop_inference()
processes.clear()
new_process = None
new_socket = None
check = True
print("Stop Success!!")
return ("All process killed")
@blp.route("/api/event/get_by_inference_job/<string:target_inference_job_id>")
class Event(MethodView):
#@blp.response(200, InferenceJobEventSchema(many=True))
@blp.response(200)
def get(self, target_inference_job_id):
global last_time, new_process, temp_data
'''
event = EventModel.query.order_by(EventModel.time.desc()).limit(1).all()
this_time = event[0].time
'''
if last_time == None:
data =[{
"event_type": {
"description": "Alert when detected trespassing",
"id": 1,
"name": "Human detection Alert"
},
"image_shot": {"image":"image"},
"inference_result": [],
"source_media_id_offset": {"media": "media"},
"time": datetime.datetime.now().isoformat()
}]
return data
data =[{
"event_type": {
"description": "Alert when detected trespassing",
"id": 1,
"name": "Human detection Alert"
},
"image_shot": {"image":"image"},
"inference_result": temp_data["inference_result"],
"source_media_id_offset": {"media": "media"},
"time": temp_data["time"]
}]
#event = EventModel(**new_process.event_data)
this_time = data[0]["time"]
print(this_time)
print(last_time)
if last_time == this_time:
data[0]["time"] = datetime.datetime.now().isoformat()
data[0]["inference_result"] = []
else:
last_time = this_time
'''
if last_time == this_time:
event[0].time = datetime.datetime.now()
event[0].inference_result = []
else:
last_time = this_time
'''
return data
@blp.route("/api/event/get_by_inference_job_all/<string:target_inference_job_id>")
class Event2(MethodView):
@blp.response(200, InferenceJobEventSchema(many=True))
def get(self, target_inference_job_id):
global last_time, check, new_process,new_process, temp_data
if check == True:
new_process = Inference(target_inference_job_id)
new_process.start_inference()
processes.append(new_process)
new_socket = SocketMessage()
new_socket.start_inference()
processes.append(new_socket)
print("Start Success!!")
check = False
last_time = None
event = EventModel.query.order_by(EventModel.time.desc()).limit(20).all()
print(event)
if event == []:
event = EventModel.query.order_by(EventModel.time.desc()).limit(20)
last_time = None
else:
last_time = event[0].time
data ={
"time": last_time,
"image_shot": {"img": "img"},
"source_media_id_offset": {"media": "media"},
"inference_result": event[0].inference_result,
"inference_job_id": new_process.job_id,
"event_type_id" : 1
}
temp_data = data
print(temp_data)
#event = EventModel.query.order_by(EventModel.time.desc()).limit(20)
return event
class Inference:
def __init__(self,job_id):
self.interest = None
self.inference = None
self.model = "person-detection-0303"
self.job = InferenceJobModel.query.get_or_404(job_id)
region = self.job.region.first()
camera = region.camera
fence = region.region_sets['fence']
self.fence = Polygon(fence).convex_hull
self.media_url = camera.RTSP
#self.media_url = "./input/videos/test1.avi"
self.job_id = job_id
self.count = 0
self.event_data = None
self.lock = False
def set_interest(self, interest):
self.interest = Polygon(interest).convex_hull
def set_fence(self, fence):
self.fence = Polygon(fence).convex_hull
def convert_to_corners(self,coords):
xmin, ymin, xmax, ymax, confidence = coords
if confidence>=0.4:
return [[xmin, ymin], [xmax, ymin], [xmax, ymax], [xmin, ymax]]
else:
return None
def find_label_index(self, result):
#labels = result_dict["inference_result"]["labels"]
boxes = result["boxes"]
temp = []
#for index, label in enumerate(labels):
for rows in boxes:
'''
if label == 1:
temp.append(self.convert_to_corners(boxes[index]))
'''
corners = self.convert_to_corners(rows)
if corners != None:
temp.append(self.convert_to_corners(rows))
return temp
def send_event(self, result):
global temp_data
self.event_data = {
"time": datetime.datetime.now().isoformat(),
"image_shot": {"img": "img"},
"source_media_id_offset": {"media": "media"},
"inference_result": result,
"inference_job_id": self.job_id,
"event_type_id" : 1
}
temp_data = self.event_data
print("Alert!!")
#print(event_data)
'''
event = EventModel(**self.event_data)
try:
db.session.add(event)
db.session.commit()
except SQLAlchemyError:
print("error when sending event")
self.count = self.count + 1
'''
'''
if self.count == 1500:
subquery = db.session.query(EventModel.time).order_by(EventModel.time.desc()).limit(60).subquery()
delete_query = EventModel.query.filter(~EventModel.time.in_(subquery))
deleted_count = delete_query.delete(synchronize_session=False)
db.session.commit()
self.count = 0
'''
def read_now(self):
return self.event_data
def if_intersect(self,human):
#print("here")
human_poly = Polygon(human).convex_hull
if self.fence.intersects(human_poly):
#print("ALERT!!!!")
self.send_event(human)
def sis(self):
address = "127.0.0.1:9000"
vidcap = cv2.VideoCapture(self.media_url)
ie = Core()
model_xml_path = "./ai-model/openvino.xml"
model = ie.read_model(model=model_xml_path)
model.reshape([1,3,736,992])
compiled_model = ie.compile_model(model=model, device_name="GPU")
input_layer_ir = compiled_model.input(0)
N, C, H, W = (1,3,736,992)
frame_index = 0
while vidcap.isOpened():
success,img = vidcap.read()
if frame_index ==2:
frame_index = 0
continue
frame_index = frame_index + 1
if success:
resized_image = cv2.resize(img, (W, H))
resized_image = cv2.cvtColor(resized_image, cv2.COLOR_BGR2RGB)
input_image = np.expand_dims(resized_image.transpose(2, 0, 1), 0)
result = compiled_model([input_image])
#boxes = result['boxes']
boxes = result[0][0]
#labels = result['labels']
labels = [0]*len(boxes)
#grpc_req = predict_pb2.PredictRequest()
#grpc_req.model_spec.name = self.model
#grpc_req.inputs["image"].CopyFrom(make_tensor_proto(img, shape=(img.shape)))
#result = stub.Predict(grpc_req, 10.0)
#boxes = make_ndarray(result.outputs["boxes"])
#labels = make_ndarray(result.outputs["labels"])
output = {
"boxes":boxes.tolist(),
#"labels":labels.tolist()
"labels":labels
}
#pub = {"video_stream":self.media_url,"frame_index":frame_index,"offset_ms":vidcap.get(cv2.CAP_PROP_POS_MSEC),"inference_result": output}
#pub = {"inference_result": output}
#print(pub)
#pub = json.dumps(pub)+';'
#frame_index = frame_index +1
human = self.find_label_index(output)
for rows in human:
self.if_intersect(rows)
#if human == []:
#print("No Human")
if self.lock == True:
break
'''
pub = {
"mediaurl":self.media_url,
"model":self.model
}
r = requests.post('http://10.10.80.46:5000/api/inference',stream=True, data = pub)
for line in r.iter_content(None,True):
line = line[:-1]
line = ast.literal_eval(line)
human = self.find_label_index(line)
for rows in human:
self.if_intersect(rows)
if human == []:
print("No Human")
'''
def start_inference(self):
#self.inference = Process(target = self.sis)
self.inference = threading.Thread(target= self.sis)
self.inference.start()
def stop_inference(self):
#self.inference.terminate()
self.lock = True
print("test killed")
'''
@blp.route("/api/test/<int:inference_job_id>")
class testingpurpose(MethodView):
def post(self, inference_job_id):
subquery = db.session.query(EventModel.time).order_by(EventModel.time.desc()).limit(20).subquery()
delete_query = EventModel.query.filter(~EventModel.time.in_(subquery))
deleted_count = delete_query.delete(synchronize_session=False)
db.session.commit()
print(deleted_count)
return("safe")
new_process = Inference(inference_job_id)
print(new_process.fence)
print(new_process.media_url)
print(new_process.model)
return("safe")
inference_job = InferenceJobModel.query.get_or_404(inference_job_id)
region = inference_job.region.first()
region_sets = region.region_sets['fence']
camera = region.camera
camera_url = camera.RTSP
print(region_sets)
print(camera_url)
return("test")
region_ids = [region.id for region in inference_job.region.all()]
print(region_ids)
return jsonify({'region_ids': region_ids})
@blp.route("/sis/<string:sis_key_name>")
class Metric(MethodView):
@blp.response(200, SisSchema)
def get(self, sis_key_name):
sis_key_name = SisModel.query.filter_by(name=sis_key_name).all()
return sis_key_name
@blp.route("/sis")
class Sis(MethodView):
@blp.response(200, SisSchema(many=True))
def get(self):
#return SisModel.query.all()
return None
def post(self):
pub = {
"mediaurl":"./input/images/people1.jpg",
"model":"face-detection"
}
r = requests.post('http://10.10.80.228:5000/api/inference',stream=True, data = pub)
sis_data = {}
for line in r.iter_content(None,True): #line is string
line_json = json.loads(line) #convert line from string into dict
sis_data = {
"data" : line_json
}
print(line)
sis = SisModel(**sis_data)
try:
db.session.add(sis)
db.session.commit()
except SQLAlchemyError:
abort(500, message="An error occurred while inserting the sis.")
sis_data = {}
break
return jsonify({'Success': 'successfully added'}), 200
'''
Comments