Я пытаюсь перевести код Python на C++ и натыкаюсь на этот код:
self.net = cv.dnn.readNetFromDarknet(cfg_file, weights_file)
self.net.setPreferableBackend(cv.dnn.DNN_BACKEND_OPENCV)
self.ln = self.net.getLayerNames()
self.ln = [self.ln[i-1] for i in self.net.getUnconnectedOutLayers()]
...
blob = cv.dnn.blobFromImage(img, 1/255.0, (416, 416), swapRB=True, crop=False)
self.net.setInput(blob)
outputs = self.net.forward(self.ln)
outputs = np.vstack(outputs)
Как видите, код пересылает выходные данные из сети из имен несвязанных слоев, указанных в self.ln. Вот мой код на C++:
static Mat blobFromImg;
bool swapRB = true;
blobFromImage(img, blobFromImg, 1/255.0, Size(416, 416), Scalar(), swapRB, false);
network.setInput(blobFromImg);
Mat outMat;
network.forward(outMat , network.getUnconnectedOutLayersNames());
vconcat(outMat, outMat);
Как видите, я использую cv::vconcat
вместо np.vstack
вместо создания нового std::vector<<cv::String>>
для перехода к network.forward()
. Я использую getUnconnectedOutLayersNames()
. Тем не менее, я получаю эту ошибку:
OpenCV(4.8.0) Error: The function/feature is not implemented () in cv::debug_build_guard::_OutputArray::assign, file D:\vcpkg\buildtrees\opencv4\src\4.8.0-2bf495557d.clean\modules\core\src\matrix_wrap.cpp, line 2052
Строка, в которой возникает исключение, — network.forward()
. Именно благодаря этому методу network.getUnconnectedOutLayersNames()
сам по себе не выдает исключение.
Если я сделаю:
std::vector<cv::String> ln;
auto layers = network.getLayerNames();
for (auto i : network.getUnconnectedOutLayers()){
ln.push_back(layers[i-1]);
}
...
network.setInput(blobFromImg);
Mat outMat;
network.forward(outMat , ln);
vconcat(outMat, outMat);
Я получаю тот же результат.
Почему функция не реализована? Почему Python имеет эту реализацию.
Примечание. Я использую darknet/yolo.
@DanMašek, это сработало отлично. Спасибо!
любой из вас должен опубликовать это в качестве ответа. ответы на вопросы занимают более высокие позиции в результатах поиска.
@ChristophRackwitz Верно, мне просто нужно было найти что-то, подтверждающее мое предположение. :)
Судя по контексту, мы имеем дело со следующей перегрузкой cv::dnn::Net::forward, в документации которой говорится:
void cv::dnn::Net::forward(OutputArrayOfArrays outputBlobs, const std::vector<String>& outBlobNames)
Параметры:
outputBlobs
содержит BLOB-объекты для первых выходных данных указанных слоев.outBlobNames
названия слоев, для получения которых необходимы результаты
Проблема в первом параметре outputBlobs
.
В документации говорится, что cv::OutputArrayOfArrays
это псевдоним для
cv::_OutputArray:
typedef OutputArray OutputArrayOfArrays;
Кроме этого, на этой странице мало что можно найти. Для получения более полезной информации нам нужно просмотреть документацию cv::_InputArray, из которой он получен:
... можно составить из ...,
std::vector<std::vector<T>>
,std::vector<Mat>
,std::vector<Mat_<T>>
...
Существует еще один родственный тип
InputArrayOfArrays
, который в настоящее время определяется как синонимInputArray
:
typedef InputArray InputArrayOfArrays;
Он обозначает аргументы функции, которые являются либо векторами векторов, либо векторами матриц. Для правильной генерации оболочек Python/Java и т. д. необходим отдельный синоним. На уровне реализации функции их использование аналогично, но
_InputArray::getMat(idx)
следует использовать для получения заголовка для idx-го компонента внешнего вектора, а_InputArray::size().area()
следует использовать для определения количества компонентов (векторов/матриц) внешнего вектора.
И вдруг становится ясно. Мы вызываем функцию с последовательностью имен слоев, мы должны вернуть последовательность больших двоичных объектов. Мы знаем, что каплю можно представить в виде 4D cv::Mat
. Их последовательность в C++ будет представлять собой vector
из Mat
: std::vector<cv::Mat>
. Итак, измените первый параметр forward
на этот тип. И, как вы говорите, «это сработало идеально».
Просто догадайтесь: сделайте
outMat
std::vector<cv::Mat>
... Это последовательность капель.