c++如何读取高维Mat:class中特定坐标的数据?

How to read data at the specific coordinates in high-dimensional Mat:class using c++?

我正在尝试使用 OpenCV 中的 MobileNet SSD + 深度神经网络 ( dnn ) 模块进行对象检测。我成功加载并使用了该模型。作为 net.forward 的输出,我获得了 Mat 对象,其中包含有关检测到的对象的信息。不幸的是,我在阅读检测到的内容时遇到了 "the easy part of work"。

这是我知道的关于输出 Mat 对象的信息:

我找不到任何 C++ 示例,但我找到了很多 python 示例。他们这样读取数据:

for i in np.arange(0, detections.shape[2]):    
    confidence = detections[0, 0, i, 2]

在 C++ 中执行此操作的最简单方法是什么? IE。我需要读取高维特定坐标的数据 Mat:class.

感谢您的热心帮助。我是 c++ 的新手,有时发现它不知所措...

我正在使用 OpenCV 3.3.0。我使用的 MobileNet SSD GitHub:https://github.com/chuanqi305/MobileNet-SSD.

我的程序代码:

#include <opencv2/dnn.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>

#include <fstream>
#include <iostream>

using namespace cv;
using namespace cv::dnn;

using namespace std;

// function to create vector of class names
std::vector<String> createClaseNames() {
    std::vector<String> classNames;
    classNames.push_back("background");
    classNames.push_back("aeroplane");
    classNames.push_back("bicycle");
    classNames.push_back("bird");
    classNames.push_back("boat");
    classNames.push_back("bottle");
    classNames.push_back("bus");
    classNames.push_back("car");
    classNames.push_back("cat");
    classNames.push_back("chair");
    classNames.push_back("cow");
    classNames.push_back("diningtable");
    classNames.push_back("dog");
    classNames.push_back("horse");
    classNames.push_back("motorbike");
    classNames.push_back("person");
    classNames.push_back("pottedplant");
    classNames.push_back("sheep");
    classNames.push_back("sofa");
    classNames.push_back("train");
    classNames.push_back("tvmonitor");
    return classNames;
}

// main function
int main(int argc, char **argv)
{
    // set inputs
    String modelTxt = "C:/Users/acer/Desktop/kurz_OCV/cv4faces/project/python/object-detection-deep-learning/MobileNetSSD_deploy.prototxt";
    String modelBin = "C:/Users/acer/Desktop/kurz_OCV/cv4faces/project/python/object-detection-deep-learning/MobileNetSSD_deploy.caffemodel";
    String imageFile = "C:/Users/acer/Desktop/kurz_OCV/cv4faces/project/puppies.jpg";
    std::vector<String> classNames = createClaseNames();

    //read caffe model
    Net net;
    try {
        net = dnn::readNetFromCaffe(modelTxt, modelBin);
    }
    catch (cv::Exception& e) {
        std::cerr << "Exception: " << e.what() << std::endl;
        if (net.empty())
        {
            std::cerr << "Can't load network." << std::endl;
            exit(-1);
        }
    }

    // read image 
    Mat img = imread(imageFile);

    // create input blob
    resize(img, img, Size(300, 300));
    Mat inputBlob = blobFromImage(img, 0.007843, Size(300, 300), Scalar(127.5)); //Convert Mat to dnn::Blob image batch

    // apply the blob on the input layer
    net.setInput(inputBlob); //set the network input

    // classify the image by applying the blob on the net
    Mat detections = net.forward("detection_out"); //compute output

    // print some information about detections
    std::cout << "dims: " << detections.dims << endl;
    std::cout << "size: " << detections.size << endl;

    //show image
    String winName("image");
    imshow(winName, img);

    // Wait for keypress
    waitKey();

}

查看 how to scan images 上的官方 OpenCV 教程。

您访问 3 通道(即颜色)Mat 的正常方式是使用 Mat::at() method of the Mat class, which is heavily overloaded for all sorts of accessor options. Specifically, you can send in an array of indices or a vector of indices.


这是创建 4D Mat 和访问特定元素的最基本示例:

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    int size[4] = { 2, 2, 5, 7 };
    cv::Mat M(4, size, CV_32FC1, cv::Scalar(1));
    int indx[4] = { 0, 0, 2, 3 };
    std::cout << "M[0, 0, 2, 3] = " << M.at<float>(indx) << std::endl;
}
M[0, 0, 2, 3] = 1

有人可能会在使用 OpenCV 中的 MobileNet SSD + 深度神经网络 ( dnn ) 模块进行对象检测的上下文中发现这个问题。所以这里我 post 对象检测的功能代码。 Alexander Reynolds 感谢您的帮助。

#include <opencv2/dnn.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>

#include <fstream>
#include <iostream>

using namespace cv;
using namespace cv::dnn;
using namespace std;

// function to create vector of class names
std::vector<String> createClaseNames() {
    std::vector<String> classNames;
    classNames.push_back("background");
    classNames.push_back("aeroplane");
    classNames.push_back("bicycle");
    classNames.push_back("bird");
    classNames.push_back("boat");
    classNames.push_back("bottle");
    classNames.push_back("bus");
    classNames.push_back("car");
    classNames.push_back("cat");
    classNames.push_back("chair");
    classNames.push_back("cow");
    classNames.push_back("diningtable");
    classNames.push_back("dog");
    classNames.push_back("horse");
    classNames.push_back("motorbike");
    classNames.push_back("person");
    classNames.push_back("pottedplant");
    classNames.push_back("sheep");
    classNames.push_back("sofa");
    classNames.push_back("train");
    classNames.push_back("tvmonitor");
    return classNames;
}  

// main function
int main(int argc, char **argv)
{
    // set inputs
    String modelTxt = "Path to MobileNetSSD_deploy.prototxt";
    String modelBin = "Path to MobileNetSSD_deploy.caffemodel";
    String imageFile = "Path to test image";
    std::vector<String> classNames = createClaseNames();

    //read caffe model
    Net net;
    try {
        net = dnn::readNetFromCaffe(modelTxt, modelBin);
    }
    catch (cv::Exception& e) {
        std::cerr << "Exception: " << e.what() << std::endl;
        if (net.empty())
        {
            std::cerr << "Can't load network." << std::endl;
            exit(-1);
        }
    }

    // read image 
    Mat img = imread(imageFile);
    Size imgSize = img.size();

    // create input blob
    Mat img300;
    resize(img, img300, Size(300, 300));
    Mat inputBlob = blobFromImage(img300, 0.007843, Size(300, 300), Scalar(127.5)); //Convert Mat to dnn::Blob image batch

    // apply the blob on the input layer
    net.setInput(inputBlob); //set the network input

    // classify the image by applying the blob on the net
    Mat detections = net.forward("detection_out"); //compute output

    // look what the detector found
    for (int i=0; i < detections.size[2]; i++) {

        // print information into console
        cout << "-----------------" << endl;
        cout << "Object nr. " << i + 1 << endl;

        // detected class
        int indxCls[4] = { 0, 0, i, 1 };
        int cls = detections.at<float>(indxCls);
        std::cout << "class: " << classNames[cls] << endl;

        // confidence
        int indxCnf[4] = { 0, 0, i, 2 };
        float cnf = detections.at<float>(indxCnf);
        std::cout << "confidence: " << cnf * 100 << "%" << endl;

        // bounding box
        int indxBx[4] = { 0, 0, i, 3 };
        int indxBy[4] = { 0, 0, i, 4 };
        int indxBw[4] = { 0, 0, i, 5 };
        int indxBh[4] = { 0, 0, i, 6 };
        int Bx = detections.at<float>(indxBx) * imgSize.width;
        int By = detections.at<float>(indxBy) * imgSize.height;
        int Bw = detections.at<float>(indxBw) * imgSize.width - Bx;
        int Bh = detections.at<float>(indxBh) * imgSize.height - By;
        std::cout << "bounding box [x, y, w, h]: " << Bx << ", " << By << ", " << Bw << ", " << Bh << endl;

        // draw bounding box to image
        Rect bbox(Bx, By, Bw, Bh);
        rectangle(img, bbox, Scalar(255,0,255),1,8,0);

    }
    //show image
    String winName("image");
    imshow(winName, img);

    // Wait for keypress
    waitKey();

}