快速反转存储在一维阵列中的3D数据轴

时间:2016-01-11 05:12:43

标签: c# arrays sorting

我有一个代表3D图像的大型数据集(大约100,000,000像素)。我想反转沿着' z'图像的轴。我的数据存储在一个字节数组中,数据排序为x,y,z(即[] = {(x = 0,y,z = 0),(x = 1,y = 0,z = 0), (x = 2,y = 0,z = 0)......)

我可以使用以下代码轻松对它们进行排序,但我希望尽可能减少计算时间(目前报告大约7秒)。我正在考虑使用数组'排序'函数,但不知道如何处理索引。

这是我目前的代码:

private int GetIndex(Image _image, int _x, int _y, int _z)
{
    return (_z * _image.Size.X * _image.Size.Y) + (_y * _image.Size.X) + _x;;
}

private void InvertZ(Image _image)
{
    for (int z = 0; z < _image.Size.Z/2; z++)
    {
        for (int y = 0; y < _image.Size.Y; y++)
        {
            for (int x = 0; x < _image.Size.X; x++)
            {
                int srcIndex = GetIndex(_image, x, y, z);
                int destIndex = GetIndex(_image, x, y, _image.Size.Z - z - 1);

                byte src = _image.Buffer[srcIndex];
                byte dest = _image.Buffer[destIndex];

                _image.Buffer[srcIndex] = dest;
                _image.Buffer[destIndex] = src;
            }
        }
    }
}

3 个答案:

答案 0 :(得分:1)

一种解决方案是复制每个帧。大幅减少迭代次数。

    private void InvertZ(Image _image)
    {            
        int frameSize = _image.Size.X * _image.Size.Y;
        byte[] temp = new byte[frameSize];

        for (int z = 0; z < _image.Size.Z / 2; z++)
        {
            int inverseZ = _image.Size.Z - z - 1;

            Array.Copy(_image.Buffer, z * frameSize, temp, 0, frameSize);
            Array.Copy(_image.Buffer, inverseZ * frameSize, _image.Buffer, z * frameSize, frameSize);
            Array.Copy(temp, 0, _image.Buffer, inverseZ  * frameSize, frameSize);
        }
    }

运行时间约&lt; 18毫秒与3175毫秒相比。

答案 1 :(得分:0)

即使它使用多个循环(每个轴一个循环),这可能比单循环解决方案更快。

有两种主要的速度增强功能(图像处理中非常常见的算法增强功能)。

  1. 图像被转换为​​数组以便快速进行腿部练习

  2. 索引在循环中部分预先计算,确保尽可能少地计算。 (不再使用Image中的内置物,这对于一个像素和另一个像素都很好但不适合整个地图)

  3. 我通常只在2d上完成这项工作,所以只添加了z轴。将它作为最后一个循环可能会更快。 (边缘示例在2d运行,如果y在x之前,那么由于内存/缓存的构建方式,你会以大约30-40%的速度运行Src这也发生在3d(这就是为什么我放置了z(前面的水平/页面))

    以下是我将以解决方案为基础的代码。

    private void InvertZ(Image _image)
    {            
        byte[] array =imageToByteArray(_image);
        int pageSize = _Image.Size.Y * _Image.Size.X;
        for (int z = 0; z < _image.Size.Z/2; z++)
        {
            int level = z * pageSize;
            int dstLevel = (_image.Size.Z - z - 1) * pageSize;
            for (int x = 0; x < _image.Size.X; x++)
            {
                int Row = x*_Image.Size.Y;
                int RowOnLevel = level + Row ;
                int dstRowOnLevel = dstLevel + xRow;
                for (int y = 0; y < _image.Size.Y; y++)
                {
                    int srcIndex = RowOnLevel + y;
                    int destIndex = dstRowOnLevel + y;
    
                    byte tmpDest = array[destIndex];
                    array[destIndex] = array[srcIndex];
                    array[srcIndex] = tmpDest;
                }
            }
        }
        return byteArrayToImage(array);
    }
    
    public Image byteArrayToImage(byte[] byteArrayIn)
    {
        MemoryStream ms = new MemoryStream(byteArrayIn);
        Image returnImage = Image.FromStream(ms);
        return returnImage;
    }
    
    public byte[] imageToByteArray(System.Drawing.Image imageIn)
    {
        MemoryStream ms = new MemoryStream();
        imageIn.Save(ms,System.Drawing.Imaging.ImageFormat.Gif);
        return  ms.ToArray();
    }
    

答案 2 :(得分:0)

你可以使用数组布局就是这样的事实

Z     Length
====  ======
[0]   x * y
[1]   x * y
[2]   x * y
...
[z-1] x * y

这使我们可以大大减少索引计算。我们可以使用像这样的经典O(N)反向算法的变体

static void InvertZ(Image _image)
{            
    int len = _image.Size.X * _image.Size.Y;
    for (int lo = 0, hi = (_image.Size.Z - 1) * len; lo < hi; lo += len, hi -= len)
        for (int i = 0; i < len; i++)
            Swap(ref _image.Buffer[lo + i], ref _image.Buffer[hi + i]);
}

static void Swap<T>(ref T a, ref T b) { var c = a; a = b; b = c; }