【VisionMaster】二次开发之第三方库的使用

VisionMaster 支持使用第三方算法来丰富自身的功能。这里使用OpenCV作为第三方库作为样例进行说明。

1. 生成算子框架

1.1 启动自定义模块生成工具

  • 打开VisionMaster,并找到 菜单栏 >> 工具菜单 >> 自定义模板生成工具
    在这里插入图片描述
  • 打开`自定义模块生成工具
    在这里插入图片描述

1.2 自定义模块生成工具参数说明

1.2.1 算法模块输入输出XML配置

  • VM版本
    指定为哪一个版本的VisionMaster开发自定义模块,当前支持VM3.XVM4.X,根据需要进行选择

  • 模块名称
    开发自定义模块的名称,尽量保证见词达意

  • 输入图像
    自定义模块是否支持图像输入,即是否包含下图中的输入。 在这里插入图片描述

  • 位置修正信息
    是否支持使用位置修正模块对该模块进行ROI的动态跟随。 在这里插入图片描述

  • 模块状态
    只是模块的运行状态,运行成功为1,运行失败为0
    在这里插入图片描述

  • 图像输出
    指定该模块是否有输出图像。具有输出图像的模块,可在显示窗口的选择栏中进行选择显示
    在这里插入图片描述

  • 自定义输入输出
    用于定义一些输入输出参数,该试用版本目前仅支持intfloatstring三种类型。

  • 输入参数
    在这里插入图片描述

  • 输入参数说明>在这里插入图片描述

    • 参数名称
      代码中获取或设置该参数时使用的名称
    • 显示名称
      UI界面上显示的名称
    • 参数类型
      参数的类型,在代码中获取参数时,需要根据类型选择对应的函数
    • 输入/输出
      指定该参数是用于输入还是输出
    • 输出参数
      在这里插入图片描述
  • 结果显示
    用于自定输出参数的显示,点击下图中的更新自定义输出按钮会将自定义输出进行同步
    在这里插入图片描述
    同步后,如下图:
    在这里插入图片描述
    如果仅仅完成这些操作,数据不会被输出到VisionMaster的显示区域。为将数据显示到显示区域,需要选中输出参数前的复选框。如下图:
    在这里插入图片描述

    • 当前结果
      在这里插入图片描述

在这里插入图片描述

- 历史结果

在这里插入图片描述

在这里插入图片描述

- 文本显示

在这里插入图片描述

在这里插入图片描述

1.2.2 算法模块界面XML配置

在这里插入图片描述

  • 基本参数

    • 输入图像源
      不可更改,与算法模块输入输出XML配置中的输入图像源参数保持一致

    • 矩形ROI
      在这里插入图片描述

    • 多边形ROI
      在这里插入图片描述

    • 圆环ROI
      在这里插入图片描述

    • 圆卡尺ROI
      在这里插入图片描述

    • 直线卡尺ROI
      在这里插入图片描述

    • 屏蔽区
      在这里插入图片描述

    • 位置修正
      不可更改,与算法模块输入输出XML配置中的位置修正参数保持一致

  • 结果显示

    • 文本显示
      不可更改,受算法模块输入输出XML配置中的文本显示参数的影响。如果在算法模块输入输出XML配置中的文本显示处至少勾选了一个输出参数,则此处默认勾选。否则,反之。
  • 模板配置界面

    • 模板配置
      是否在配置中插入特征模板选项卡。
      在这里插入图片描述
  • 自定义运行参数
    用于添加模块所使用的算法的参数。点击添加按钮,增加如下一个参数:
    在这里插入图片描述
    在选择参数类型,输入参数名称显示 名称之后,点击编辑列中对应项的单击编辑按钮,弹出通用类型对话框。
    在这里插入图片描述
    点击通用类型对话框,中的确定按钮后,关闭此对话框,并更新编辑状态列中对应项的状态。
    在这里插入图片描述
    支持一下类型:

    • int
    • float
    • bool
    • string
    • enumeration
    • intBetween
    • floatBetween
  • 命令按钮

    • 生成XML
      用于生成自定义模块的相关配置
    • 生成C++工程
      用于生成自定义模块的算法工程
    • 生成C#工程
      用于生成自定义模块的UI工程

    依次点击这个三个命令后,生成如下文件
    在这里插入图片描述

2. 编译工程

2.1 编译UI工程

  • 使用VS2013及其以上版本打开CustomedModule_CsProj\CustomedModuleCs\CustomedModuleCs.sln。注意,该工程需要.NET4.6.1的支持
  • 将编译类型切换为Any CPU + Release在这里插入图片描述
  • 编译CustomedModuleCs工程
    在这里插入图片描述
  • 将生成的CustomedModuleCs.dll拷贝到使用工具生成的CustomedModule文件夹中
    在这里插入图片描述

2.2 编译算法工程

  • 使用VS2013及其以上版本打开CustomedModule_CProj\CustomedModule\CustomedModule.sln
  • 属性页配置Release + x64
    在这里插入图片描述
  • 配置OpenCV头目录
    在这里插入图片描述
  • 配置OpenCV库目录
    在这里插入图片描述
  • 配置OpenCV依赖项
    在这里插入图片描述
  • 切换编译配置到Release + x64,并生成工程。
    在这里插入图片描述
  • 打开源文件AlgorithmModule.cpp
  • 添加OpenCV头文件
#include <opencv2\opencv.hpp>

using namespace cv;
  • OpenCV::Mat与HKA_IMAGE互转
Mat HKAImageToMat(HKA_IMAGE hik_image)
{
	Mat mat;
	if (hik_image.format == HKA_IMG_MONO_08)
	{
		mat = Mat(hik_image.height, hik_image.width, CV_8UC1, hik_image.data[0]);
		int a = mat.cols;
	}
	else if (hik_image.format == HKA_IMG_RGB_RGB24_C3)
	{
		mat = Mat(hik_image.height, hik_image.width, CV_8UC3, hik_image.data[0]);
	}
	return mat;
}

HKA_IMAGE MatToHKAImage(Mat mat)
{
	HKA_IMAGE image;
	if (mat.channels() == 1)
	{
		image = { HKA_IMG_MONO_08, 0 };
		image.width = mat.cols;
		image.height = mat.rows;
		image.format = HKA_IMG_MONO_08;
		image.step[0] = mat.cols;
		image.data[0] = mat.data;
	}
	else if (mat.channels() == 3)
	{
		image = { HKA_IMG_RGB_RGB24_C3, 0 };
		image.width = mat.cols;
		image.height = mat.rows;
		image.format = HKA_IMG_RGB_RGB24_C3;
		image.step[0] = 3 * mat.cols;
		image.data[0] = mat.data;
	}
	return image;
}
  • 根据模块要求修改CAlgorithmModule::Process函数,这里仅演示二值化功能
int CAlgorithmModule::Process(IN void* hInput, IN void* hOutput, IN MVDSDK_BASE_MODU_INPUT* modu_input)
{
	OutputDebugStringA("###Call CAlgorithmModule::Proces -->begin\n");
	int nErrCode = 0;

	// 1.获取图像
	HKA_IMAGE			struInputImg;
	HKA_S32             nRet = IMVS_EC_UNKNOWN;
	HKA_U32             nImageStatus = 0;
	do
	{
		nRet = VmModule_GetInputImageByName(hInput, "InImage", "InImageWidth", "InImageHeight", "InImagePixelFormat", &struInputImg, &nImageStatus);
		HKA_CHECK_BREAK(IMVS_EC_OK != nRet);
	} while (0);

	// 2. 图像转换
	Mat input_image = HKAImageToMat(struInputImg);

	// 3. 获取输入参数
	int count = -1;

	int inputInt = -1;
	nRet = VM_M_GetInt(hInput, "InputInt", 0, &inputInt, &count);

	float inputFloat = 0;
	nRet = VM_M_GetFloat(hInput, "InputFloat", 0, &inputFloat, &count);

	
	int inputString1Length = 100;
	char inputString1[100];
	nRet = VM_M_GetString(hInput, "InputString", 0, inputString1, 100, &inputString1Length, &count);

	// 4. 获取运行参数
	auto runParam1 = this->m_nRunInt;

	// 5. 算法处理
	OutputDebugStringA("###Call CAlgorithmModule::Proces --> do algorighm process\n");

	Mat binary;
	cv::threshold(input_image, binary, 128, 255, cv::THRESH_BINARY);


	// 6. 输出图像格式转换
	HKA_IMAGE output_image = MatToHKAImage(binary);

	// 7. 输出图像
	if (MVD_PIXEL_MONO_08 == modu_input->pImageInObj->GetPixelFormat())
	{
		VmModule_OutputImageByName_8u_C1R(hOutput, 1, "OutImage", "OutImageWidth", "OutImageHeight", "OutImagePixelFormat", &output_image);
	}
	else if (MVD_PIXEL_RGB_RGB24_C3 == modu_input->pImageInObj->GetPixelFormat())
	{
		VmModule_OutputImageByName_8u_C3R(hOutput, 1, "OutImage", "OutImageWidth", "OutImageHeight", "OutImagePixelFormat", &output_image);
	}

	// 8. 设置自定义输出参数
	VM_M_SetInt(hOutput, "OutputInt", 0, 77);
	VM_M_SetFloat(hOutput, "OutputFloat", 0, 3.1425f);
	VM_M_SetString(hOutput, "OutputString", 0, "OK");

	// 9. 设置模块运行状态
	VM_M_SetInt(hOutput, "ModuStatus", 0, nErrCode == 0 ? 1 : nErrCode);


	if (nErrCode != IMVS_EC_OK)
	{
		return IMVS_EC_PARAM;
	}

	/************************************************/
	//默认算法时间20ms,根据实际时间计算
	MODULE_RUNTIME_INFO struRunInfo = { 0 };
	struRunInfo.fAlgorithmTime = 20;
	VM_M_SetModuleRuntimeInfo(m_hModule, &struRunInfo);

	OutputDebugStringA("###Call CAlgorithmModule::Proces end\n");

	return IMVS_EC_OK;
}
  • 编译生成算法工程
    在这里插入图片描述

  • 将生成的CustomedModule.dllCustomedModule.pdb文件拷贝到使用工具生成的CustomedModule文件夹中
    在这里插入图片描述

  • 完整源码

#include "stdafx.h"
#include "AlgorithmModule.h"
#include <stdlib.h>
#include <fstream>
#include "ErrorCodeDefine.h"
#include "iMVS-6000PixelFormatDefine.h"

#include <opencv2\opencv.hpp>

using namespace cv;

Mat HKAImageToMat(HKA_IMAGE hik_image)
{
	Mat mat;
	if (hik_image.format == HKA_IMG_MONO_08)
	{
		mat = Mat(hik_image.height, hik_image.width, CV_8UC1, hik_image.data[0]);
		int a = mat.cols;
	}
	else if (hik_image.format == HKA_IMG_RGB_RGB24_C3)
	{
		mat = Mat(hik_image.height, hik_image.width, CV_8UC3, hik_image.data[0]);
	}
	return mat;
}

HKA_IMAGE MatToHKAImage(Mat mat)
{
	HKA_IMAGE image;
	if (mat.channels() == 1)
	{
		image = { HKA_IMG_MONO_08, 0 };
		image.width = mat.cols;
		image.height = mat.rows;
		image.format = HKA_IMG_MONO_08;
		image.step[0] = mat.cols;
		image.data[0] = mat.data;
	}
	else if (mat.channels() == 3)
	{
		image = { HKA_IMG_RGB_RGB24_C3, 0 };
		image.width = mat.cols;
		image.height = mat.rows;
		image.format = HKA_IMG_RGB_RGB24_C3;
		image.step[0] = 3 * mat.cols;
		image.data[0] = mat.data;
	}
	return image;
}


int GetInputImage(IN void* hInput, HKA_IMAGE& struInputImg)
{
	HKA_S32             nRet = IMVS_EC_UNKNOWN;
	HKA_U32             nImageStatus = 0;

	do
	{
		nRet = VmModule_GetInputImageByName(hInput, "InImage", "InImageWidth", "InImageHeight", "InImagePixelFormat", &struInputImg, &nImageStatus);
		HKA_CHECK_BREAK(IMVS_EC_OK != nRet);
	} while (0);

	return nRet;
}

CAlgorithmModule::CAlgorithmModule()
{
	m_nRunInt = 50;
}

CAlgorithmModule::~CAlgorithmModule()
{

}

int CAlgorithmModule::Init()
{
	PARAM_VALUE_INFO_LIST stList = { 0 };
	int nRet = VM_M_GetDefaultConfigByFile(m_hModule, UNICODEtoUTF8(VmModule_GetXmlPath().GetBuffer()), &stList);
	if (nRet == IMVS_EC_OK)
	{
		for (int i = 0; i < stList.nNum; i++)
		{
			SetParam(stList.paramValueList[i].byParamName, stList.paramValueList[i].byParamValue, strlen(stList.paramValueList[i].byParamValue));
		}
	}

	return nRet;
}

int CAlgorithmModule::Process(IN void* hInput, IN void* hOutput, IN MVDSDK_BASE_MODU_INPUT* modu_input)
{
	OutputDebugStringA("###Call CAlgorithmModule::Proces -->begin\n");
	int nErrCode = 0;

	// 1.获取图像
	HKA_IMAGE			struInputImg;
	HKA_S32             nRet = IMVS_EC_UNKNOWN;
	HKA_U32             nImageStatus = 0;
	do
	{
		nRet = VmModule_GetInputImageByName(hInput, "InImage", "InImageWidth", "InImageHeight", "InImagePixelFormat", &struInputImg, &nImageStatus);
		HKA_CHECK_BREAK(IMVS_EC_OK != nRet);
	} while (0);

	// 2. 图像转换
	Mat input_image = HKAImageToMat(struInputImg);

	// 3. 获取输入参数
	int count = -1;

	int inputInt = -1;
	nRet = VM_M_GetInt(hInput, "InputInt", 0, &inputInt, &count);

	float inputFloat = 0;
	nRet = VM_M_GetFloat(hInput, "InputFloat", 0, &inputFloat, &count);

	
	int inputString1Length = 100;
	char inputString1[100];
	nRet = VM_M_GetString(hInput, "InputString", 0, inputString1, 100, &inputString1Length, &count);

	// 4. 获取运行参数
	auto runParam1 = this->m_nRunInt;

	// 5. 算法处理
	OutputDebugStringA("###Call CAlgorithmModule::Proces --> do algorighm process\n");

	Mat binary;
	cv::threshold(input_image, binary, 128, 255, cv::THRESH_BINARY);


	// 6. 输出图像格式转换
	HKA_IMAGE output_image = MatToHKAImage(binary);

	// 7. 输出图像
	if (MVD_PIXEL_MONO_08 == modu_input->pImageInObj->GetPixelFormat())
	{
		VmModule_OutputImageByName_8u_C1R(hOutput, 1, "OutImage", "OutImageWidth", "OutImageHeight", "OutImagePixelFormat", &output_image);
	}
	else if (MVD_PIXEL_RGB_RGB24_C3 == modu_input->pImageInObj->GetPixelFormat())
	{
		VmModule_OutputImageByName_8u_C3R(hOutput, 1, "OutImage", "OutImageWidth", "OutImageHeight", "OutImagePixelFormat", &output_image);
	}

	// 8. 设置自定义输出参数
	VM_M_SetInt(hOutput, "OutputInt", 0, 77);
	VM_M_SetFloat(hOutput, "OutputFloat", 0, 3.1425f);
	VM_M_SetString(hOutput, "OutputString", 0, "OK");

	// 9. 设置模块运行状态
	VM_M_SetInt(hOutput, "ModuStatus", 0, nErrCode == 0 ? 1 : nErrCode);


	if (nErrCode != IMVS_EC_OK)
	{
		return IMVS_EC_PARAM;
	}

	/************************************************/
	//默认算法时间20ms,根据实际时间计算
	MODULE_RUNTIME_INFO struRunInfo = { 0 };
	struRunInfo.fAlgorithmTime = 20;
	VM_M_SetModuleRuntimeInfo(m_hModule, &struRunInfo);

	OutputDebugStringA("###Call CAlgorithmModule::Proces end\n");

	return IMVS_EC_OK;
}


int CAlgorithmModule::GetParam(IN const char* szParamName, OUT char* pBuff, IN int nBuffSize, OUT int* pDataLen)
{
	OutputDebugStringA("###Call CAlgorithmModule::GetParam");

	int nErrCode = IMVS_EC_OK;
	if (szParamName == NULL || strlen(szParamName) == 0 || pBuff == NULL || nBuffSize <= 0 || pDataLen == NULL)
	{
		return IMVS_EC_PARAM;
	}
 	//memset(pBuff, 0, nBuffSize);

	if (0 == strcmp("RunInt", szParamName))
	{
		sprintf_s(pBuff, nBuffSize, "%d", m_nRunInt);
	}
	else
	{
		return CVmAlgModuleBase::GetParam(szParamName, pBuff, nBuffSize, pDataLen);
	}
	
	return nErrCode;
}

int CAlgorithmModule::SetParam(IN const char* szParamName, IN const char* pData, IN int nDataLen)
{
	OutputDebugStringA("###Call CAlgorithmModule::SetParam");

	int nErrCode = IMVS_EC_OK;
	if (szParamName == NULL || strlen(szParamName) == 0 || pData == NULL || nDataLen == 0)
	{
		return IMVS_EC_PARAM;
	}

	if (0 == strcmp("RunInt", szParamName))
	{
		sscanf_s(pData, "%d", &m_nRunInt);
	}
	else
	{
		return CVmAlgModuleBase::SetParam(szParamName, pData, nDataLen);
	}

	return nErrCode;
}


/模块须导出的接口(实现开始)//

LINEMODULE_API CAbstractUserModule* __stdcall CreateModule(void* hModule)
{
	assert(hModule != NULL);
   

	// 创建用户模块,并记录实例。
	CAlgorithmModule* pUserModule = new(nothrow) CAlgorithmModule;

	if (pUserModule == NULL)
	{
		return NULL;
	}

	pUserModule->m_hModule = hModule;

	int nRet = pUserModule->Init();
	if (IMVS_EC_OK != nRet)
	{
		delete pUserModule;
		return NULL;
	}

	printf("[ LineModule ] CreateModule, hModule = 0x%x, pUserModule = 0x%x \n", hModule, pUserModule);

	OutputDebugStringA("###Call CreateModule");

	return pUserModule;
}


LINEMODULE_API void __stdcall DestroyModule(void* hModule, CAbstractUserModule* pUserModule)
{
	assert(hModule != NULL);

	printf("\n[ LineModule ] DestroyModule, hModule = 0x%x\n", hModule);

	OutputDebugStringA("###Call DestroyModule");

	if (pUserModule != NULL)
	{
		delete pUserModule;
	}
}
/模块须导出的接口(实现结束)//

3. 模块导入

  • CustomedModule文件夹拷贝到C:\Program Files\VisionMaster4.0.0\Applications\Module(sp)\x64\UserTools文件夹中
    在这里插入图片描述
  • 拷贝opencv_world310.dllC:\Program Files\VisionMaster4.0.0\Applications\PublicFile\x64。如果将自定义模块拖拽到流程图中提示找不到模块,需要重启电脑。
    在这里插入图片描述

4. 模块测试

  • 将自定义工具拖入流程图中
    在这里插入图片描述
  • 配置类似如下的方案
    在这里插入图片描述
  • 打开自定义模块,显示如下
    在这里插入图片描述
  • 配置自定义输入参数
    在这里插入图片描述
  • 点击运行按钮,查看结果
    在这里插入图片描述

5. 调试自定义模块算法

  • 配置好方案,并打开自定模块

  • VS2013及其以上版本打开算法工程

  • 选择附件到进程
    在这里插入图片描述

  • 选择VmModuleProxy.exe
    在这里插入图片描述

  • 在源代码的合适位置,打上断点
    在这里插入图片描述

  • 运行自定义模块
    在这里插入图片描述

  • 查看是否进入断点调试中
    在这里插入图片描述

  • 16
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论
VisionMaster是一种先进的视觉处理软件,可以进行图像分析、图像处理和目标识别等功能。而VisionMaster二次开发,则是指在原有软件基础上进行定制化开发和功能扩展。 VisionMaster二次开发可以根据不同用户的需求进行个性化定制。通过二次开发,可以将软件与用户现有的系统进行集成,实现与其他设备的数据交互和信息共享。开发人员可以根据用户需求,增加新的图像处理算法和功能模块,提供更加专业和精确的图像处理服务。 另外,VisionMaster二次开发还可以适应不同行业的需求。比如,在医疗行业中,可以通过开发特定功能模块,实现医学图像的自动识别和分析,为医生提供更准确、更快速的诊断结果。在工业领域中,可以通过二次开发,实现对工业产品的质量检测和生产过程的自动化控制。 此外,VisionMaster二次开发还有助于提高工作效率和降低成本。通过开发自动化的图像处理流程和算法,可以减少人工操作的时间和成本。同时,通过定制化开发,可以实现对特定场景的快速识别和分析,提高工作效率和准确性。 综上所述,VisionMaster二次开发具有灵活性、定制化和高效性的优势。无论是应用于特定行业,还是用于个性化需求,二次开发都可以使VisionMaster软件更好地适应用户的实际需求,并为用户带来更多价值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhy29563

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值