VisionMaster 支持使用第三方算法来丰富自身的功能。这里使用OpenCV
作为第三方库作为样例进行说明。
VM版本
指定为哪一个版本的VisionMaster
开发自定义模块,当前支持VM3.X
与VM4.X
,根据需要进行选择
模块名称
开发自定义模块的名称,尽量保证见词达意
自定义输入输出
用于定义一些输入输出参数,该试用版本目前仅支持int
、float
与string
三种类型。
结果显示
用于自定输出参数的显示,点击下图中的更新自定义输出
按钮会将自定义输出
进行同步
同步后,如下图:
如果仅仅完成这些操作,数据不会被输出到VisionMaster
的显示区域。为将数据显示到显示区域,需要选中
输出参数前的复选框。如下图:
- 历史结果
- 文本显示
基本参数
结果显示
算法模块输入输出XML配置
中的文本显示
参数的影响。如果在算法模块输入输出XML配置
中的文本显示
处至少勾选了一个输出参数,则此处默认勾选。否则,反之。模板配置界面
自定义运行参数
用于添加模块所使用的算法的参数。点击添加
按钮,增加如下一个参数:
在选择参数类型
,输入参数名称
与显示 名称
之后,点击编辑
列中对应项的单击编辑
按钮,弹出通用类型
对话框。
点击通用类型
对话框,中的确定
按钮后,关闭此对话框,并更新编辑状态
列中对应项的状态。
支持一下类型:
命令按钮
自定义模块
的相关配置自定义模块
的算法工程自定义模块
的UI工程VS2013
及其以上版本打开CustomedModule_CsProj\CustomedModuleCs\CustomedModuleCs.sln
。注意,该工程需要.NET4.6.1
的支持Any CPU
+ Release
CustomedModuleCs
工程CustomedModuleCs.dll
拷贝到使用工具生成的CustomedModule
文件夹中VS2013
及其以上版本打开CustomedModule_CProj\CustomedModule\CustomedModule.sln
。Release
+ x64
Release
+ x64
,并生成工程。AlgorithmModule.cpp
#include
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;
}
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;
}
#include "stdafx.h"
#include "AlgorithmModule.h"
#include
#include
#include "ErrorCodeDefine.h"
#include "iMVS-6000PixelFormatDefine.h"
#include
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;
}
}
/模块须导出的接口(实现结束)//
CustomedModule
文件夹拷贝到C:\Program Files\VisionMaster4.0.0\Applications\Module(sp)\x64\UserTools
文件夹中opencv_world310.dll
到C:\Program Files\VisionMaster4.0.0\Applications\PublicFile\x64
。如果将自定义模块拖拽到流程图中提示找不到模块,需要重启电脑。