在前面出现的融合方法中,最突出的问题就是每次运算,都须要将整个推断的过程所有操做一遍,这样确定是费时间的——因此咱们须要将可以独立的地方独立出来,可是这个过中很是容易出现溢出的错误——通过一段时间的尝试,终于获得了相对稳定的结果,这里将结果记录下来:
一、原始状态:
咱们已经将算法融合到了MFC中,而且可以发挥做用:
// 用于推断的函数
Mat CGOMfcTemplate2Dlg
:
:IEInfer(Mat m_mainframe)
{
//初始化IE
// --------------------------- 1.为IE准备插件-------------------------------------
InferencePlugin plugin(PluginDispatcher().getSuitablePlugin(TargetDevice
:
:eCPU));
plugin.AddExtension(std
:
:make_shared
<Extensions
:
:Cpu
:
:CpuExtensions
>());
//Extension,useful
// --------------------------- 2.读取IR模型(xml和bin)---------------------------------
CNNNetReader networkReader;
networkReader.ReadNetwork(
"./road-segmentation-adas-0001.xml");
networkReader.ReadWeights(
"./road-segmentation-adas-0001.bin");
CNNNetwork network
= networkReader.getNetwork();
// --------------------------- 3. 准备输入输出的------------------------------------------
InputsDataMap inputInfo(network.getInputsInfo());
//得到输入信息
if (inputInfo.size()
!=
1)
throw std
:
:logic_error(
"错误,该模型应该为单输入");
auto lrInputInfoItem
= inputInfo[
"data"];
//开始读入
int w
=
static_cast
<
int
>(lrInputInfoItem
-
>getTensorDesc().getDims()[
3]);
//模型要求的输入大小
int h
=
static_cast
<
int
>(lrInputInfoItem
-
>getTensorDesc().getDims()[
2]);
network.setBatchSize(
1);
//只有1副图片,故BatchSize = 1
//准备输出数据
OutputsDataMap outputInfo(network.getOutputsInfo());
//得到输出信息
std
:
:string firstOutputName;
for (
auto
&item
: outputInfo) {
if (firstOutputName.empty()) {
firstOutputName
= item.first;
}
DataPtr outputData
= item.second;
if (
!outputData) {
throw std
:
:logic_error(
"错误的格式,请检查!");
}
item.second
-
>setPrecision(Precision
:
:FP32);
}
// --------------------------- 4. 读取模型 ------------------------------------------(目视第4步骤最消耗时间)
ExecutableNetwork executableNetwork
= plugin.LoadNetwork(network, {});
// --------------------------- 5. 建立推断 -------------------------------------------------
infer_request
= executableNetwork.CreateInferRequest();
// --------------------------- 6. 将数据塞入模型 -------------------------------------------------
Blob
:
:Ptr lrInputBlob
= infer_request.GetBlob(
"data");
//data这个名字是我看出来的,实际上这里能够更统一一些
matU8ToBlob
<float_t
>(m_mainframe, lrInputBlob,
0);
//重要的转换函数,第3个参数是batchSize,应该是本身+1的
// --------------------------- 7. 推断结果 -------------------------------------------------
infer_request.Infer();
//多张图片屡次推断
// --------------------------- 8. 处理结果-------------------------------------------------------
const Blob
:
:Ptr outputBlob
= infer_request.GetBlob(firstOutputName);
const
auto outputData
= outputBlob
-
>buffer().as
<PrecisionTrait
<Precision
:
:FP32
>
:
:value_type
*
>();
size_t numOfImages
= outputBlob
-
>getTensorDesc().getDims()[
0];
size_t numOfChannels
= outputBlob
-
>getTensorDesc().getDims()[
1];
h
= outputBlob
-
>getTensorDesc().getDims()[
2];
w
= outputBlob
-
>getTensorDesc().getDims()[
3];
size_t nunOfPixels
= w
* h;
//写在内存里的结果,仍是要拼出来的
std
:
:vector
<cv
:
:Mat
> imgPlanes{ cv
:
:Mat(h, w, CV_32FC1,
&(outputData[
0])),
cv
:
:Mat(h, w, CV_32FC1,
&(outputData[nunOfPixels])),
cv
:
:Mat(h, w, CV_32FC1,
&(outputData[nunOfPixels
*
2])) };
for (
auto
& img
: imgPlanes)
//原本是平的
img.convertTo(img, CV_8UC1,
255);
cv
:
:Mat resultImg;
cv
:
:merge(imgPlanes, resultImg);
return resultImg;
}
这样一段代码,包含了1-8所有8个步骤,能够在具体的状况下被触发(好比按下某个按键)
须要注意,运行代码以后再正常退出,会报这样一个错误,多是和系统某种资源没有销毁相关。
二、初步设想:
可是这样很是低效,因此要提升效率。通过分析研究,最为消耗时间的一步为
// --------------------------- 4. 读取模型 ------------------------------------------(目视第4步骤最消耗时间)
ExecutableNetwork executableNetwork = plugin.LoadNetwork(network, {});
因此但愿可以将这步前调到Oninitdialog中,这样每次运行过程当中,针对不一样输入,只须要运行
// --------------------------- 7. 推断结果 -------------------------------------------------
infer_request.Infer();//多张图片屡次推断
而后将后面的结果进行显示就能够了。
三、容易出错:
简单的想法是直接将executableNetwork变成全局变量,而且在initdialog中申明完成,觉得这样就可以将耗时的操做解决在
init阶段。
可是很是常见的方法是这个。
四、解决方法:
实际上我没有专门想出一个什么方法解决这个问题,我作了较多实验,不断去验证设想,最后发现这个方法可以达到目标。
将前面的1-4步分解为如下函数(经过这个过程,发现原来代码里面一些不须要的部分):
CNNNetwork CGOMfcTemplate2Dlg
:
:IENetWork(string strXML, string strBIN)
{
CNNNetReader networkReader;
networkReader.ReadNetwork(strXML);
networkReader.ReadWeights(strBIN);
CNNNetwork network
= networkReader.getNetwork();
return network;
}
string CGOMfcTemplate2Dlg
:
:IENetSetup(CNNNetwork network)
{
InputsDataMap inputInfo(network.getInputsInfo());
//得到输入信息
BlobMap inputBlobs;
//保持全部输入的blob数据
if (inputInfo.size()
!=
1)
throw std
:
:logic_error(
"错误,该模型应该为单输入");
auto lrInputInfoItem
= inputInfo[
"data"];
//开始读入
int h
=
static_cast
<
int
>(lrInputInfoItem
-
>getTensorDesc().getDims()[
2]);
int w
=
static_cast
<
int
>(lrInputInfoItem
-
>getTensorDesc().getDims()[
3]);
//模型要求的输入大小
network.setBatchSize(
1);
//只有1副图片,故BatchSize = 1
//准备输出数据
OutputsDataMap outputInfo(network.getOutputsInfo());
//得到输出信息
std
:
:string firstOutputName;
for (
auto
&item
: outputInfo) {
if (firstOutputName.empty()) {
firstOutputName
= item.first;
}
DataPtr outputData
= item.second;
if (
!outputData) {
throw std
:
:logic_error(
"错误的格式,请检查!");
}
item.second
-
>setPrecision(Precision
:
:FP32);
}
return firstOutputName;
}
InferencePlugin CGOMfcTemplate2Dlg
:
:IEplugin(CNNNetwork network)
{
InferencePlugin plugin(PluginDispatcher().getSuitablePlugin(TargetDevice
:
:eCPU));
plugin.AddExtension(std
:
:make_shared
<Extensions
:
:Cpu
:
:CpuExtensions
>());
//Extension,useful
return plugin;
}
ExecutableNetwork CGOMfcTemplate2Dlg
:
:getNetWork(InferencePlugin plugin, CNNNetwork network)
{
ExecutableNetwork executableNetwork
= plugin.LoadNetwork(network, {});
return executableNetwork;
}
然后分别在oninitdialog和业务代码中这样执行
std
:
:string firstOutputName
= IENetSetup(network);
InferRequest infer_request
= executableNetwork.CreateInferRequest();
Blob
:
:Ptr lrInputBlob
= infer_request.GetBlob(
"data");
matU8ToBlob
<float_t
>(m_mainframe, lrInputBlob,
0);
//重要的转换函数,第3个参数是batchSize,应该是本身+1的
// ---------------------------推断结果 -------------------------------------------------
infer_request.Infer();
//多张图片屡次推断
// ---------------------------处理结果-------------------------------------------------------
const Blob
:
:Ptr outputBlob
= infer_request.GetBlob(firstOutputName);
const
auto outputData
= outputBlob
-
>buffer().as
<PrecisionTrait
<Precision
:
:FP32
>
:
:value_type
*
>();
size_t numOfImages
= outputBlob
-
>getTensorDesc().getDims()[
0];
size_t numOfChannels
= outputBlob
-
>getTensorDesc().getDims()[
1];
int h
= outputBlob
-
>getTensorDesc().getDims()[
2];
int w
= outputBlob
-
>getTensorDesc().getDims()[
3];
size_t nunOfPixels
= w
* h;
//写在内存里的结果,仍是要拼出来的
std
:
:vector
<cv
:
:Mat
> imgPlanes{ cv
:
:Mat(h, w, CV_32FC1,
&(outputData[
0])),
cv
:
:Mat(h, w, CV_32FC1,
&(outputData[nunOfPixels])),
cv
:
:Mat(h, w, CV_32FC1,
&(outputData[nunOfPixels
*
2])) };
for (
auto
& img
: imgPlanes)
//原本是平的
img.convertTo(img, CV_8UC1,
255);
cv
:
:Mat resultImg;
cv
:
:merge(imgPlanes, resultImg);
showImage(resultImg, IDC_PIC);
//显示原始图像
这个结果,的确是提升了运算的效率。
而且可以直接嵌入摄像头循环:
//摄像头显示循环,全部关于采集的操做是经过主线程传递控制变量到采集线程,然后由采集线程完成的
DWORD WINAPI CaptureThread(LPVOID lpParameter)
{
CGOMfcTemplate2Dlg
* pDlg
= (CGOMfcTemplate2Dlg
*)lpParameter;
double t_start
= (
double)cv
:
:getTickCount();
//开始时间
Mat tmpPrydown;
//#pragma omp parallel for
while (
true)
{
if (pDlg
-
>b_closeCam)
//退出循环
break;
double t
= ((
double)cv
:
:getTickCount()
- t_start)
/ getTickFrequency();
if (t
<
=
0.
1)
//fps =10,主动下降速度
{
Sleep(
100);
continue;
}
else
{
t_start
= (
double)cv
:
:getTickCount();
}
//从directX中得到当前图像并显示出来
IplImage
* queryframe
= pDlg
-
>cameraDs.QueryFrame();
//在2.0版本中能够强转,在3.0中须要使用函数
Mat camframe
= cvarrToMat(queryframe);
pDlg
-
>showImage(camframe, IDC_CAM);
//显示原始图像
////根据条件,决定是否采用算法
Mat dst;
Mat img;
Mat tmp;
Mat divideGaussMin;
Mat divideGaussMiddle;
Mat divideGaussMax;
cvtColor(camframe, img, COLOR_BGR2GRAY);
cvtColor(img, img, COLOR_GRAY2BGR);
if (pDlg
-
>bMethod)
//这里实现的是灰度转彩色
{
//算法
if (img.empty())
{
return
-
1;
}
std
:
:string firstOutputName
= pDlg
-
>IENetSetup(pDlg
-
>network);
InferRequest infer_request
= pDlg
-
>executableNetwork.CreateInferRequest();
Blob
:
:Ptr lrInputBlob
= infer_request.GetBlob(
"data");
matU8ToBlob
<float_t
>(img, lrInputBlob,
0);
//重要的转换函数,第3个参数是batchSize,应该是本身+1的
// ---------------------------推断结果 -------------------------------------------------
infer_request.Infer();
//多张图片屡次推断
// ---------------------------处理结果-------------------------------------------------------
const Blob
:
:Ptr outputBlob
= infer_request.GetBlob(firstOutputName);
const
auto outputData
= outputBlob
-
>buffer().as
<PrecisionTrait
<Precision
:
:FP32
>
:
:value_type
*
>();
size_t numOfImages
= outputBlob
-
>getTensorDesc().getDims()[
0];
size_t numOfChannels
= outputBlob
-
>getTensorDesc().getDims()[
1];
int h
= outputBlob
-
>getTensorDesc().getDims()[
2];
int w
= outputBlob
-
>getTensorDesc().getDims()[
3];
size_t nunOfPixels
= w
* h;
//写在内存里的结果,仍是要拼出来的
std
:
:vector
<cv
:
:Mat
> imgPlanes{ cv
:
:Mat(h, w, CV_32FC1,
&(outputData[
0])),
cv
:
:Mat(h, w, CV_32FC1,
&(outputData[nunOfPixels])),
cv
:
:Mat(h, w, CV_32FC1,
&(outputData[nunOfPixels
*
2])) };
for (
auto
& img
: imgPlanes)
//原本是平的
img.convertTo(img, CV_8UC1,
255);
cv
:
:merge(imgPlanes, dst);
}
else
{
dst
= img.clone();
}
pDlg
-
>showImage(dst, IDC_PIC);
//显示网络处理图像
}
return
0;
}
最后的结果是实时效果。那么这里的东西是能够复用的。
五、小结反思。
获得最后这个结果比较满意,这也是不断尝试的结果。问题产生的缘由多是多方面的,目前也只是获得了基本的解决方法;更系统的方法应该是类化,这个会在后面处理级联问题的时候遇到;而我这里总结出来的函数化的方法,对于解决单模型简单问题,应该已是可用的了。
可以看到这里的,必定是遇到了相似问题的同事,那也是对相关问题有较为深刻研究的了。
感谢阅读至此,但愿有所帮助。
附件列表