Files
ANSCORE/modules/ANSODEngine/ANSCUSTOMPY.h

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