OpenCVのblobFromImage関数の詳しい説明

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であるため、 RGを交換する必要がある場合は、 Crop Cropping が true の場合、swapRB=true
Cropにする必要があります。次に、サイズ変更された一方の側が対応する寸法と等しく、もう一方の側がそれ以上になるように入力画像を調整します。次に、中心から切り取ります。「crop」が「false」の場合、トリミングせずにサイズを変更し、アスペクト比を維持します。

d Depth、出力 BLOB の深さ。CV_32F または CV_8U を選択します。

cv2.dnn.blobFromImage関数によって返される BLOB は、入力画像が中心からランダムに切り取られ、平均から減算され、スケーリングされ、チャネルが交換された結果です。cv2.dnn.blobFromImagescv2.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

Guess you like

Origin blog.csdn.net/wxy2020915/article/details/126749072