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,所以如果需要交换R和G,那么就要使swapRB=true crop,如果crop裁剪为真,则调整输入图像的大小,使调整大小后的一侧等于相应的尺寸,另一侧等于或大于。然后,从中心进行裁剪。如果“裁剪”为“假”,则直接调整大小而不进行裁剪并保留纵横比。

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

cv2.dnn.blobFromImage函数返回的blob是我们输入图像进行随意从中心裁剪,减均值、缩放和通道交换的结果。cv2.dnn.blobFromImages和cv2.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());

for (int i = 0; i < detectionMat.rows; i++)

{

//自定义阈值

if (detectionMat.at(i, 2) >= 0.14)

{

int xLeftBottom = static_cast(detectionMat.at(i, 3) * image.cols);

int yLeftBottom = static_cast(detectionMat.at(i, 4) * image.rows);

int xRightTop = static_cast(detectionMat.at(i, 5) * image.cols);

int yRightTop = static_cast(detectionMat.at(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

{

for (int w = 0; w < p.Width; w++)

{

res.Set(h, w, (byte)(p.At(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 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

精彩文章

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: