VisionMaster自定义模块

一、参考资料:

1、教学视频

VisionMaster自定义模块_第1张图片

2、VM服务管家

【VM服务管家】VM4.x算法模块开发_4.3 联合Halcon开发-CSDN博客问题:有的用户在使用VisionMaster软件在开发视觉项目时,可能同时也使用HALCON,OpenCV等视觉算法库做一些图像的处理,并且希望能将HALCON等第三方算子集成到VM工具箱,能够在VM工具箱中拖拽出来,就像VisionMaster中的其他算法模块工具一样,可以通过弹出窗口配置运行参数,通过连线订阅其他模块传递的参数,设置ROI,通过图像窗口查看算法直接结果的渲染效果。实际上是可行的,VisionMaster是一个开放平台,可以接入第三方生态,这也是VisionMaster的一大亮点。https://blog.csdn.net/MVExpert/article/details/130413120

 3、二次开发之第三方库的使用

【VisionMaster】二次开发之第三方库的使用_visionmaster二次开发-CSDN博客二次开发之第三方库的使用_visionmaster二次开发https://blog.csdn.net/zhy29563/article/details/124115483

4、开发文档

VisionMaster自定义模块_第2张图片

二、一些注意的点

1、输出变量的定义

VisionMaster自定义模块_第3张图片

 2、多个ROI的实现

VisionMaster自定义模块_第4张图片

本来是Single,说明只有一个ROI,我改成Mul之后,就可以多个ROI了

3、设置halcon字符识别全局变量

VisionMaster自定义模块_第5张图片

下图中,再Init函数种,放入那两个函数,还是有必要的,防止每次运行该模块,都会耗费时间create

VisionMaster自定义模块_第6张图片

三、一些代码

1、头文件

#ifdef EXAMPLEMODULE_EXPORTS
#define LINEMODULE_API __declspec(dllexport)
#else
#define LINEMODULE_API __declspec(dllimport)
#endif
#include "VmModuleBase.h"
#include "VmAlgModuBase.h"
#include "ErrorCodeDefine.h"
#include "VmModuleSharedMemoryBase.h"

#include "halconcpp.h"
using namespace HalconCpp;

// This class is exported from the LineModule.dll
class LINEMODULE_API CAlgorithmModule : public CVmAlgModuleBase, public CModuleSharedMemoryBase
{
public:
	// 构造
	explicit CAlgorithmModule();
	
	// 析构
	virtual ~CAlgorithmModule();

public:

	// 初始化
	int Init();

	// 进行算法
	int Process(IN void* hInput, IN void* hOutput, IN MVDSDK_BASE_MODU_INPUT* modu_input);

	// 获取算法参数
	int GetParam(IN const char* szParamName, OUT char* pBuff, IN int nBuffSize, OUT int* pDataLen);

	// 设置算法参数
	int SetParam(IN const char* szParamName, IN const char* pData, IN int nDataLen);

	//获取halcon格式图像,高恩阳的函数
	HObject GetHalconImage(MVDSDK_BASE_MODU_INPUT* modu_input);

	//我的DeepOCR
	string MyDeepOCR(IN HObject in);

	void set_suitable_device_in_ocr_handle(HTuple hv_DeepOcrHandle);

public:
	//void* m_hModule;   // 模块句柄 - 4.3 在基类中定义了


private:

	int m_ntheta;
	HTuple  hv_DeepOcrHandle;

};


/模块须导出的接口(实现开始)//
#ifdef __cplusplus
extern "C"
{
#endif
    
    // 采用__stdcall调用约定,且须在.def文件中增加接口描述。
	LINEMODULE_API CAbstractUserModule* __stdcall CreateModule(void* hModule);
	LINEMODULE_API void __stdcall DestroyModule(void* hModule, CAbstractUserModule* pUserModule);

#ifdef __cplusplus
};
#endif
/模块须导出的接口(实现结束)//

 2、cpp文件

#include "stdafx.h"
#include "AlgorithmModule.h"
#include 
#include 
#include "ErrorCodeDefine.h"
#include "iMVS-6000PixelFormatDefine.h"


#include
#include
#include
#include
#include
using namespace std;



CAlgorithmModule::CAlgorithmModule()
{
	m_ntheta = 128;
}

CAlgorithmModule::~CAlgorithmModule()
{

}

int CAlgorithmModule::Init()
{

	int nRet = VM_M_GetModuleId(m_hModule, &m_nModuleId);
	if (IMVS_EC_OK != nRet)
	{
		m_nModuleId = -1;
		return nRet;
	}

	nRet = ResetDefaultParam();
	if (nRet != IMVS_EC_OK)
	{
		OutputDebugStringA("###Call ResetDefaultParam failed.");
	}

	CreateDeepOcr(HTuple(), HTuple(), &hv_DeepOcrHandle);
	set_suitable_device_in_ocr_handle(hv_DeepOcrHandle);


	return nRet;
}

HObject CAlgorithmModule::GetHalconImage(MVDSDK_BASE_MODU_INPUT* modu_input)
{
	HObject ho_image;
	GenEmptyObj(&ho_image);

	if (modu_input->pImageInObj->GetImageData(0)->pData != nullptr)
	{
		if (MVD_PIXEL_MONO_08== modu_input->pImageInObj->GetPixelFormat())
		{
			GenImage1(&ho_image
				, "byte"
				, static_cast(modu_input->pImageInObj->GetWidth())
				, static_cast(modu_input->pImageInObj->GetHeight())
				, reinterpret_cast(modu_input->pImageInObj->GetImageData(0)->pData)
			);
		}

		if (MVD_PIXEL_RGB_RGB24_C3 == modu_input->pImageInObj->GetPixelFormat())
		{
			GenImage3(&ho_image
				, "byte"
				, static_cast(modu_input->pImageInObj->GetWidth())
				, static_cast(modu_input->pImageInObj->GetHeight())
				, reinterpret_cast(modu_input->pImageInObj->GetImageData(0)->pData)
				, reinterpret_cast(modu_input->pImageInObj->GetImageData(1)->pData)
				, reinterpret_cast(modu_input->pImageInObj->GetImageData(2)->pData)

			);
		}
	}

	return ho_image;
	
}

string CAlgorithmModule::MyDeepOCR(IN HObject in)
{

	HTuple  hv_DeepOcrResult;
	HTuple  hv_RecognizedWords,hv_RecognizedWord;

	ApplyDeepOcr(in, hv_DeepOcrHandle, "auto", &hv_DeepOcrResult);
	GetDictTuple(hv_DeepOcrResult, "words", &hv_RecognizedWords);
	GetDictTuple(hv_RecognizedWords, "word", &hv_RecognizedWord);
	int wordCount = hv_RecognizedWord.Length(); 
	string strBuff;
	for (size_t i = 0; i < wordCount; i++)
	{
		strBuff += hv_RecognizedWord[i].S();
	}

	return strBuff;
}

void CAlgorithmModule::set_suitable_device_in_ocr_handle(HTuple hv_DeepOcrHandle)
{

	// Local control variables
	HTuple  hv_DLDeviceHandles, hv_RecognitionImageWidthDefault;
	HTuple  hv_Exception, hv_Index;

	//Determine deep learning device to work with (prefer GPU over CPU).
	QueryAvailableDlDevices((HTuple("runtime").Append("runtime")), (HTuple("gpu").Append("cpu")),
		&hv_DLDeviceHandles);
	if (0 != (int((hv_DLDeviceHandles.TupleLength()) == 0)))
	{
		throw HException("No supported device found to continue this example.");
	}
	//Set recognition_image_width larger for the example to work without memory problems.
	try
	{
		GetDeepOcrParam(hv_DeepOcrHandle, "recognition_image_width", &hv_RecognitionImageWidthDefault);
		SetDeepOcrParam(hv_DeepOcrHandle, "recognition_image_width", 250);
	}
	// catch (Exception) 
	catch (HException& HDevExpDefaultException)
	{
		HDevExpDefaultException.ToHTuple(&hv_Exception);
	}
	//
	{
		HTuple end_val12 = (hv_DLDeviceHandles.TupleLength()) - 1;
		HTuple step_val12 = 1;
		for (hv_Index = 0; hv_Index.Continue(end_val12, step_val12); hv_Index += step_val12)
		{
			try
			{
				SetDeepOcrParam(hv_DeepOcrHandle, "device", HTuple(hv_DLDeviceHandles[hv_Index]));
				break;
			}
			// catch (Exception) 
			catch (HException& HDevExpDefaultException)
			{
				HDevExpDefaultException.ToHTuple(&hv_Exception);
				if (0 != (int(hv_Index == ((hv_DLDeviceHandles.TupleLength()) - 1))))
				{
					throw HException("Could not set any of the supported devices to continue this example.");
				}
			}
		}
	}
	//Reset recognition_image_width to the default value.
	try
	{
		SetDeepOcrParam(hv_DeepOcrHandle, "recognition_image_width", hv_RecognitionImageWidthDefault);
	}
	// catch (Exception) 
	catch (HException& HDevExpDefaultException)
	{
		HDevExpDefaultException.ToHTuple(&hv_Exception);
	}
	//
	return;
}

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.获取输入
	
	/************************************************/

	//ToDo Code...............
	HObject myImage=GetHalconImage(modu_input);
    int nsize = modu_input->vtFixRoiShapeObj.size();

	/************************************************/

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

	/************************************************/
	for (size_t i = 0; i < nsize; i++)
	{
		IMvdRectangleF* rectangleRoi = dynamic_cast(modu_input->vtFixRoiShapeObj[i]);
		int width = rectangleRoi->GetWidth();
		int height = rectangleRoi->GetHeight();
		int centerX = rectangleRoi->GetCenterX();
		int centerY = rectangleRoi->GetCenterY();
		HObject rect,imageReduced,imageCroped;
		GenRectangle2(&rect, centerY, centerX, 0, width / 2, height / 2);
		HTuple Row1, Column1, Row2, Column2;
		SmallestRectangle1(rect, &Row1, &Column1, &Row2, &Column2);
		CropRectangle1(myImage, &imageCroped, Row1, Column1, Row2, Column2);
		ReduceDomain(myImage, rect, &imageReduced);
		//if (0 == i)
		//{
		//	WriteImage(imageCroped, "bmp", 0, "D:\\gao\\ocr0");
		//}
		//if (1 == i)
		//{
		//	WriteImage(imageCroped, "bmp", 0, "D:\\gao\\ocr1");
		//}
		//if (2 == i)
		//{
		//	WriteImage(imageCroped, "bmp", 0, "D:\\gao\\ocr2");
		//}
		//if (3 == i)
		//{
		//	WriteImage(imageCroped, "bmp", 0, "D:\\gao\\ocr3");
		//}
		//if (4 == i)
		//{
		//	WriteImage(imageCroped, "bmp", 0, "D:\\gao\\ocr4");
		//}

		

		string ocrStr = MyDeepOCR(imageCroped);

		ofstream file1;
		//file1.open("D:\\gao\\car.txt", ios::app);      //   所有输出附加在文件末尾,用追加的方式写入,
		//   写入追加的结果以换行的方式往下添加
		if (file1.is_open())
		{
			cout << "正确打开文件! " << endl;
			file1 << ocrStr << endl;

		}
		file1.close();


		const char* p = ocrStr.data();
		VM_M_SetString(hOutput, "mystring", i, p);
	}
	//ToDo Code...............

	/************************************************/


// 3.输出结果
	
	/************************************************/

	//ToDo Code...............

    //输出图像(渲染控件只能显示共享内存中的图像数据)
        //char* pSharedName = NULL;
        //HKA_IMAGE stImage;
        //stImage.height = heightValue;
        //stImage.width = widthValue;
        //stImage.step[0] = widthValue;
        //int nRet = AllocateSharedMemory(m_nModuleId, stImage.height*stImage.width, (char**)(&stImage.data), &pSharedName);
        //if (nRet == IMVS_EC_OK && stImage.data != NULL)
        //{
        //    memcpy_s(......);
        //    VmModule_OutputImageByName_8u_C1R(hOutput, 
		//		  status, 
		//		  OUTIMAGE, 
		//		  OUTIMAGEWIDTH, 
		//		  OUTIMAGEHEIGHT, 
		//		  OUTIMAGEPIXELFORMAT, 
		//		  &stImage, 
		//		  0, 
		//		  pSharedName);
        //}


	/************************************************/

	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 nMsgLen = 0;
	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("theta", szParamName))
	{
		sprintf_s(pBuff, nBuffSize, "%d", m_ntheta);
	}
	else
	{
		return CVmAlgModuleBase::GetParam(szParamName, pBuff, nBuffSize, pDataLen);
	}
	//if(0 == strcmp(szParamName, "paramA"))
	//{
	//	  sprintf(pBuff, nBuffSize, "", ..);
	//}
	
	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("theta", szParamName))
	{
		sscanf_s(pData, "%d", &m_ntheta);
	}
	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;
	}

	OutputDebugStringA("###Call CreateModule");

	return pUserModule;
}


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

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

你可能感兴趣的:(visionmaster)