当前位置: 首页 > news >正文

VM4.4 获取自己的路径

一直再找VisionMaster 脚本获取sol自身路径的办法.无奈一直没找到.今天无聊看文档 发现了一个点,于是紧跟着尝试了一下 发现可以用 所以记录一下过程.

还是老生常谈介绍一下创作背景: 先说VM的模式

1. VM 应用 
	简单应用场景,VM 能够实现业务逻辑,无定制界面需求,无外围(数据库、图表统计)功能需求。
	该模式无需任何开发,轻松上手,调参方便。 
2. VM SDK 开发(亦称 VM 二次开发) 
	用户希望部分业务逻辑由自己实现(例如定位计算等),有定制界面和外围功能需求,或希望把 VM
	嵌入客户开发的软件中。该开发模式代码量少、开发周期较短,且 VM 提供各类流程与参数编辑控件,
	能够满足绝大多数应用需求,是最为推荐的开发模式。 
3. 算子 SDK 开发 
	用户希望全部业务逻辑由自己实现,该开发模式代码量大、开发周期长,海康只提供算子库和少
	量界面控件,能够满足部分应用需求。 
4. 算子模块开发(只支持 C++) 
	用户希望将自己开发的算子封装成模块并能在 VM 中使用(例如拖拽、订阅等),补充项目所需的
	算子功能。该模式需要开发者有一定的算法开发经验和编程功底。 

上面的是官方说辞咱自己也感受了 说一下:

首先4就是自己做一个VM的模块

1就是直接VM拖拉拽托界面 完事直接用VM运行. 我叫它纯VM

2.就是给拖拉拽套一个框该拖拉拽还是一样的,输入输出控制层面暴露出来给外面这个框.

3.类似opencv这种模式.

今天不说2/3/4;说一下1:

一般初级应用都是"纯VM"就部署到现场了,因为现在传统常见应用都要求短平快 你根本没别的时间干其他.

但是纯VM获取自己的路径还是比较棘手的:

获取自己的路径的意义在于 方便管理参数和配置文件;

什么 模板 各种标定文件 存图路径之类的 散乱的存放在机器的各个地方.

得到方案路径的好处:就可以把 工程依赖的所有文件 统一管理.

首先:全局脚本:

using VM.Core;
using VM.PlatformSDKCS;

	    public int Getpath()
        {
			/*
			using System;
			using System.IO;
        	using VM.Core;
			using VM.PlatformSDKCS;
			string strPath = VmSolution.Instance.SolutionPath;
			*/
			VmProcedure pro1 = (VmProcedure)VmSolution.Instance["流程1"];
	        if (pro1 != null)
	        {
	            ProcedureParam proParam = pro1.ModuParams;
	            if (proParam != null)
	            {
	                string filePath;
	                // 获取当前VM 的.sol文件 路径(完整) @"C:\Users\Administrator\Desktop\获取方案路径.sol"
	                 filePath = VmSolution.Instance.SolutionPath;
	                // 流程输入需要设置对应的 变量
	                //设置流程输入string    流程输入 "SOLPath" 
	               proParam.SetInputString("SOLPath0", new InputStringData[] { new InputStringData() { strValue = filePath} });	
	            }
	        }
            return 0;
        }

在初始化和处理函数里面调用一下:

        public int Init()
        {
			Getpath();
            return InitSDK();
        }

        public int Process()
        {
        	
        	Getpath();
            ....................
        }

算了我还是把整个全局脚本放出来吧:

using System; 
using VM.GlobalScript.Methods;
using System.Windows.Forms; 
using iMVS_6000PlatformSDKCS;
using System.Runtime.InteropServices;

using VM.Core;
using VM.PlatformSDKCS;


public class UserGlobalScript : UserGlobalMethods,IScriptMethods
{
	

	    public int Getpath()
        {
			/*
			using System;
			using System.IO;
        	using VM.Core;
			using VM.PlatformSDKCS;
			string strPath = VmSolution.Instance.SolutionPath;
			*/
			VmProcedure pro1 = (VmProcedure)VmSolution.Instance["流程1"];
	        if (pro1 != null)
	        {
	            ProcedureParam proParam = pro1.ModuParams;
	            if (proParam != null)
	            {
	                string filePath;
	                // 获取当前VM 的.sol文件 路径(完整) @"C:\Users\Administrator\Desktop\获取方案路径.sol"
	                 filePath = VmSolution.Instance.SolutionPath;
	                // 流程输入需要设置对应的 变量
	                //设置流程输入string    流程输入 "SOLPath" 
	               proParam.SetInputString("SOLPath0", new InputStringData[] { new InputStringData() { strValue = filePath} });	
	            }
	        }
            return 0;
        }
	
        /// <summary>
        /// Init
        /// </summary>
		/// <returns>Success:return 0</returns>
        public int Init()
        {
			Getpath();
			
            return InitSDK();
            
        }

        /// <summary>
        /// execute function
        /// Single run:the function execute once
        /// Continuous run:Repeat the function at regular intervals
		/// 运行函数
        /// 单次执行:该函数执行一次
        /// 连续执行:以一定时间间隔重复执行该函数
        /// </summary>
		/// <returns>Success:return 0</returns>
        public int Process()
        {
        	
        	Getpath();
        	
        	
        	//m_operateHandle SDK handle
            if (m_operateHandle == IntPtr.Zero)
            {return ImvsSdkPFDefine.IMVS_EC_NULL_PTR;}
			
            //All processes are executed by default
			//If execute in your own define logic,please remove the function :DefaultExecuteProcess, Create your own logic function.
			//默认执行全部流程,
			//如果自定义流程执行逻辑,请移除DefaultExecuteProcess方法,编写自定义流程执行逻辑代码
			int nRet = DefaultExecuteProcess();
			
			return nRet;
        }
        
        /// <summary>
        /// SDK callback function 
        /// </summary>
        public override void ResultDataCallBack(IntPtr outputPlatformInfo, IntPtr puser)
        {
            base.ResultDataCallBack(outputPlatformInfo, puser);
            ImvsSdkPFDefine.IMVS_PF_OUTPUT_PLATFORM_INFO struInfo = (ImvsSdkPFDefine.IMVS_PF_OUTPUT_PLATFORM_INFO)Marshal.PtrToStructure(outputPlatformInfo, typeof(ImvsSdkPFDefine.IMVS_PF_OUTPUT_PLATFORM_INFO));
            switch (struInfo.nInfoType)
            {
                //Get module result
				//获取模块结果数据
                case (uint)ImvsSdkPFDefine.IMVS_CTRLC_OUTPUT_PlATFORM_INFO_TYPE.IMVS_ENUM_CTRLC_OUTPUT_PLATFORM_INFO_MODULE_RESULT:
                    {
                    	ImvsSdkPFDefine.IMVS_PF_MODULE_RESULT_INFO_LIST_P resultInfo = (ImvsSdkPFDefine.IMVS_PF_MODULE_RESULT_INFO_LIST_P)Marshal.PtrToStructure(struInfo.pData, typeof(ImvsSdkPFDefine.IMVS_PF_MODULE_RESULT_INFO_LIST_P));
                    	break;
                    }
                ///Get process execute state
				//获取流程运行状态
                case (uint)ImvsSdkPFDefine.IMVS_CTRLC_OUTPUT_PlATFORM_INFO_TYPE.IMVS_ENUM_CTRLC_OUTPUT_PLATFORM_INFO_WORK_STATE:
                    {
                        ImvsSdkPFDefine.IMVS_PF_MODULE_WORK_STAUS stWorkStatus = (ImvsSdkPFDefine.IMVS_PF_MODULE_WORK_STAUS)Marshal.PtrToStructure(struInfo.pData, typeof(ImvsSdkPFDefine.IMVS_PF_MODULE_WORK_STAUS));
                        break;
                    }
                default:
                    break;
            }
        }
}

这时 工程中只有一个流程名叫 "流程1"

在"流程1"输入设置里面新建一个string"SOLPath0"变量

稍微解释一下:这里只有1个关键点2行程序2个注意事项

filePath = VmSolution.Instance.SolutionPath;//获取sol文件完整路径
//设置流程输入string    流程输入 "SOLPath" 
proParam.SetInputString("SOLPath0", new InputStringData[] { new InputStringData() { strValue = filePath} });	
// 当然 还得保证 第一个流程名叫 "流程1"
// "流程1" 的流程输入得有一个 "SOLPath0"的string变量
VmProcedure pro1 = (VmProcedure)VmSolution.Instance["流程1"];
proParam.SetInputString("SOLPath0", new InputStringData[] { new InputStringData() { strValue = filePath} });	

现在点击VM单次运行不出意外sol完整路径就会传入这个地方,当然你看不见的.

拖入一个脚本模块 输入订阅这个地方,脚本什么也不写;

在点击VM单次运行; 当然你得点击最外面的运行,让全局脚本运行起来,只点击脚本的执行是不妥的.

这时稳稳地看到了VM当前打开sol文件的完整路径了.

用这个路径可以做很多事情,我先来举个例子:

为了当前文章更具有艺术色彩,个人风格,我决定稍微用一点C#和 python把他们 拖下水.

首先用VS 2013 以上都可以[当然你不用VS也可以]:

目的: C# 创建 类库.NET Framrwork 4.6.1 X64 Release

我的工程名:"ScriptINI" 所以生成的目标文件叫"ScriptINI.dll"

附上类库程序:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
// 创建 类库.NET Framrwork 4.6.1
// X64 Release
namespace ScriptINI
{
    /// <summary>
    ///  INI 文件读写类
    /// </summary>
    public static class RWINI
    {
        #region 声明
        [DllImport("kernel32")]
        private static extern long WritePrivateProfileString(string section, string key, string val, string filePath);

        [DllImport("kernel32")]
        private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath);
        #endregion 声明

        public static string path = AppDomain.CurrentDomain.BaseDirectory + "CFG.ini";
        public static string Getcwd = System.Environment.CurrentDirectory;
        static public bool NewWinifolder(string folderPath)//folderPath// 指定你想要检查的文件夹路径
        {
            if (!Directory.Exists(folderPath))// 检查文件夹是否存在
            {
                Directory.CreateDirectory(folderPath);// 如果文件夹不存在,则创建它
                return true;
            }
            else { return false; }
        }

        static public bool IsFolder(string folderPath)//folderPath// 指定你想要检查的文件夹路径
        {
            if (Directory.Exists(folderPath)) { return true; }
            else { return false; }
        }

        /// <summary>
        /// 写INI文件
        /// </summary>
        /// <param name="path">path</param>
        /// <param name="Section">分组节点</param>
        /// <param name="Key">关键字</param>
        /// <param name="Value">值</param>
        static public void Wini(string path, string Section, string Key, string Value)
        {
            WritePrivateProfileString(Section, Key, Value, path);
        }
        /// <summary>
        /// 读取INI文件
        /// </summary>
        /// <param name="path">path</param>
        /// <param name="Section">分组节点</param>
        /// <param name="Key">关键字</param>
        /// <param name="def">缺省值</param>
        /// <returns></returns>
        static public string Rini(string path, string Section, string Key, string def = "")
        {
            StringBuilder temp = new StringBuilder(255);
            int i = GetPrivateProfileString(Section, Key, def, temp, 255, path);
            return temp.ToString();
        }



        /// <summary>
        /// 删除ini文件下所有段落
        /// </summary>
        public static void ClearAllSection(string path)
        {
            Wini(path, null, null, null);
        }
        /// <summary>
        /// 删除ini文件下指定段落下的所有键
        /// </summary>
        /// <param name="Section"></param>
        public static void ClearSection(string path, string Section)
        {
            Wini(path, Section, null, null);
        }


        static public string RWini测试()
        {
            Wini(Getcwd + "\\CFG.ini", "Section", "Key", "Value");
            string x = Rini(Getcwd + "\\CFG.ini", "Section", "Key", "def");
        
            return "";
        }


        /********
                    _minThreshold = Convert.ToInt32(  );
        ********/
    }
}

好了,现在已经生成了一个 ***\ScriptINI\bin\x64\Release\ScriptINI.dll

用C# 调用就算了,意义不大,人生苦短 用python 调用一下C#写的 dll

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 安装python后安装pythonnet 3.7以及以上都可以
import os,sys,time
import clr
import System
print(clr.AddReference(f"{os.getcwd()}\ScriptINI.dll"))#载入后会返回 一个地址
import ScriptINI #这个就是刚才的类 C#写的无所谓 当作python的包拿进来
if __name__ == '__main__':
    ScriptINI.RWINI.NewWinifolder(f"{os.getcwd()}\INI")#创建文件夹
    print(ScriptINI.RWINI.IsFolder(f"{os.getcwd()}\INI"))#测试文件夹
	#测试ini读写接口
    print(ScriptINI.RWINI.path)#显示路径
    print(ScriptINI.RWINI.Getcwd)
    ScriptINI.RWINI.Wini(ScriptINI.RWINI.Getcwd+"\pyCFG.ini", "Section", "Key", "Value");#写入测试
    print(ScriptINI.RWINI.Rini(ScriptINI.RWINI.Getcwd+"\pyCFG.ini", "Section", "Key", "def"))#读取测试
input("结束")	

很顺利的生成了一个文件夹,读写了配置文件.

好 这个例子先留着一会用得到.

接下来 写VM 里面的 脚本 和 python脚本

系统环境是win10毋庸置疑

VM 里 脚本 几乎相当于 C# .net Framework4.6.1 .

VM里面python 几乎相当于 python3.7 X64

几乎相当于是啥意思呢 : 理论上一样 实际行不行你得试 也就是实测.

好,现在开始C#脚本;前面已经通过VM全局脚本获取到了sol文件的完整路径并传到了流程的输入;

脚本订阅流程输入的变量就可以获取到这个字符串;

我现在用 脚本订阅  到变量in0

 接下来贴脚本:  环境配置在注释里面体现 不再重复;

using System;
using System.Text;
using System.Windows.Forms;
using Script.Methods;
/************************************
Shell Module default code: using .NET Framwwork 4.6.1
*************************************/


//using VM.Core;
//using VM.PlatformSDKCS;
// 不要打开脚本模块 在流程编辑器页面(也就是拖拉拽,说模块也行) 选择模块 按 Ctrl+M 会打开一个路径 就是C#脚本模块的运行路径
// 把dll复制进去 一定要复制进去才行 别的地方引用会出问题
// 应该是这个路径
// C:\Program Files\VisionMaster4.4.0\Applications\Module(sp)\x64\Logic\ShellModule
// 刚才写的类库生成的dll 复制进去
// 先添加引用
// 在using ScriptINI

using ScriptINI;

public partial class UserScript:ScriptMethods,IProcessMethods
{
	
	
	public bool Getpram()
    {
		// 计算sol路径
		string directoryPath = System.IO.Path.GetDirectoryName(in0);// 目录路径(完整)
		string fileName = System.IO.Path.GetFileName(in0);// 文件名(包括扩展名)
		string fileNameWithoutExtension = System.IO.Path.GetFileNameWithoutExtension(in0);// 文件名(不包括扩展名)	
		string extension = System.IO.Path.GetExtension(in0);// 扩展名 				
		string configpath=directoryPath+"\\"+"VMCFG.ini"; //配置文件路径
		ScriptINI.RWINI.NewWinifolder(directoryPath+"\\文件夹"); // 创建文件夹
		
		ScriptINI.RWINI.NewWinifolder(directoryPath+"\\"+fileNameWithoutExtension+"Pram");
		
		
		
		if( ScriptINI.RWINI.IsFolder(directoryPath+"\\文件夹"))out5=1;//测试文件夹
		ScriptINI.RWINI.Wini(configpath, "Section", "Key", "Value"); //写入ini
		out6=ScriptINI.RWINI.Rini(configpath, "Section", "Key", "def");// 读取ini
		out0=in0     ;
		out1=directoryPath     ;
		out2=fileName          ;
		out3=fileNameWithoutExtension   ;
		out4=extension	       ;
		out7=configpath;
		
        return true;
    }
	
    int processCount ;  
    public void Init()
    {
        processCount = 0;
    }
    public bool Process()
    {				
		Getpram();
		string directoryPath = System.IO.Path.GetDirectoryName(in0);
		string configpath=directoryPath+"\\"+"VMCFGRun.ini";
		int Run= Convert.ToInt32(ScriptINI.RWINI.Rini(configpath, "Pram", "RUN", "0"));// 读取ini
		Run++;
		ScriptINI.RWINI.Wini(configpath, "Pram", "RUN", Run.ToString()); //写入ini
        return true;
    }
}
                     

 点外面的运行 而不是单独执行脚本.

看运行结果. 是不是和python那个一模一样 但是这个是在 VM 里面的

在 获取方案路径.sol 同级目录创建了文件夹 和 成功创建读写ini配置文件

接下来说VM 里面的python 脚本;

还是刚刚写那个程序: 通过 pythonnet 调用.net接口

python 只需要 py 的main文件跟dll是同级目录就行

VM里面的python 脚本不行  经过实验 你得把 dll 就是刚才生成的ScriptINI.dll复制到

# dll 复制到这个地方
#C:\Program Files\VisionMaster4.4.0\Applications\ModuleProxy\x64\
#Lib\site-packages\clr_loader\ffi\dlls\amd64

clr.AddReference('ScriptINI') 就不会报错了.

接下来一模一样 只是语言不一样 贴脚本 截图 贴结果 结束.

VMpython脚本:

# coding: utf-8
import sys
from ioHelper import *
import os,sys,time
import clr
import System
# dll 复制到这个地方
#C:\Program Files\VisionMaster4.4.0\Applications\ModuleProxy\x64\
#Lib\site-packages\clr_loader\ffi\dlls\amd64
clr.AddReference('ScriptINI')
import ScriptINI
def CFparth(fullpath):
    # 获取目录路径
    directoryPath = os.path.dirname(fullpath)    
    # 获取文件名(包括扩展名)
    fileName = os.path.basename(fullpath)    
    # 获取文件名(不包括扩展名)
    fileNameWithoutExtension = os.path.splitext(fileName)[0]    
    # 获取扩展名
    extension = os.path.splitext(fileName)[1]    
    return directoryPath, fileName, fileNameWithoutExtension, extension
def Process(data) -> int:
    moduleVar = IoHelper(data, INIT_MODULE_VAR)
    globalVar = IoHelper(data, INIT_GLOBAL_VAR)
    localVar = IoHelper(data, INIT_LOCAL_VAR)    
    string=moduleVar.in0
    moduleVar.out1=string
    result = CFparth(string)
    moduleVar.out1=result[0]
    
    ScriptINI.RWINI.Wini(result[0]+"\VMpyCFG.ini", "Section", "Key", "Value")
    moduleVar.out2=ScriptINI.RWINI.Rini(result[0]+"\VMpyCFG.ini", "Section", "Key", "def")
    
    try:
        #PrintMsg("\nUser code start")
        pass
        #PrintMsg("User code end")
    except BaseException as e:
        PrintMsg(e)
    return 0

python脚本截图:

python脚本达到了同样的效果.

当然 获取sol文件路径的目的 1是统一配置文件路径 2是管理 文件 比如后面有 标定文件 或者存图路径 就可以存到 刚刚生成的文件夹中 "获取方案路径Pram" ini文件也可以存在里面 统一管理 不至于同一个工程下依赖文件散乱的存放在磁盘各个角落  也可以 创建 字符串数组 作为脚本输出 后面的 模块 依次订阅  方便 文件的 管理

相关文章:

  • 教务考试管理系统-Sprintboot vue
  • OpenAI Whisper:开启语音转文本的智能时代
  • React
  • <建模软件安装教程1>Blender4.2系列
  • Unity Dots
  • Python使用alembic实现数据库管理
  • docker 常用命令教程
  • LeetCode --- 439周赛
  • 【.NET】WinForms 和 WPF 在性能方面的对比
  • 5、STL中priority_queue的使用方法
  • Unity UGUI下实现精确点击的一种方式
  • 【GIT】non-fast-forward错误
  • python面试常见题目
  • 【RAG】基于向量检索的 RAG (BGE示例)
  • Leetcode 刷题记录 05 —— 普通数组
  • 硬件学习笔记--48 磁保持继电器相关基础知识介绍
  • 【每日学点HarmonyOS Next知识】 状态变量、公共Page、可见区域变化回调、接收参数、拖拽排序控件
  • 前端数据模拟 Mock.js 学习笔记(附带详细)
  • 中小学信息学特长生试卷(C++)
  • 6.聊天室环境安装 - Ubuntu22.04 - elasticsearch(es)的安装和使用
  • 今年前4个月上海对拉美国家进出口总值增长2%
  • 国台办:80年前台湾重归中国版图,80年后不可能让台湾分裂出去
  • 深圳中院回应“退休夫妻月入1.2万负债1.2亿”:其自述因经营不善负债
  • 7月打卡乐高乐园,还可以去千年古镇枫泾参加这个漫画艺术季
  • 中美会谈前都发生了什么?美方为何坐不住了?
  • 呼和浩特推进新一轮国企重组整合:杜绝一项目一公司、一业务一公司