前提・実現したいこと
C++/CLIにて学習済みのモデルを使って物体検出のプログラムの作成をしています。
https://github.com/opencv/opencv/blob/3.4.15/samples/dnn/object_detection.cpp
こちらのopencvのサンプルを参考にファイル選択ダイアログで画像、設定ファイル(.cfg,.prototxt)、モデルファイル(.weights,.caffemodel)を選択して、ピクチャーボックスに検出結果を表示するようなWindowsフォームアプリケーションを作成しました。
アプリの動作の流れとしては画像選択→設定ファイル・モデルファイル選択→検出→検出結果画像の描画となっています。
困っていることとしては、アプリを起動して1度目は検出結果画像の描画までうまくいくのですが、その後選択するモデルを切り替えてもう一度検出しようとすると、うまく検出できていない画像が表示されてしまいます。
(画像選択→設定ファイル・モデルファイル選択→検出→検出結果画像の描画→別の設定ファイル・モデルファイル選択→検出→検出結果画像の描画の順序だとうまくいかない)
なにかアイデアなどあれば教えていただきたいです。
よろしくお願いいたします。
発生している問題・エラーメッセージ
該当のソースコード
c++
1#pragma once 2 3#define _CRT_SECURE_NO_WARNINGS 4 5#include <iostream> 6#include <msclr\marshal_cppstd.h> 7#include <opencv2/opencv.hpp> 8#include "common.hpp" 9 10std::string imgpath = "", cfg = "", model = ""; 11dnn::Net *net = NULL; 12std::vector<cv::String> outNames; 13int selectModel = NOMODEL; 14 15 16namespace opencvdetectgui { 17 18 using namespace System; 19 using namespace System::ComponentModel; 20 using namespace System::Collections; 21 using namespace System::Windows::Forms; 22 using namespace System::Data; 23 using namespace System::Drawing; 24 25//////////////////////////////////////////////////////////////////////// 26////////////////////省略//////////////////////////////////////////////// 27//////////////////////////////////////////////////////////////////////// 28 29 } 30#pragma endregion 31 private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) { 32 33 //ファイル選択ダイアログでもととなる画像を選択して左側のピクチャーボックスに描画 34 35 } 36 37 private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e) { 38 39 //ファイル選択ダイアログで設定ファイル(.cfg,.prototxt)、モデルファイル(.weights,.caffemodel)の選択 40 41 } 42 43 private: System::Void button3_Click(System::Object^ sender, System::EventArgs^ e) { 44 45 //接待ファイル、モデルの読み込み 46 dnn::Net net = readNet(model, cfg); 47 net.setPreferableBackend(0); 48 net.setPreferableTarget(0); 49 outNames = net.getUnconnectedOutLayersNames(); 50 51 //ビデオキャプチャの取得(後々カメラ映像で検出したいためこのように書いています) 52 VideoCapture cap; 53 if (imgpath != "") 54 cap.open(imgpath); 55 else 56 cap.open(0); 57 cv::Mat frame, blob; 58 cap >> frame; 59 60 //yolo,mobilenetssdそれぞれのパラメータで読み込んで検出 61 if (selectModel == YOLO) { 62 preprocess(frame, net, cv::Size(416, 416), 0.00392, cv::Scalar(0, 0, 0), true); 63 } 64 else if (selectModel == SSD) { 65 preprocess(frame, net, cv::Size(300, 300), 0.007843, cv::Scalar(127.5, 127.5, 127.5), false); 66 } 67 68 std::vector<Mat> outs; 69 net.forward(outs, outNames); 70 71 postprocess(frame, outs, net, 0); 72 73 //検出したバウンディングボックスの書き込み 74 std::vector<double> layersTimes; 75 double freq = getTickFrequency() / 1000; 76 double t = net.getPerfProfile(layersTimes) / freq; 77 std::string label = format("Inference time: %.2f ms", t); 78 putText(frame, label, cv::Point(0, 15), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 0)); 79 80 //検出結果画像を右側のピクチャーボックスのサイズに調整してから表示 81 cv::Mat mat_pb(pictureBox2->Height, pictureBox2->Width, CV_8U); 82 cv::resize(frame, frame, mat_pb.size()); 83 drawImage(pictureBox2, frame); 84 } 85}; 86}
common.hppは以下のものをコピペしました。
(https://github.com/opencv/opencv/blob/3.4.15/samples/dnn/common.hpp)
試したこと
アプリ起動→yolo検出(正常)→mobilenetssd検出(異常)→yolo検出(正常)
となるのでなにかの変数が検出ごとに初期化されずに保存されていることが原因なのですが、その変数がわからず困っています。
common.hppの関数でstaticで宣言されているところも確認しましたが改善されませんでした。
補足情報(FW/ツールのバージョンなど)
opencv 3.4.15
visual studio 2019
Windows 10 64 bit
追記
モデルを読み込んでから検出して描画まで複数の関数があるのですが、その中でどの関数を検出手法間で共有(SSDで使ってからYOLOで使う)すると不具合が起きるのか調べてみました。
調べたところ、postprocess()という関数を共有すると不具合が起こっているようです。
一応postprocess()と内容が同じ関数のpostprocess_yolo()とpostprocess_ssd()を定義して、共有しないようにするととりあえず画像に関しては連続して(SSD検出後にYOLO検出)は問題なくできるようにはなりました。
ただ理由がわからず困っています。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/09/02 07:12
2021/09/02 08:31 編集
2021/09/02 10:12 編集