【问题标题】:Grayscale image classification with neural network on Android with OpenCV使用 OpenCV 在 Android 上使用神经网络进行灰度图像分类
【发布时间】:2019-01-22 01:52:24
【问题描述】:

我正在开发一个可以数字化纸张数字的安卓应用。我使用本机 OpenCV 代码来查找图像上的数字。之后我想使用 OpenCV 的 dnn 模块来识别号码。可以在此处找到有关创建神经网络的精彩教程:
https://www.youtube.com/watch?v=kFWKdLOxykE
mnist_convnet_graph.pbtxt 开头是这样的:

node {
  name: "conv2d_1_input"
  op: "Placeholder"
  attr {
    key: "dtype"
    value {
    type: DT_FLOAT
  }
  }
  attr {
    key: "shape"
    value {
      shape {
        dim {
          size: -1
        }
        dim {
          size: 28
        }
        dim {
          size: 28
        }
        dim {
          size: 1
        }
      }
    }
  }
}

所以输入是 28x28 灰度图像。
在教程中,java 代码用于使用神经网络。但是,由于速度的原因,我想在 C++ 中使用它。我使用 cv::dnn::Net Dnn.readNetFromTensorflow(String model, String config); 成功加载了模型并将对象传递到 NDK 端。我使用以下内容为神经网络创建输入:

// The part of the image, we are interested in.
Rect roi(static_cast<int>(w), static_cast<int>(h),
             static_cast<int>(w), static_cast<int>(h));
Mat cropped(image_gray, roi);
// Resize image to 28x28.
Mat resized;
cv::resize(cropped, resized, Size(28,28));

之后,转发应该可以工作了:

const double IN_SCALE_FACTOR = 0.003921; // 1.0/255.0
Mat blob = dnn::blobFromImage(resized, IN_SCALE_FACTOR, Size(28,28));
net.setInput(blob);
Mat detections = net.forward();

其中 net 是传递的 cv::dnn::Net 对象。但是 net.forward() 命令失败并给出:
OpenCV(3.4.5) 错误:虚拟布尔 cv::dnn::experimental_dnn_34_v11::DataLayer::getMemoryShapes(const std::vector >&, int, std:: 中的断言失败 (inputs.size() == requiredOutputs) vector >&, std::vector >&) const,文件 /build/3_4_pack-android/opencv/modules/dnn/src/dnn.cpp,第 681 行

我也试过了:

  • 裁剪 rgb 图像
  • Mat blob = dnn::blobFromImage(resized, 1.0f, Size(28,28));
  • 不使用 blobFromImage,而是使用 net.setInput(resized); 代替

但这些都没有导致解决方案。有人对此有解决方案吗?任何建议或想法将不胜感激。

【问题讨论】:

  • 能否提供std::cout &lt;&lt; blob.size &lt;&lt; std::endl的输出?
  • 当然。这是一个 1x1x28x28 的图像。我不知道它是否适合输入。因为在mnist_convnet_graph.pbtxt文件中顺序不一样。
  • 1x1x28x28 可以。 OpenCV 可以管理的只是不同的数据布局。您能否分享一个完整的文本.pbtxt 文件以查看它?请指定您使用的 OpenCV 版本。顺便说一句,您是否尝试过仅使用二进制 .pb 文件导入模型?
  • 当然。它在这里:link。我使用 OpenCV 3.4.5 版和 Android Studio 3.3。问题是readNetFromTensorflow() 函数的第一个参数是.pb 文件(~17,4 MB),第二个参数是.pbtxt(~284 KB)。
  • hmm,看起来模型是在训练模式下序列化的(应该是测试模式)。有一个称为冻结的过程,它禁用了所有仅训练的节点(在您的图表中有)。

标签: android c++ opencv neural-network


【解决方案1】:

好的,我设法解决了我的问题。

首先,我意识到.pb.pbtxt 文件在错误的目录中,并得到2 个Failed to upload a file 信息日志。

将文件放入正确的目录后,我遇到了问题:
error: (-215:Assertion failed) const_layers.insert(std::make_pair(name, li)).second in function 'void cv::dnn::experimental_dnn_34_v11::{anonymous}::addConstNodes(opencv_tensorflow::GraphDef&amp;, std::map&lt;cv::String, int&gt;&amp;, std::set&lt;cv::String&gt;&amp;)'

正如Dmitry Kurtaev 建议的here,我从Dnn.readNetFromTensorflow 中删除了.pbtxt。之后我收到错误:
OpenCV(3.4.5) Error: Unspecified error (Can't create layer "flatten_1/Shape" of type "Shape") in cv::Ptr&lt;cv::dnn::experimental_dnn_34_v11::Layer&gt; cv::dnn::experimental_dnn_34_v11::LayerData::getLayerInstance(), file /build/3_4_pack-android/opencv/modules/dnn/src/dnn.cpp, line 513

这使我找到了一个链接,我在Dmitry Kurtaev 的评论here 中找到了该链接。在对.pbtxt 文件进行了建议的修改(删除 Const 节点,修改和删除 flatten 节点)后,最后我没有错误并成功运行神经网络。

注意:在创建模型之前添加K.backend.set_learning_phase(0),也很有用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-05-16
    • 2018-09-04
    • 2011-12-03
    • 2014-05-20
    • 2017-03-21
    • 1970-01-01
    • 2020-11-08
    • 2014-07-16
    相关资源
    最近更新 更多