汇编学习:二维数组遍历

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010839382/article/details/52752771

作为正式接触汇编的开篇,本文将研究二维数组的遍历问题。在图像处理中,通常需要遍历图像像素(即二维数组)。下面给出三个版本的遍历函数,并研究他们的汇编代码(VC2010编译器,x86版,Release模式)。

(1)在两层循环内每次根据行列索引计算元素位置。

(2)为了避免在内存循环内的乘法计算,可在每次外层循环中计算好行起始地址,内层循环每次执行++操作。

(3)将外层循环的乘法操作也去掉,在循环外部先计算好数组的起始地址,内层循环每次执行++操作即可。

测试程序实现对图像的反相操作(即B=255-A)。我们的直观感觉时他们的访问效率应该逐步提升的,本人之前也是一直用第三种方法来遍历图像像素的。但本次测试发现,效率根本没有提升。究其原因,是编译器做了优化。下面分别给出三个函数以及他们对应的汇编代码(VS中调试—>窗口-->反汇编可查看),并对汇编代码做了注释。


(1)版本1

inline void InvimageV1(uchar *A ,uchar *B,int Width,int Height)
{
	for (int Y=0;Y<Height;Y++)
	{
		for (int X=0;X<Width;X++)
		{
			B[Y*Width+X]=255-A[Y*Width+X];
		}
	}
}

汇编:


其中黄色覆盖区域为外层循环,绿色覆盖区域为内层循环。


(2)版本2
inline void InvimageV2(uchar *A ,uchar *B,int Width,int Height)
{

	uchar *LinePS,*LinePD;
	for (int Y=0;Y<Height;Y++)
	{
		LinePS=A+Y*Width;
		LinePD=B+Y*Width;
		for (int X=0;X<Width;X++)
		{
			LinePD[X]=255-LinePS[X];
		}
	}
}
汇编:




其中黄色覆盖区域为外层循环,绿色覆盖区域为内层循环。

(3)版本3

inline void InvimageV3(uchar *A ,uchar *B,int Width,int Height)
{
	uchar *LinePS=A,*LinePD=B;
	for (int Y=0;Y<Height;Y++)
	{
		for (int X=0;X<Width;X++)
		{
			LinePD[0]=255-LinePS[0];
			LinePS++;
			LinePD++;
		}
	}
}

汇编:


其中黄色覆盖区域为外层循环,绿色覆盖区域为内层循环。

可以看出三个版本的内层循环操作上并没有什么差异,Release模式下编译器已经将循环内计算地址中的乘法计算优化成加法,而我们第三个版本的目的正是去掉乘法计算,因此三者执行效率上并没有多大差异。

下面给出完整的测试代码:

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std; 
inline void InvimageV1(uchar *A ,uchar *B,int Width,int Height)
{
	for (int Y=0;Y<Height;Y++)
	{
		for (int X=0;X<Width;X++)
		{
			B[Y*Width+X]=255-A[Y*Width+X];
		}
	}
}
inline void InvimageV2(uchar *A ,uchar *B,int Width,int Height)
{

	uchar *LinePS,*LinePD;
	for (int Y=0;Y<Height;Y++)
	{
		LinePS=A+Y*Width;
		LinePD=B+Y*Width;
		for (int X=0;X<Width;X++)
		{
			LinePD[X]=255-LinePS[X];
		}
	}
}
inline void InvimageV3(uchar *A ,uchar *B,int Width,int Height)
{
	uchar *LinePS=A,*LinePD=B;
	for (int Y=0;Y<Height;Y++)
	{
		for (int X=0;X<Width;X++)
		{
			LinePD[0]=255-LinePS[0];
			LinePS++;
			LinePD++;
		}
	}
}

int main()
{
	Mat src,dst;
	int nWidth,nHeight,iterNum=1000;
	uchar *pSrc,*pDst;
	int64 t1,t2;
	src=imread("1.jpg",0);
	dst = src.clone();
	nWidth=src.cols;
	nHeight=src.rows;		
	pSrc=src.data;
	pDst=dst.data;
	imshow("原始图",src);
	t1=getTickCount();
	for (int i=0;i<iterNum;i++)
	{
		InvimageV1(pSrc ,pDst,nWidth,nHeight);
	}
	t2=getTickCount();
	cout<<"InvimageV1:"<<(t2 - t1)*1000./getTickFrequency()<<"ms"<<endl;
	imshow("InvimageV1",dst);
	
	t1=getTickCount();
	for (int i=0;i<iterNum;i++)
	{
		InvimageV2(pSrc ,pDst,nWidth,nHeight);
	}
	t2=getTickCount();
	cout<<"InvimageV2:"<<(t2 - t1)*1000./getTickFrequency()<<"ms"<<endl;
	imshow("InvimageV2",dst);

	t1=getTickCount();
	for (int i=0;i<iterNum;i++)
	{
		InvimageV3(pSrc,pDst,nWidth,nHeight);
	}
	t2=getTickCount();
	cout<<"InvimageV3:"<<(t2 - t1)*1000./getTickFrequency()<<"ms"<<endl;
	imshow("InvimageV3",dst);
	waitKey(0);
}






猜你喜欢

转载自blog.csdn.net/u010839382/article/details/52752771