340 lines
10 KiB
C++
340 lines
10 KiB
C++
#ifndef ANSCUSTOMPY_H
|
|
#define ANSCUSTOMPY_H
|
|
#pragma once
|
|
#include "ANSEngineCommon.h"
|
|
#include <iostream>
|
|
#include <iomanip>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <queue>
|
|
#include <fstream>
|
|
#include <thread>
|
|
#include <future>
|
|
#include <atomic>
|
|
#include <mutex>
|
|
#include <cmath>
|
|
#include <opencv2/opencv.hpp>
|
|
#include <pybind11/embed.h>
|
|
namespace py = pybind11;
|
|
namespace ANSCENTER {
|
|
struct ModelWrapper {
|
|
std::unordered_map<int, std::shared_ptr<pybind11::object>> map;
|
|
std::function<pybind11::object()> modelFactory;
|
|
};
|
|
|
|
class PythonRuntime {
|
|
public:
|
|
static bool IsInitialized();
|
|
static void Shutdown();
|
|
void AddToSysPath(const std::string& path);
|
|
friend PythonRuntime& GetPythonRuntime(const std::wstring& pythonHome);
|
|
private:
|
|
explicit PythonRuntime(const std::wstring& home);
|
|
void InitializeInterpreter();
|
|
void PatchPythonStreamsSafe();
|
|
|
|
static std::once_flag initFlag;
|
|
static std::unique_ptr<PythonRuntime> instance;
|
|
static std::atomic<bool> _isInitialized;
|
|
static std::atomic<bool> shuttingDown;
|
|
static std::mutex _instanceMutex;
|
|
|
|
std::wstring pythonHome;
|
|
};
|
|
|
|
PythonRuntime& GetPythonRuntime(const std::wstring& pythonHome);
|
|
|
|
class ANSENGINE_API ANSCUSTOMPY : public ANSODBase {
|
|
public:
|
|
ANSCUSTOMPY();
|
|
~ANSCUSTOMPY();
|
|
bool Initialize(std::string licenseKey, ModelConfig modelConfig, const std::string& modelZipFilePath,
|
|
const std::string& modelZipPassword, std::string& labelMap) override;
|
|
bool LoadModel(const std::string& modelZipFilePath, const std::string& modelZipPassword) override;
|
|
bool LoadModelFromFolder(std::string licenseKey, ModelConfig modelConfig, std::string modelName,
|
|
std::string className, const std::string& modelFolder, std::string& labelMap) override;
|
|
|
|
bool ConfigureParameters(Params& param) override;
|
|
bool SetParameters(const Params& param) override;
|
|
bool OptimizeModel(bool fp16, std::string& optimizedModelFolder);
|
|
std::vector<Object> RunInference(const cv::Mat& input) override;
|
|
std::vector<Object> RunInference(const cv::Mat& input, const std::string& camera_id) override;
|
|
|
|
bool Destroy() override;
|
|
static void SafeShutdownAll(bool waitForShutdown);
|
|
|
|
private:
|
|
bool _destroyed = false;
|
|
bool _isInitialized = false;
|
|
std::recursive_mutex _mutex;
|
|
|
|
pybind11::object pyModelClass;
|
|
std::shared_ptr<ModelWrapper> _wrapper;
|
|
int _instanceId;
|
|
|
|
std::string _scriptPath;
|
|
std::string _moduleName;
|
|
|
|
bool InitializePythonModel(const std::string& moduleName, const std::string& fullPath);
|
|
pybind11::object GetThreadLocalModel();
|
|
bool EnsureModelReady(const std::string& methodName);
|
|
void ClearThreadState();
|
|
|
|
void RegisterSelf();
|
|
void UnregisterSelf();
|
|
|
|
std::string RunPythonInferenceFromMat(const cv::Mat& image);
|
|
|
|
static std::mutex _globalInstancesMutex;
|
|
static std::unordered_set<ANSCUSTOMPY*> _globalInstances;
|
|
static std::atomic<int> globalInstanceCounter;
|
|
};
|
|
} // namespace ANSCENTER
|
|
|
|
#endif // ANSCUSTOMPY_H
|
|
//import numpy as np
|
|
//import os
|
|
//import json
|
|
//from ultralytics import YOLO
|
|
//from typing import List
|
|
//
|
|
//class ROIPoint :
|
|
// def __init__(self, x, y) :
|
|
// self.x = x
|
|
// self.y = y
|
|
//
|
|
// def to_dict(self) :
|
|
// return { "x": self.x, "y" : self.y }
|
|
//
|
|
// class ROIConfig :
|
|
// def __init__(self, rectangle, polygon, line, min_items, max_items, name, roi_match) :
|
|
// self.Rectangle = rectangle
|
|
// self.Polygon = polygon
|
|
// self.Line = line
|
|
// self.MinItems = min_items
|
|
// self.MaxItems = max_items
|
|
// self.Name = name
|
|
// self.ROI_Match = roi_match
|
|
//
|
|
// def to_dict(self) :
|
|
// return {
|
|
// "Rectangle": self.Rectangle,
|
|
// "Polygon" : self.Polygon,
|
|
// "Line" : self.Line,
|
|
// "MinItems" : self.MinItems,
|
|
// "MaxItems" : self.MaxItems,
|
|
// "Name" : self.Name,
|
|
// "ROI-Match" : self.ROI_Match
|
|
//}
|
|
//
|
|
//class Parameter :
|
|
// def __init__(self, name, datatype, no_of_decimals, max_val, min_val, start_val, list_items, default_val, value) :
|
|
// self.Name = name
|
|
// self.DataType = datatype
|
|
// self.NoOfdecimals = no_of_decimals
|
|
// self.MaxValue = max_val
|
|
// self.MinValue = min_val
|
|
// self.StartValue = start_val
|
|
// self.ListItems = list_items
|
|
// self.DefaultValue = default_val
|
|
// self.Value = value
|
|
//
|
|
// def to_dict(self) :
|
|
// return {
|
|
// "Name": self.Name,
|
|
// "DataType" : self.DataType,
|
|
// "NoOfdecimals" : self.NoOfdecimals,
|
|
// "MaxValue" : self.MaxValue,
|
|
// "MinValue" : self.MinValue,
|
|
// "StartValue" : self.StartValue,
|
|
// "ListItems" : self.ListItems,
|
|
// "DefaultValue" : self.DefaultValue,
|
|
// "Value" : self.Value
|
|
//}
|
|
//
|
|
//class ROIValue :
|
|
// def __init__(self, roi_match, roi_points, option, name, original_image_size) :
|
|
// self.ROI_Match = roi_match
|
|
// self.ROIPoints = roi_points # list of ROIPoint
|
|
// self.Option = option
|
|
// self.Name = name
|
|
// self.OriginalImageSize = original_image_size
|
|
//
|
|
// def to_dict(self) :
|
|
// return {
|
|
// "ROI-Match": self.ROI_Match,
|
|
// "ROIPoints" : [p.to_dict() for p in self.ROIPoints] ,
|
|
// "Option" : self.Option,
|
|
// "Name" : self.Name,
|
|
// "OriginalImageSize" : self.OriginalImageSize
|
|
//}
|
|
//
|
|
//class Params :
|
|
// def __init__(self) :
|
|
// self.ROI_Config : List[ROIConfig] = []
|
|
// self.ROI_Options : List[str] = []
|
|
// self.Parameters : List[Parameter] = []
|
|
// self.ROI_Values : List[ROIValue] = []
|
|
//
|
|
// def to_dict(self) :
|
|
// return {
|
|
// "ROI_Config": [cfg.to_dict() for cfg in self.ROI_Config] ,
|
|
// "ROI_Options" : self.ROI_Options,
|
|
// "Parameters" : [p.to_dict() for p in self.Parameters] ,
|
|
// "ROI_Values" : [v.to_dict() for v in self.ROI_Values]
|
|
//}
|
|
//
|
|
//def to_json(self) :
|
|
// return json.dumps(self.to_dict(), indent = 2)
|
|
//
|
|
// class ANSModel :
|
|
// def __init__(self, model_name = "yolo11n.pt") :
|
|
// current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
// model_path = os.path.join(current_dir, model_name)
|
|
// self.model = YOLO(model_path)
|
|
//
|
|
// # Define empty but structured parameter dictionary
|
|
// self.params = {
|
|
// "ROI_Config": [] ,
|
|
// "ROI_Options" : [] ,
|
|
// "Parameters" : [] ,
|
|
// "ROI_Values" : []
|
|
//}
|
|
//
|
|
//def run_inference(self, image_bytes: bytes, width : int, height : int, channels : int)->str:
|
|
//np_arr = np.frombuffer(image_bytes, dtype = np.uint8)
|
|
//image = np_arr.reshape((height, width, channels))
|
|
//
|
|
//results = self.model(image)
|
|
//output = { "results": [] }
|
|
//
|
|
//for result in results :
|
|
//for box in result.boxes :
|
|
// cls_id = int(box.cls[0])
|
|
// conf = float(box.conf[0])
|
|
// class_name = self.model.names[cls_id]
|
|
// x1, y1, x2, y2 = box.xyxy[0].tolist()
|
|
// x = int(x1)
|
|
// y = int(y1)
|
|
// w = int(x2 - x1)
|
|
// h = int(y2 - y1)
|
|
//
|
|
// output["results"].append({
|
|
// "class_id": cls_id,
|
|
// "track_id" : -1,
|
|
// "class_name" : class_name,
|
|
// "prob" : conf,
|
|
// "x" : x,
|
|
// "y" : y,
|
|
// "width" : w,
|
|
// "height" : h,
|
|
// "mask" : "",
|
|
// "extra_info" : "",
|
|
// "camera_id" : "",
|
|
// "polygon" : "",
|
|
// "kps" : ""
|
|
// })
|
|
//
|
|
// return json.dumps(output)
|
|
//
|
|
// def model_optimize(self, fp16: bool) -> bool:
|
|
//try :
|
|
// print(f"[model_optimize] Called with fp16={fp16}")
|
|
// # self.model.export(...) # real optimization here
|
|
// return True
|
|
// except Exception as e :
|
|
//print(f"[model_optimize] Error: {e}")
|
|
//return False
|
|
//
|
|
//def configureParameters(self)->str :
|
|
//# --- Add ROI_Config entries ---
|
|
// self.params["ROI_Config"].append({
|
|
// "Rectangle": True,
|
|
// "Polygon" : True,
|
|
// "Line" : False,
|
|
// "MinItems" : 0,
|
|
// "MaxItems" : 3,
|
|
// "Name" : "Traffic Light",
|
|
// "ROI-Match" : "All Corners"
|
|
// })
|
|
//
|
|
// self.params["ROI_Config"].append({
|
|
// "Rectangle": True,
|
|
// "Polygon" : False,
|
|
// "Line" : False,
|
|
// "MinItems" : 1,
|
|
// "MaxItems" : 1,
|
|
// "Name" : "Car Zone",
|
|
// "ROI-Match" : "All Corners"
|
|
// })
|
|
//
|
|
// self.params["ROI_Config"].append({
|
|
// "Rectangle": False,
|
|
// "Polygon" : False,
|
|
// "Line" : True,
|
|
// "MinItems" : 1,
|
|
// "MaxItems" : 2,
|
|
// "Name" : "Cross Line",
|
|
// "ROI-Match" : "All Corners"
|
|
// })
|
|
//
|
|
//# --- Add ROI_Options entries ---
|
|
// self.params["ROI_Options"] += ["Inside ROI", "Inside ROI", "Both Directions"]
|
|
//
|
|
//# --- Add Parameters entries ---
|
|
// self.params["Parameters"].append({
|
|
// "Name": "Para1",
|
|
// "DataType" : "Boolean",
|
|
// "NoOfdecimals" : 0,
|
|
// "MaxValue" : 0,
|
|
// "MinValue" : 0,
|
|
// "StartValue" : "",
|
|
// "ListItems" : [] ,
|
|
// "DefaultValue" : "",
|
|
// "Value" : "true"
|
|
// })
|
|
//
|
|
// self.params["Parameters"].append({
|
|
// "Name": "Para2",
|
|
// "DataType" : "Integer",
|
|
// "NoOfdecimals" : 0,
|
|
// "MaxValue" : 5,
|
|
// "MinValue" : 1,
|
|
// "StartValue" : "2",
|
|
// "ListItems" : [] ,
|
|
// "DefaultValue" : "",
|
|
// "Value" : "3"
|
|
// })
|
|
//
|
|
// self.params["Parameters"].append({
|
|
// "Name": "Para3",
|
|
// "DataType" : "List-Single",
|
|
// "NoOfdecimals" : 0,
|
|
// "MaxValue" : 0,
|
|
// "MinValue" : 0,
|
|
// "StartValue" : "",
|
|
// "ListItems" : ["A", "B", "C"] ,
|
|
// "DefaultValue" : "",
|
|
// "Value" : "A"
|
|
// })
|
|
//
|
|
// self.params["Parameters"].append({
|
|
// "Name": "Para4",
|
|
// "DataType" : "Range",
|
|
// "NoOfdecimals" : 0,
|
|
// "MaxValue" : 100,
|
|
// "MinValue" : 50,
|
|
// "StartValue" : ">,60",
|
|
// "ListItems" : [">", "<"] ,
|
|
// "DefaultValue" : "",
|
|
// "Value" : ">,52.000000"
|
|
// })
|
|
// return json.dumps(self.params)
|
|
//
|
|
// def setParameters(self, json_str: str) -> bool:
|
|
//try :
|
|
// self.params = json.loads(json_str)
|
|
// return True
|
|
// except Exception as e :
|
|
//print(f"[setParameters] Failed to parse parameters: {e}")
|
|
//return False
|