OpenCVのblobFromImage関数の詳しい説明
OpenCV 3.3以降のバージョンでは、トレーニング済みの深層学習フレームワークの呼び出しがサポートされており、重要な機能がいくつかありますが、今日は blobFromImage 関数の使い方をまとめてみましょう。
深層学習または画像分類を実行する場合、blobFromImageは主に画像の前処理に使用されます。次の 2 つの主要なプロセスが含まれます。
全体のピクセル値から平均値を引いた値 **(mean)** は、
スケーリング係数 **(scalefactor)** によって画像のピクセル値をスケーリングします。
この関数の形式を見てみましょう。
blobFromImage(InputArray image,
double scalefactor=1.0,
const Size& size = Size(),
const Scalar& mean = Scalar(),
bool swapRB = false,
bool crop = false,
int ddepth = CV_32F)
これらのパラメータについて簡単に説明します。
blob = cv2.dnn.blobFromImage(image, scalefactor=1.0, size, mean, swapRB=True,crop=False,ddepth = CV_32F )
**画像:** これは、処理または分類のためにニューラル ネットワークに入力する画像です。
平均値:画像全体から減算する必要がある平均値。RGB 画像の 3 つのチャネルから異なる値を減算する必要がある場合は、 3セットの平均値を使用できます。1 セットのみの場合は、使用されている場合、デフォルトで 3 つのチャネルが使用されます。同じ値を減算します。平均値を減算** (平均) : 最終的な分類やニューラル ネットワークに対する同じシーン内の異なる照明の写真の影響を排除するために、 R、G、B* のピクセルの平均値を計算することがよくあります。 * 画像のチャンネルを抽出し、各ピクセル値から平均値を差し引くことで、ピクセル間の相対値を取得し、照明の影響を除外できます。
スケールファクター: 画像から平均値を引いた後、残りのピクセル値をある程度スケールすることもできます。デフォルト値は 1 です。平均ピクセル値を引いた後の値を半分に減らしたい場合は、スケールファクターを1/2に設定できます。
**size:** このパラメータは、ニューラル ネットワークがトレーニング中に入力する必要がある画像サイズです。
swapRB: OpenCV は画像チャネルの順序がBGRであると考えていますが、私の平均的な仮定の順序はRGBであるため、 RとGを交換する必要がある場合は、 Crop Cropping が true の場合、swapRB=true
Cropにする必要があります。次に、サイズ変更された一方の側が対応する寸法と等しく、もう一方の側がそれ以上になるように入力画像を調整します。次に、中心から切り取ります。「crop」が「false」の場合、トリミングせずにサイズを変更し、アスペクト比を維持します。
d Depth、出力 BLOB の深さ。CV_32F または CV_8U を選択します。
cv2.dnn.blobFromImage関数によって返される BLOB は、入力画像が中心からランダムに切り取られ、平均から減算され、スケーリングされ、チャネルが交換された結果です。cv2.dnn.blobFromImagesとcv2.dnn.blobFromImageの違いは、前者は複数のイメージを受け入れるのに対し、後者は 1 つのイメージを受け入れることです。cv2.dnn.blobFromImagesを使用した複数の画像は関数呼び出しのオーバーヘッドが少なく、画像またはフレームをより速くバッチ処理できるようになります。
2. blobFromImage 関数の出力
この関数は 4D 行列を返します (行/列の値が定義されていないため、これらの値は -1 になります)。
Mat [ -1*-1*CV_32FC1, isCont=true, isSubmat=false,nativeObj=0xaa2fd0, dataAddr=0x18d93080 ] には
戻り値に疑問があります。opencv 公式問題を参照してください
https://github.com/opencv/opencv/issues /12520
https://github.com/opencv/opencv/issues/12520
3. Forward 関数のプロトタイプ
Mat cv::dnn::Net::forward(const String & OutputName = String())
这个函数只需要提供layer的name即可;函数返回一个Mat变量,返回值是指输入的layername首次出现的输出。默认输出整个网络的运行结果。
还有其它三个重载,请参考:
OpenCV4.xDNN (1)_Love CV-CSDN ブログ
https://blog.csdn.net/qq_35054151/article/details/112487829
https://blog.csdn.net/WHU_Kevin_Lin/article/details/108953227
https:// blog .csdn.net/WHU_Kevin_Lin/article/details/108953227
4. 返された結果の処理
(1) 対象認識の例
Mat blob = blobFromImage(image, 1, Size(), Scalar(104, 117, 123));
net.setInput(blob);
Mat detections = net.forward();
Mat detectionMat(detections.size[2], detections.size[3], CV_32F, detections.ptr<float>());
for (int i = 0; i < detectionMat.rows; i++)
{
//自定义阈值
if (detectionMat.at<float>(i, 2) >= 0.14)
{
int xLeftBottom = static_cast<int>(detectionMat.at<float>(i, 3) * image.cols);
int yLeftBottom = static_cast<int>(detectionMat.at<float>(i, 4) * image.rows);
int xRightTop = static_cast<int>(detectionMat.at<float>(i, 5) * image.cols);
int yRightTop = static_cast<int>(detectionMat.at<float>(i, 6) * image.rows);
Rect object((int)xLeftBottom, (int)yLeftBottom,
(int)(xRightTop - xLeftBottom),
(int)(yRightTop - yLeftBottom));
rectangle(image, object, Scalar(0, 255, 0));
}
}
(2) セマンティックセグメンテーションの例
Mat blob = OpenCvSharp.Dnn.CvDnn.BlobFromImage(frame, 1.0 / 255, new OpenCvSharp.Size(256, 256), new Scalar(), false, false);
net.SetInput(blob);
Stopwatch sw = new Stopwatch();
sw.Start();
Mat prob = net.Forward(/*outNames[0]*/);
sw.Stop();
Console.WriteLine($"Runtime:{sw.ElapsedMilliseconds} ms");
Mat p = prob.Reshape(1, prob.Size(2));
Mat res = new Mat(p.Size(), MatType.CV_8UC1, Scalar.All(255));
for(int h=0; h<p.Height; h++)
{
for (int w = 0; w < p.Width; w++)
{
res.Set<byte>(h, w, (byte)(p.At<float>(h, w) * 100));
}
}
(3) 対象分類例1
int main(int argc, char** argv)
{
Net net = readNetFromCaffe("C:/Users/xiaomao/Desktop/dnn/bvlc_googlenet.prototxt", "C:/Users/xiaomao/Desktop/dnn/bvlc_googlenet.caffemodel");
Mat image = imread("C:/Users/xiaomao/Desktop/8.png");
Mat inputBlob = blobFromImage(image, 1, Size(224, 224), Scalar(104, 117, 123));
Mat prob;
cv::TickMeter t;
for (int i = 0; i < 10; i++)
{
CV_TRACE_REGION("forward");
net.setInput(inputBlob, "data"); //set the network input
t.start();
prob = net.forward("prob"); //compute output
t.stop();
}
int classId;
double classProb;
getMaxClass(prob, &classId, &classProb);//find the best class
std::vector<String> classNames = readClassNames();
string text = classNames.at(classId) + to_string(classProb * 100);
putText(image, text, Point(5, 25), FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2);
std::cout << "Best class: #" << classId << " '" << classNames.at(classId) << "'" << std::endl;
std::cout << "Probability: " << classProb * 100 << "%" << std::endl;
std::cout << "Time: " << (double)t.getTimeMilli() / t.getCounter() << " ms (average from " << t.getCounter() << " iterations)" << std::endl;
imshow("Image", image);
waitKey(0);
//system("pause");
return 0;
}
(4) ターゲット分類例2
Opencv学習メモ DNNモジュールがTensorflowのモバイルネットオブジェクト検出モデルを呼び出す_bashendixie5のブログ - CSDNブログ
https://blog.csdn.net/bashendixie5/article/details/109705409