图像平移:图像的平移是将一幅图像上的所有点都按照给定的偏移量在水平方向沿x轴、在垂直方向上沿y轴移动,平移后的图像与原图像大小相同。设(x0,y0) 为原图像上的一点,图像水平平移量为△x,垂直平移量为△y,则平移后点(x0,y0)坐标将变为(x1,y1),它们之间的数学关系式如下,坐标平移原理如下图所示:
本次实验图像用的时500w像素的图像(2592×1944),且深度为8。
C# 代码实现
上面代码种tempArray数组用Array.Fill方法初始化默认值,因为图像背景为黑色,为了方便区分,设置为白色,以就是:Array.Fill(tempArray, byte.MaxValue);
但是性能很差,耗时808、383ms,非常耗时,如下图:
接下来我们做算法优化,优化方向:减少重复计算和边界处理。如下:
耗时截图如下:
优化非常有效,性能嘎嘎猛!
但是作为simd资深玩家,怎么可能止步到此,接下来我们用simd优化,如下:
耗时如下:
哇靠!性能再一次突破!太猛了~
附:OpeCV Sharp代码:
为了兼容24、32深度图像,我们可以做如下修改(simd代码同样修改方法):
private unsafe Bitmap? Translation2()
{
if (string.IsNullOrEmpty(_imagePath)) return null;
Bitmap bitmap = new Bitmap(_imagePath);
Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
BitmapData bitmapData = bitmap.LockBits(rect, ImageLockMode.WriteOnly, bitmap.PixelFormat);
byte* ptrSrc = (byte*)bitmapData.Scan0;
int bytes = bitmapData.Stride * bitmapData.Height;
byte[] tempArray = new byte[bytes];
Array.Fill(tempArray, byte.MaxValue);
int xOffset = (int)numericUpDown1.Value;
int yOffset = (int)numericUpDown2.Value;
int yoffset1, yoffset2;
int tempy = yOffset * bitmapData.Stride;
int startX;
int startY;
int nheight;
int nwidth;
if (xOffset >= 0)
{
startX = 0;
nwidth = bitmapData.Stride - xOffset;
}
else
{
startX = -xOffset;
nwidth = bitmapData.Stride;
}
if (yOffset >= 0)
{
startY = 0;
nheight = bitmap.Height - yOffset;
}
else
{
startY = -yOffset;
nheight = bitmap.Height;
}
int setp = 1;
if (bitmap.PixelFormat == PixelFormat.Format24bppRgb)
setp = 3;
else if(bitmap.PixelFormat == PixelFormat.Format32bppRgb)
setp = 4;
else
setp = 1;
fixed (byte* ptr = tempArray)
{
int x = xOffset * setp;
for (int i = startY; i < nheight; i++)
{
yoffset1 = i * bitmapData.Stride;
yoffset2 = yoffset1 + tempy;
for (int j = startX; j < nwidth; j++)
{
//*(ptr + j + xOffset + yoffset2) = *(ptrSrc + j + yoffset1);
for (int k = 0; k < setp; k++)
{
*(ptr + j + x + k + yoffset2) = *(ptrSrc + j + k + yoffset1);
}
}
}
}
Marshal.Copy(tempArray, 0, bitmapData.Scan0, bytes);
bitmap.UnlockBits(bitmapData);
return bitmap;
}