2016-01-11 32 views
0

我有一個大型數據集,它表示一個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)...)存儲在一維數組中的3D數據軸的快速反轉

我可以很容易地使用下面的代碼對它們進行排序,但是我希望儘可能減少計算時間(目前報告大約7秒)。我正在考慮使用數組'sort'函數,但不知道如何處理索引。

這裏是我當前的代碼:

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; 
      } 
     } 
    } 
} 
+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); 
     } 
    } 

運行時大約< 18毫秒相比3175毫秒。

+0

雖然我發佈了自己的答案,但由於使用了(可高度優化的)塊複製操作,因此此解決方案比我的解決方案更快,因此您已獲得我的投票。 –

0

即使使用多個循環,每個軸一個循環,這可能會更快。

有2個主要的速度增強(圖像處理內非常常見的算法增強)。

  1. 圖像被轉換爲​​陣列快速跑腿

  2. 該指數成爲環內部分預先計算,確保在你計算儘可能少的時間儘可能。 (在圖像不再使用內置的東西,這是很好的一個又一個像素,但不適合於整個地圖)

所以剛添加的Z軸,我通常只做二維這項工作。將它作爲最後一個循環可能會更快。 (如果y在x之前,則會在2d中運行的邊緣示例,那麼由於內存/緩存的構建方式,您會釋放大約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(); 
} 
0

可以使用的事實陣列布局是這樣

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

這使我們可以大大降低指數計算,我們可以使用經典的O(N)逆算法lik的變體e這

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; } 
相關問題