【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】
作为图像处理的engineer来说,有时候我们需要提供上位机软件,有时候需要提供下位机程序,还有一种情况,虽然不多,但是也代表着一种商业合作模式。那就是,部分客户虽然没有算法开发的能力,但是他们还是有一定业务软件开发能力。这个时候,他们需要的其实就是一个算法库。
那对于供应商来说,供应算法库这个肯定是一个基础能力,但是怎么保证自己的算法细节不被别人发现,并且在这过程中又尽可能方便自己的调试,这就是一门学问了。今天,我们简单来聊一下怎么编写算法库。
1、编写算法库
图像算法尽量数据简单一些,但最好不要和平台有太大的联系。如果非要联系,可以再封装一层。在类构造的时候,尽量简单。只有外界设置长度和宽度的时候,才开始设置参数、分配内存。分配的内存也不要释放,只有软件关闭的时候,才去释放内存。算法的接口放在public区域,而算法的细节放在private区域。当然,如果需要调试的话,可以再实现一下dumpImage函数。
class ImageProcess
{
public:
int width_;
int height_;
private:
void* pImage_;
void* pGray_;
void* pEnhanced_;
void* pBinary_;
void* pErode_;
void* pDilate_;
void* pResult_;
public:
ImageProcess()
{
width_ = 0;
height_ = 0;
pImage_ = NULL;
pGray_ = NULL;
pEnhanced_ = NULL;
pBinary_ = NULL;
pErode_ = NULL;
pDilate_ = NULL;
pResult_ = NULL;
}
~ImageProcess()
{
if (pGray_) free(pGray_);
if (pEnhanced_) free(pEnhanced_);
if (pBinary_) free(pBinary_);
if (pErode_) free(pErode_);
if (pDilate_) free(pDilate_);
if (pResult_) free(pResult_);
}
bool initData(int width, int height)
{
pGray_ = (unsigned char*)malloc(width*height);
pEnhanced_ = (unsigned char*)malloc(width*height);
pBinary_ = (unsigned char*)malloc(width*height);
pErode_ = (unsigned char*)malloc(width*height);
pDilate_ = (unsigned char*)malloc(width*height);
// result depend on final output
return true;
}
bool processImage(void* pData, void** ppResult)
{
/* ready to call private function here */
return true;
}
void dumpImage(int level)
{
return;
}
private:
bool generateGrayImage(void* pSrc, void* pDst)
{
return true;
}
bool doEnhancedImage(void* pSrc, void* pDst)
{
return true;
}
bool generateBinaryImage(void* pSrc, void* pDst)
{
return true;
}
bool doErodeImage(void* pSrc, void* pDst)
{
return true;
}
bool doDilateImage(void* pSrc, void* pDst)
{
return true;
}
bool getDataFromImage(void* pDst, void** pResult)
{
return true;
}
};
2、编写给客户的接口
给客户的接口文件,也就是通常所认为的头文件。头文件部分尽量简洁,最好就是类似于linux这种打开、关闭、读、写、控制五种接口。当然,我们今天编写的是图像处理程序,可以更加简单一点。
#ifndef RESULT_H_
#define RESULT_H_
bool initData(int width, int height);
bool processData(void* pData, void** ppResult);
bool getWidth();
bool getHeight();
#endif
整个接口还是非常简洁的,甚至有点过于简洁。这中间的ppResult就是核心。一般来说,图像输出的可以是位置、距离、识别、大小、有没有错误等等,根据实际情况而定。
3、对接口的实现和封装
前面说过ProcessImage是不会给客户的,但是头文件中的内容又过于简单,那么应该怎么处理呢。其实方法非常简单,只需要在cpp文件中实现一个全局变量就可以了,比如像这样,所有的实现细节就不会暴露出来了。
static ImageProcess gImageProcess;
bool initData(int width, int height)
{
return gImageProcess.initData(width, height);
}
bool processData(void* pData, void** ppResult)
{
return gImageProcess.processImage(pData, ppResult);
}
bool getWidth()
{
return gImageProcess.width_;
}
bool getHeight()
{
return gImageProcess.height_;
}