OpenCV中blobFromImage函数详细解释

OpenCV中blobFromImage函数详细解释

OpenCV 3.3之后的版本中,支持调用训练好的深度学习框架,其中有一些重要的函数,今天先总结一下blobFromImage函数的用法。

在进行深度学习或者图片分类时,blobFromImage主要是用来对图片进行预处理。包含两个主要过程:

整体像素值减去平均值**(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 )

**image:**这个就是我们将要输入神经网络进行处理或者分类的图片。

mean:需要将图片整体减去的平均值,如果我们需要对RGB图片的三个通道分别减去不同的值,那么可以使用3组平均值,如果只使用一组,那么就默认对三个通道减去一样的值。减去平均值**(mean):为了消除同一场景下不同光照的图片,对我们最终的分类或者神经网络的影响,我们常常对图片的R、G、B**通道的像素求一个平均值,然后将每个像素值减去我们的平均值,这样就可以得到像素之间的相对值,就可以排除光照的影响。

scalefactor:当我们将图片减去平均值之后,还可以对剩下的像素值进行一定的尺度缩放,它的默认值是1,如果希望减去平均像素之后的值,全部缩小一半,那么可以将scalefactor设为1/2

**size:**这个参数是我们神经网络在训练的时候要求输入的图片尺寸。

swapRB:OpenCV中认为我们的图片通道顺序是BGR,但是我平均值假设的顺序是RGB,所以如果需要交换RG,那么就要使swapRB=true
crop,如果crop裁剪为真,则调整输入图像的大小,使调整大小后的一侧等于相应的尺寸,另一侧等于或大于。然后,从中心进行裁剪。如果“裁剪”为“假”,则直接调整大小而不进行裁剪并保留纵横比。

ddepth, 输出blob的深度,选则CV_32F or CV_8U。

cv2.dnn.blobFromImage函数返回的blob是我们输入图像进行随意从中心裁剪,减均值、缩放和通道交换的结果。cv2.dnn.blobFromImagescv2.dnn.blobFromImage不同在于,前者接受多张图像,后者接受一张图像。多张图像使用cv2.dnn.blobFromImages有更少的函数调用开销,你将能够更快批处理图像或帧。

2、blobFromImage函数输出
函数返回4D矩阵(没有定义行/列值,因此这些值为-1)。

Mat [ -1*-1*CV_32FC1, isCont=true, isSubmat=false, nativeObj=0xaa2fd0, dataAddr=0x18d93080 ]
对于返回值有疑问,参见opencv官方issues
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(一)_爱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的mobilenet对象检测模型_bashendixie5的博客-CSDN博客

https://blog.csdn.net/bashendixie5/article/details/109705409

猜你喜欢

转载自blog.csdn.net/wxy2020915/article/details/126749072