旋转变换、映射、parallel_for、parallel_for_ 、for的性能比较

opencv英文文档

Geometric Image Transformations

The functions in this section perform various geometrical transformations of 2D images. They do not change the image content but deform the pixel grid and map this deformed grid to the destination image. In fact, to avoid sampling artifacts, the mapping is done in the reverse order, from destination to the source. That is, for each pixel (x, y) of the destination image, the functions compute coordinates of the corresponding “donor” pixel in the source image and copy the pixel value:

The functions in this section perform various geometrical transformations of 2D images. They do not change the image content but deform the pixel grid and map this deformed grid to the destination image. In fact, to avoid sampling artifacts, the mapping is done in the reverse order, from destination to the source. That is, for each pixel (x, y) of the destination image, the functions compute coordinates of the corresponding “donor” pixel in the source image and copy the pixel value: .. math:

\texttt{dst} (x,y)= \texttt{src} (f_x(x,y), f_y(x,y))

In case when you specify the forward mapping \left<g_x, g_y\right>: \texttt{src} \rightarrow \texttt{dst} , the OpenCV functions first compute the corresponding inverse mapping \left<f_x, f_y\right>: \texttt{dst} \rightarrow \texttt{src} and then use the above formula.

convertMaps

Converts image transformation maps from one representation to another.

C++:  void  convertMaps (InputArray  map1, InputArray  map2, OutputArray  dstmap1, OutputArray  dstmap2, int  dstmap1type, bool  nninterpolation=false  )
Python:   cv2. convertMaps (map1, map2, dstmap1type [, dstmap1 [, dstmap2 [, nninterpolation ] ] ] ) → dstmap1, dstmap2
Parameters:
  • map1 – The first input map of type CV_16SC2 , CV_32FC1 , or CV_32FC2 .
  • map2 – The second input map of type CV_16UC1 , CV_32FC1 , or none (empty matrix), respectively.
  • dstmap1 – The first output map that has the type dstmap1type and the same size as src .
  • dstmap2 – The second output map.
  • dstmap1type – Type of the first output map that should be CV_16SC2 , CV_32FC1 , or CV_32FC2 .
  • nninterpolation – Flag indicating whether the fixed-point maps are used for the nearest-neighbor or for a more complex interpolation.

The function converts a pair of maps for remap() from one representation to another. The following options ( (map1.type(), map2.type()) \rightarrow (dstmap1.type(), dstmap2.type()) ) are supported:

  • \texttt{(CV\_32FC1, CV\_32FC1)} \rightarrow \texttt{(CV\_16SC2, CV\_16UC1)} . This is the most frequently used conversion operation, in which the original floating-point maps (see remap() ) are converted to a more compact and much faster fixed-point representation. The first output array contains the rounded coordinates and the second array (created only when nninterpolation=false ) contains indices in the interpolation tables.
  • \texttt{(CV\_32FC2)} \rightarrow \texttt{(CV\_16SC2, CV\_16UC1)} . The same as above but the original maps are stored in one 2-channel matrix.
  • Reverse conversion. Obviously, the reconstructed floating-point maps will not be exactly the same as the originals.
  • 第一个输出是dstmap_1 contains pairs (cvFloor(x), cvFloor(y))
  • 第二个输出dstmap_2 contains indices in a table of interpolation coefficients.
  • 输出一定都是(CV_16SC2,CV_16UC1)
  • remap

    Applies a generic geometrical transformation to an image.

    C++:  void  remap (InputArray  src, OutputArray  dst, InputArray  map1, InputArray  map2, int  interpolation, int  borderMode=BORDER_CONSTANT, const Scalar&  borderValue=Scalar() )
    Python:   cv2. remap (src, map1, map2, interpolation [, dst [, borderMode [, borderValue ] ] ] ) → dst
    C:  void  cvRemap (const CvArr*  src, CvArr*  dst, const CvArr*  mapx, const CvArr*  mapy, int  flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS, CvScalar  fillval=cvScalarAll(0)  )
    Python:   cv. Remap (src, dst, mapx, mapy, flags=CV_INNER_LINEAR+CV_WARP_FILL_OUTLIERS, fillval=(0, 0, 0, 0) ) → None
    Parameters:
    • src – Source image.
    • dst – Destination image. It has the same size as map1 and the same type as src .
    • map1 – The first map of either (x,y) points or just x values having the type CV_16SC2 , CV_32FC1 , or CV_32FC2 . See convertMaps() for details on converting a floating point representation to fixed-point for speed.
    • map2 – The second map of y values having the type CV_16UC1 , CV_32FC1 , or none (empty map if map1 is (x,y) points), respectively.
    • interpolation – Interpolation method (see resize() ). The method INTER_AREA is not supported by this function.
    • borderMode – Pixel extrapolation method (see borderInterpolate() ). When borderMode=BORDER_TRANSPARENT , it means that the pixels in the destination image that corresponds to the “outliers” in the source image are not modified by the function.
    • borderValue – Value used in case of a constant border. By default, it is 0.

    The function remap transforms the source image using the specified map:

    \texttt{dst} (x,y) =  \texttt{src} (map_x(x,y),map_y(x,y))

    where values of pixels with non-integer coordinates are computed using one of available interpolation methods. map_x and map_y can be encoded as separate floating-point maps in map_1 and map_2 respectively, or interleaved floating-point maps of (x,y) in map_1 , or fixed-point maps created by using convertMaps() . The reason you might want to convert from floating to fixed-point representations of a map is that they can yield much faster (~2x) remapping operations. In the converted casemap_1 contains pairs (cvFloor(x), cvFloor(y)) and map_2 contains indices in a table of interpolation coefficients.

    This function cannot operate in-place.


invertAffineTransform

Inverts an affine transformation.

C++:  void  invertAffineTransform (InputArray  M, OutputArray  iM )
Python:   cv2. invertAffineTransform (M [, iM ] ) → iM
Parameters:
  • M – Original affine transformation.
  • iM – Output reverse affine transformation.

The function computes an inverse affine transformation represented by 2 \times 3 matrix M :

\begin{bmatrix} a_{11} & a_{12} & b_1  \\ a_{21} & a_{22} & b_2 \end{bmatrix}

The result is also a 2 \times 3 matrix of the same type as M .

 cv::invertAffineTransform(InputArray _matM, OutputArray __iM)
{
    Mat matM = _matM.getMat();
    CV_Assert(matM.rows == 2 && matM.cols == 3);
    __iM.create(2, 3, matM.type());
    Mat _iM = __iM.getMat();

    if( matM.type() == CV_32F )
    {
        const float* M = (const float*)matM.data;
        float* iM = (float*)_iM.data;
        int step = (int)(matM.step/sizeof(M[0])), istep = (int)(_iM.step/sizeof(iM[0]));

        double D = M[0]*M[step+1] - M[1]*M[step];
        D = D != 0 ? 1./D : 0;
        double A11 = M[step+1]*D, A22 = M[0]*D, A12 = -M[1]*D, A21 = -M[step]*D;
        double b1 = -A11*M[2] - A12*M[step+2];
        double b2 = -A21*M[2] - A22*M[step+2];

        iM[0] = (float)A11; iM[1] = (float)A12; iM[2] = (float)b1;
        iM[istep] = (float)A21; iM[istep+1] = (float)A22; iM[istep+2] = (float)b2;
    }
    else if( matM.type() == CV_64F )
    {
        const double* M = (const double*)matM.data;
        double* iM = (double*)_iM.data;
        int step = (int)(matM.step/sizeof(M[0])), istep = (int)(_iM.step/sizeof(iM[0]));

        double D = M[0]*M[step+1] - M[1]*M[step];
        D = D != 0 ? 1./D : 0;
        double A11 = M[step+1]*D, A22 = M[0]*D, A12 = -M[1]*D, A21 = -M[step]*D;
        double b1 = -A11*M[2] - A12*M[step+2];
        double b2 = -A21*M[2] - A22*M[step+2];

        iM[0] = A11; iM[1] = A12; iM[2] = b1;
        iM[istep] = A21; iM[istep+1] = A22; iM[istep+2] = b2;
    }
    else
        CV_Error( CV_StsUnsupportedFormat, "" );
}



warpAffine

Applies an affine transformation to an image.

C++:  void  warpAffine (InputArray  src, OutputArray  dst, InputArray  M, Size  dsize, int  flags=INTER_LINEAR, int  borderMode=BORDER_CONSTANT, const Scalar&  borderValue=Scalar() )
Python:   cv2. warpAffine (src, M, dsize [, dst [, flags [, borderMode [, borderValue ] ] ] ] ) → dst
C:  void  cvWarpAffine (const CvArr*  src, CvArr*  dst, const CvMat*  mapMatrix, int  flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS, CvScalar  fillval=cvScalarAll(0)  )
Python:   cv. WarpAffine (src, dst, mapMatrix, flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS, fillval=(0, 0, 0, 0) ) → None
C:  void  cvGetQuadrangleSubPix (const CvArr*  src, CvArr*  dst, const CvMat*  mapMatrix )
Python:   cv. GetQuadrangleSubPix (src, dst, mapMatrix ) → None
Parameters:
  • src – Source image.
  • dst – Destination image that has the size dsize and the same type as src .
  • M – 2\times 3 transformation matrix.
  • dsize – Size of the destination image.
  • flags – Combination of interpolation methods (see resize() ) and the optional flag WARP_INVERSE_MAP that means that M is the inverse transformation ( \texttt{dst}\rightarrow\texttt{src} ).
  • borderMode – Pixel extrapolation method (see borderInterpolate() ). When borderMode=BORDER_TRANSPARENT , it means that the pixels in the destination image corresponding to the “outliers” in the source image are not modified by the function.
  • borderValue – Value used in case of a constant border. By default, it is 0.

The function warpAffine transforms the source image using the specified matrix:

\texttt{dst} (x,y) =  \texttt{src} ( \texttt{M} _{11} x +  \texttt{M} _{12} y +  \texttt{M} _{13}, \texttt{M} _{21} x +  \texttt{M} _{22} y +  \texttt{M} _{23})

when the flag WARP_INVERSE_MAP is set. Otherwise, the transformation is first inverted with invertAffineTransform() and then put in the formula above instead of M . The function cannot operate in-place.


etRotationMatrix2D

Calculates an affine matrix of 2D rotation.

C++:  Mat  getRotationMatrix2D (Point2f  center, double  angle, double  scale )
Python:   cv2. getRotationMatrix2D (center, angle, scale ) → retval
C:  CvMat*  cv2DRotationMatrix (CvPoint2D32f  center, double  angle, double  scale, CvMat*  mapMatrix )
Python:   cv. GetRotationMatrix2D (center, angle, scale, mapMatrix ) → None
Parameters:
  • center – Center of the rotation in the source image.
  • angle – Rotation angle in degrees. Positive values mean counter-clockwise rotation (the coordinate origin is assumed to be the top-left corner).
  • scale – Isotropic scale factor.
  • mapMatrix – The output affine transformation, 2x3 floating-point matrix.

The function calculates the following matrix:

\begin{bmatrix} \alpha &  \beta & (1- \alpha )  \cdot \texttt{center.x} -  \beta \cdot \texttt{center.y} \\ - \beta &  \alpha &  \beta \cdot \texttt{center.x} + (1- \alpha )  \cdot \texttt{center.y} \end{bmatrix}

where

\begin{array}{l} \alpha =  \texttt{scale} \cdot \cos \texttt{angle} , \\ \beta =  \texttt{scale} \cdot \sin \texttt{angle} \end{array}

The transformation maps the rotation center to itself. If this is not the target, adjust the shift.



getAffineTransform

Calculates an affine transform from three pairs of the corresponding points.

C++:  Mat  getAffineTransform (const Point2f*  src, const Point2f*  dst )
Python:   cv2. getAffineTransform (src, dst ) → retval
C:  CvMat*  cvGetAffineTransform (const CvPoint2D32f*  src, const CvPoint2D32f*  dst, CvMat*  mapMatrix )
Python:   cv. GetAffineTransform (src, dst, mapMatrix ) → None
Parameters:
  • src – Coordinates of triangle vertices in the source image.
  • dst – Coordinates of the corresponding triangle vertices in the destination image.

The function calculates the 2 \times 3 matrix of an affine transform so that:

\begin{bmatrix} x'_i \\ y'_i \end{bmatrix} = \texttt{map\_matrix} \cdot \begin{bmatrix} x_i \\ y_i \\ 1 \end{bmatrix}

where

dst(i)=(x'_i,y'_i),src(i)=(x_i, y_i),i=0,1,2

    已知对应三点求变换矩阵

Mat getAffineTransform_self(const Point2f src[], const Point2f dst[])
{
	Mat M(2, 3, CV_64F), X(6, 1, CV_64F, M.data);
	double a[6 * 6], b[6];
	Mat A(6, 6, CV_64F, a), B(6, 1, CV_64F, b);

	for (int i = 0; i < 3; i++)
	{
		//*which maps(xi, yi) to(ui, vi), (i = 1, 2, 3) :
		//	*
		//	* ui = c00*xi + c01*yi + c02
		//	*
		//	* vi = c10*xi + c11*yi + c12
		//	*
		//  * where:cij - matrix coefficients
		// / x0 y0  1  0  0  0 \ /c00\ /u0\
		// \  0  0  0 x0 y0  1 / \c01/ \v0/
                // / x1 y1  1  0  0  0 \ /c02\ /u1\
		// \  0  0  0 x1 y1  1 / \c10/ \v1/
                // / x2 y2  1  0  0  0 \ /c11\ /u2\
		// \  0  0  0 x2 y2  1 / \c12/ \v2/
		int j = i * 12;
		int k = i * 12 + 6;
		a[j] = a[k + 3] = src[i].x;
		a[j + 1] = a[k + 4] = src[i].y;
		a[j + 2] = a[k + 5] = 1;
		a[j + 3] = a[j + 4] = a[j + 5] = 0;
		a[k] = a[k + 1] = a[k + 2] = 0;
		b[i * 2] = dst[i].x;
		b[i * 2 + 1] = dst[i].y;
	}

	solve(A, B, X);//Ax=B
	return M;
}

已知两图像

Mat getAffineTransform_self(InputArray _src, InputArray _dst)
{
	Mat src = _src.getMat(), dst = _dst.getMat();
	CV_Assert(src.checkVector(2, CV_32F) == 3 && dst.checkVector(2, CV_32F) == 3);
	return getAffineTransform((const Point2f*)src.data, (const Point2f*)dst.data);
}
int main()
{
	Mat src = imread("E:\\D\\ruanjianxiangmu\\vs\\2018_6_5\\interpolation_realize\\interpolation_realize\\cameraman.tif");
	cvtColor(src, src, CV_BGR2GRAY);
	cv::imshow("src", src);
	Size ssize = src.size();
	int  width = src.cols;
	int  height = src.rows;

	//保证原图可以任意旋转的最小尺寸
	int dstLength = 3 * sqrt((double)width * width + (double)height *height) + 10;
	int dstX = (dstLength + 1) / 2 - width / 2;
	int dstY = (dstLength + 1) / 2 - height / 2;
	Mat dst(Size(dstLength, dstLength), src.type(), Scalar::all(0));
	Size   dsize = dst.size();

	Point2f  src_point[1][3];
	Point2f  dst_point[1][3];

	Point2f s1(100, 100);
	Point2f s2(100, 120);
	Point2f s3(150, 100);
	Point2f d1(100, 100);
	Point2f d2(80, 100);
	Point2f d3(100, 150);
	src_point[0][0] = s1;
	src_point[0][1] = s2;
	src_point[0][2] = s3;
	dst_point[0][0] = d1;
	dst_point[0][1] = d2;
	dst_point[0][2] = d3;
	Mat MM(2, 3, CV_64F), XX(6, 1, CV_64F, MM.data);
	double aa[6 * 6], bb[6];
	Mat AA(6, 6, CV_64F, aa), BB(6, 1, CV_64F, bb);
	//相当于getAffineTransform( const Point2f src[], const Point2f dst[] )
	//        = getAffineTransform( dst_point,src_point);
	for (int i = 0; i < 3; i++)
	{
		int j = i * 12;
		int k = i * 12 + 6;
		aa[j] = aa[k + 3] = dst_point[0][i].x;
		aa[j + 1] = aa[k + 4] = dst_point[0][i].y;
		aa[j + 2] = aa[k + 5] = 1;
		aa[j + 3] = aa[j + 4] = aa[j + 5] = 0;
		aa[k] = aa[k + 1] = aa[k + 2] = 0;
		bb[i * 2] = src_point[0][i].x;
		bb[i * 2 + 1] = src_point[0][i].y;
	}
	
	cv::solve(AA, BB, XX);

	
	double *mm = (double*)MM.data;
	mm[2] += (dst.cols - src.cols) / 2;
	mm[5] += (dst.rows - src.rows) / 2;

	cv::imshow("src", src);
	warpAffine(src, dst, MM, dsize, 1, 0, Scalar::all(0));
	cv::imshow("dst", dst);
	cv::waitKey();
	return 0;
}


效果图:和预期的一样



//当的输入getAffineTransform( const Point2f src[], const Point2f dst[] )

//        = getAffineTransform( src_point,dst_point);

效果图;相当于使用了逆变换


所以说当getAffineTransform( const Point2f src[], const Point2f dst[] )第一个参数为变换前的图像时;

warpAffine_self(InputArray _src, OutputArray _dst,InputArray _M0, Size 

dsize,int flags,int borderType, const Scalar& borderValue)

The function warpAffine transforms the source image using the specified matrix:

\texttt{dst} (x,y) =  \texttt{src} ( \texttt{M} _{11} x +  \texttt{M} _{12} y +  \texttt{M} _{13}, \texttt{M} _{21} x +  \texttt{M} _{22} y +  \texttt{M} _{23})

when the flag WARP_INVERSE_MAP is set. Otherwise, the transformation is first inverted with invertAffineTransform() and then put in the formula above instead of M . The function cannot operate in-place.

if( !(flags & WARP_INVERSE_MAP) )
    {
        double D = M[0]*M[4] - M[1]*M[3];
        D = D != 0 ? 1./D : 0;
        double A11 = M[4]*D, A22=M[0]*D;
        M[0] = A11; M[1] *= -D;
        M[3] *= -D; M[4] = A22;
        double b1 = -M[0]*M[2] - M[1]*M[5];
        double b2 = -M[3]*M[2] - M[4]*M[5];
        M[2] = b1; M[5] = b2;
    }

不设置flag  WARP_INVERSE_MAP时,应该就是前后映射;也就是opencv默认向后映射;

getAffineTransform( const Point2f src[], const Point2f dst[] )第一个参数为变换前的图像时src;

warpAffine_self(InputArray _src, OutputArray _dst,InputArray _M0, Size 

dsize,int flags,int borderType, const Scalar& borderValue)

其中flags=16,效果图如图所示

效果图:





另一种


  // 获取变换矩阵
    rot = getRotationMatrix2D(center,degree,scale);
    rimg;
    warpAffine(img,rimg,rot,img.size());
    imshow("img",img);
    imshow("rimg",rimg);

    // 获取变换之后的 区域,这个很重要,不然的话,变换之后的图像显示不全
    Rect bbox;
    bbox = RotatedRect(center,Size(scale*img.cols,scale*img.rows),degree).boundingRect();

    // 对变换矩阵的最后一列做修改,重新定义变换的 中心

    rot.at<double>(0,2) += bbox.width/2 - center.x;
    rot.at<double>(1,2) += bbox.height/2 - center.y;


    Mat dst;
    warpAffine(img,dst,rot, bbox.size());
    imshow("dst",dst);

box = RotatedRect(center,Size(scale*img.cols,scale*img.rows),degree).boundingRect(); 
是什么鬼?** 
答:这一句就是获取,展示变换之后图像所需图片的大小。 
手册中 RotatedRect 给出的一个例子很好的展示了这个意思: 
这里写图片描述 
图中蓝色是利用 RotatedRect 得到的 Rect 的区域,绿色是变换之后的图像。 
问题:最后boundingRect(); 表示什么意思呢? 
答:直观理解相当于对这个区域“向大取整”。 
**问题:代码中 
rot.at<double>(0,2) += bbox.width/2 - center.x; 
rot.at<double>(1,2) += bbox.height/2 - center.y; 

是什么意思呢?** 
答:还记得前面最后推导出来的公式么: 
这里写图片描述 
这两行代码的意思就相当于:这里写图片描述

  • 直观的意义就是:变换前的中心(x0,y0),在变换之后在(bw/2,bh/2)。也就是 dst 的中心。 
    **问题:为什么你代码中,将变换前的中心设置为 
    center = Point2f(img.cols/2.0, img.rows/2.0);? 
    设置为其他的点不可以么?** 
    答:设置为其他的点,确实不可以,还是会出现显示不全的问题。

  • 我们关心的是放射变换之后的全图是生么样的,与变换前的中心在哪里没有关系,只是相当于将变换之后的图像进行了平移。因此,我们用这种最简单粗暴的方式来得到我们想要的效果。


(1)

图像重映射:即是把一个图像中一个位置的像素放置到另一个图像指定位置的过程因为有时候源图像和目标图像并不总是一一对应的关系(目标图像的像素可能映射到源图像的非整数坐标上),所以有时候会需要做插值。

         描述映射过程:通过重映射来表达每个像素的位置(x,y):g(x,y)= f(h(x,y))

         其中:克()是目标图像,即重映射的结果; f()的是源图像; H(X,Y)是作用于(X,Y)的映射方法函数如H(X,Y)=(。 I.cols-X,Y),得到的目标图像将是按照X轴方向发生翻转。

         映射分为向前映射和向后映射。将输入映射到输出的向前映射,反正就是向后映射。即如果已知源图像到目标图像的坐标变换,即可以知道源图像的一点在变换后在目标图像的位置,称为向前映射。如果知道目标图像的一点在变换前在源图像上的位置,称为向后映射,向后映射比较直观,计算量小,OpenCV中的中经常使用的图像变换都是采用向后映射的方法来处理。但向后映射需要知道变换的反变换公式,但在有些变换比较复杂的场合,这个反变换是很难得到的。此时就需要采用前向映射的方法进行变换了。

(2)

opencv里面用的±符号有差别

(1)

OpenCV 从2.4.3开始加入了并行计算的函数parallel_for和parallel_for_(更准确地讲,parallel_for以前就存在于tbb模块中,但是OpenCV官网将其列在2.4.3.的New Features中,应该是重新改写过的)。

2.4.3中自带的calcOpticalFlowPyrLK函数也用parallel_for重写过了,之前我一直认为parallel_for就是用来并行计算的,之前也自己写了一些用parallel_for实现的算法。直到今天在opencv官网中看到别人的提问,才发现parallel_for实际上是serial loop,而parallel_for_才是parallel loop(OpenCV官网answer)。

为了比较for循环,parallel_for和parallel_for_ 三者的差异,下面做了一个简单的测试,对一个Mat中所有的元素(按列为单位)做立方操作。


Code

test.hpp

[cpp]  view plain  copy
  1. /**@ Test parallel_for and parallel_for_ 
  2. /**@ Author: chouclee 
  3. /**@ 03/17/2013*/  
  4. #include <opencv2/core/internal.hpp>  
  5. namespace cv  
  6. {  
  7. namespace test  
  8. {  
  9.     class parallelTestBody : public ParallelLoopBody//参考官方给出的answer,构造一个并行的循环体类  
  10.     {  
  11.     public:  
  12.         parallelTestBody(Mat& _src)//class constructor  
  13.         {  
  14.             src = &_src;  
  15.         }  
  16.         void operator()(const Range& range) const//重载操作符()  
  17.         {  
  18.             Mat& srcMat = *src;  
  19.             int stepSrc = (int)(srcMat.step/srcMat.elemSize1());//获取每一行的元素总个数(相当于cols*channels,等同于step1)  
  20.             for (int colIdx = range.start; colIdx < range.end; ++colIdx)  
  21.             {  
  22.                 float* pData = (float*)srcMat.col(colIdx).data;  
  23.                 for (int i = 0; i < srcMat.rows; ++i)  
  24.                     pData[i*stepSrc] = std::pow(pData[i*stepSrc],3);  
  25.             }     
  26.         }  
  27.   
  28.     private:  
  29.         Mat* src;  
  30.     };  
  31.   
  32.     struct parallelTestInvoker//构造一个供parallel_for使用的循环结构体  
  33.     {  
  34.         parallelTestInvoker(Mat& _src)//struct constructor  
  35.         {  
  36.             src = &_src;  
  37.         }  
  38.         void operator()(const BlockedRange& range) const//使用BlockedRange需要包含opencv2/core/internal.hpp  
  39.         {  
  40.             Mat& srcMat = *src;  
  41.             int stepSrc = (int)(srcMat.step/srcMat.elemSize1());  
  42.             for (int colIdx = range.begin(); colIdx < range.end(); ++colIdx)  
  43.             {  
  44.                 float* pData = (float*)srcMat.col(colIdx).data;  
  45.                 for (int i = 0; i < srcMat.rows; ++i)  
  46.                     pData[i*stepSrc] = std::pow(pData[i*stepSrc],3);  
  47.             }  
  48.         }  
  49.         Mat* src;  
  50.     };  
  51. }//namesapce test  
  52. void parallelTestWithFor(InputArray _src)//'for' loop  
  53. {  
  54.     CV_Assert(_src.kind() == _InputArray::MAT);  
  55.     Mat src = _src.getMat();  
  56.     CV_Assert(src.isContinuous());  
  57.     int stepSrc = (int)(src.step/src.elemSize1());  
  58.     for (int x = 0; x < src.cols; ++x)  
  59.     {  
  60.         float* pData = (float*)src.col(x).data;  
  61.         for (int y = 0; y < src.rows; ++y)  
  62.             pData[y*stepSrc] = std::pow(pData[y*stepSrc], 3);  
  63.     }  
  64. };  
  65.   
  66. void parallelTestWithParallel_for(InputArray _src)//'parallel_for' loop  
  67. {  
  68.     CV_Assert(_src.kind() == _InputArray::MAT);  
  69.     Mat src = _src.getMat();  
  70.     int totalCols = src.cols;  
  71.     typedef test::parallelTestInvoker parallelTestInvoker;  
  72.     parallel_for(BlockedRange(0, totalCols), parallelTestInvoker(src));  
  73. };  
  74.   
  75. void parallelTestWithParallel_for_(InputArray _src)//'parallel_for_' loop  
  76. {  
  77.     CV_Assert(_src.kind() == _InputArray::MAT);  
  78.     Mat src = _src.getMat();  
  79.     int totalCols = src.cols;  
  80.     typedef test::parallelTestBody parallelTestBody;  
  81.     parallel_for_(Range(0, totalCols), parallelTestBody(src));  
  82. };  
  83. }//namespace cv  
main.cpp

[cpp]  view plain  copy
  1. /**@ Test parallel_for and parallel_for_ 
  2. /**@ Author: chouclee 
  3. /**@ 03/17/2013*/  
  4. #include <opencv2/opencv.hpp>  
  5. #include <time.h>  
  6. #include "test.hpp"  
  7. using namespace cv;  
  8. using namespace std;  
  9.   
  10. int main(int argc, char* argv[])  
  11. {  
  12.     Mat testInput = Mat::ones(40,400000, CV_32F);  
  13.     clock_t start, stop;  
  14.   
  15.     start = clock();  
  16.     parallelTestWithFor(testInput);  
  17.     stop = clock();  
  18.     cout<<"Running time using \'for\':"<<(double)(stop - start)/CLOCKS_PER_SEC*1000<<"ms"<<endl;  
  19.   
  20.     start = clock();  
  21.     parallelTestWithParallel_for(testInput);  
  22.     stop = clock();  
  23.     cout<<"Running time using \'parallel_for\':"<<(double)(stop - start)/CLOCKS_PER_SEC*1000<<"ms"<<endl;  
  24.   
  25.     start = clock();  
  26.     parallelTestWithParallel_for_(testInput);  
  27.     stop = clock();  
  28.     cout<<"Running time using \'parallel_for_\':"<<(double)(stop - start)/CLOCKS_PER_SEC*1000<<"ms"<<endl;  
  29.   
  30.     system("pause");  
  31. }  

Result
输入为400000*40时,结果如下:
Debug模式
Running time using 'for': 1376ms
Running time using 'parallel_for': 1316ms
Running time using 'parallel_for_': 553ms
Release模式
Running time using 'for': 463ms
Running time using 'parallel_for': 475ms
Running time using 'parallel_for_': 301ms

输入改为40*400000
Debug模式
Running time using 'for': 1005ms
Running time using 'parallel_for': 1013ms
Running time using 'parallel_for_': 526ms
Release模式
Running time using 'for': 105ms
Running time using 'parallel_for': 106ms
Running time using 'parallel_for_': 81ms

输入改为4000*4000
Debug模式
Running time using 'for': 1138ms
Running time using 'parallel_for': 1136ms
Running time using 'parallel_for_': 411ms
Release模式
Running time using 'for': 234ms
Running time using 'parallel_for': 239ms
Running time using 'parallel_for_': 130ms

大多数情况下,parallel_for比for循环慢那么一丁丁点儿,有时甚至会比for循环快一些,总体上两者差不多,parallel_for_一直都是最快的。但上面的代码只是做测试使用(因此强制按列进行操作),实际上,像上面这种简单的操作,直接对Mat使用for循环和指针递增操作,只需要几十毫秒。但是,对于复杂算法,比如光流或之类的,使用parallel_for(虽然不是并行操作,但代码简洁易于维护,且速度和for循环差不多)或者parallel_for_将是不错的选择。

猜你喜欢

转载自blog.csdn.net/weixin_41484240/article/details/80589790