如何在高维Mat:Class中使用C++读取特定坐标处的数据?
我正尝试在OpenCV中使用MobileNet SSD +深度神经网络(dnn)模块进行对象检测。我成功加载并使用了模型。作为net.forward的输出,我获得了包含关于检测到的对象的信息的Mat对象。不幸的是,我在与“易于工作的一部分”斗争,阅读究竟是什么被发现。如何在高维Mat:Class中使用C++读取特定坐标处的数据?
这是我知道的输出垫目标信息:
- 它有4种尺寸。
- 的大小是1×1×number_of_objects_detected X 7.
- 七条关于每个对象的信息的有:第一是类ID,所述第二是信心,所述第三-第七是边界框的值。
我找不到任何C++的例子,但我发现了很多python的例子。他们读取这样的数据:
for i in np.arange(0, detections.shape[2]):
confidence = detections[0, 0, i, 2]
如何在C++中做到这一点最简单的方法是什么?即我需要读取高维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
类,它在很大程度上重载各种访问选项的Mat::at()
方法的正常方式。具体而言,您可以发送array of indices或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
感谢建议。事实上,我已经试过Mat :: at() - 但它似乎最多支持三维空间(https://docs.opencv.org/3.3.0/d3/d63/classcv_1_1Mat.html #a305829ed5c0ecfef7b44db18953048e8)。 具体而言,我只是无法做到这一点: 'int class = detections。在
谢谢你的例子,知道我明白了。 – Betty
@Beth是啊,如果你看看在文档中链接的at()的所有重载定义,你会发现最多有3个参数用于3D访问;否则您需要使用数组或向量来索引N-D矩阵。如果这回答你的问题,你介意接受它吗?否则让我知道它是否应该扩大。 –
有人可能会发现在使用MobileNet SSD的背景下,这个问题+ OpenCV中的深度神经网络(dnn)模块用于对象检测。所以在这里我发布了已经实现的对象检测代码。亚历山大雷诺兹感谢你的帮助。
#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();
}
有一个C++样品与MobileNet-SSD从来自Caffe:https://github.com/opencv/opencv/blob/master/samples/dnn/ssd_mobilenet_object_detection.cpp –