Gertjan Gielen
Gertjan Gielen

Reputation: 119

Slicing a 3d image

I'm trying to slice a 3d representation of a image. Following factors is known:

Voxels[] is an array of ushorts representing the grayscale of the pixel.

Presentation of image

Now i need to slice it in all possible directions. With let we say x, y or z.

Z-SliceY-SliceX-Slice

I have tree implementations for this, but they have one problem, they don't work with dimensions that are not the same. (Except for get Z Slice, this is working perfectly).

These are the methods:

private ushort[] GetZSlice(int z, ushort[] voxels, int DimensionX, int DimensionY)
{
   var res = new ushort[DimensionX * DimensionY];
   for(int j = 0; j < DimensionY; j++)
   {
       for(int i = 0; i < DimensionX; i++)
       {
           res[j*DimensionX + i] = voxels[z*DimensionX*DimensionY + j*DimensionX + i];
       }
   }
   return res;
}

This method is working perfectly, it does not mather wat i choose as the dimension.

The next two methods, with x or y as depth poses as a harder problem.

private ushort[] GetYSlice(int y, ushort[] voxels, int DimensionX, int DimensionY, int DimensionZ)
{
    var res = new ushort[DimensionX * DimensionZ];
    for( int i = 0; i < DimensionX; i++)
    {
        for( int j = 0; j < DimensionX; j++)
        {
            res[j + i*DimensionX] = voxels[j * DimensionZ * DimensionY + Y*DimensionZ + i]
        }
    }
    return res;
}

private ushort[] GetXSlice(int x, ushort[voxels], int DimensionX, int DimensionY, int DimensionZ)
{
   var res = new short[DimensionY * DimensionZ];
   for(int i = 0; i < DimensionY; i++)
   {
       for(int j = 0; j < DimensionZ; j++)
       {
           res[j + i*DimensionZ] = voxels[i*DimensionY + j*DimensionZ*DimensionX + x]
       }
   }
   return res;
} 

How could I improve the last 2 methods so it works with dimensions that are not equal?

Upvotes: 2

Views: 323

Answers (1)

Spektre
Spektre

Reputation: 51845

Why not make universal slice function using basis vectors? It will be far less code the manage.

Basicly you got U,V axises each mapped into X,Y or Z. And the Slice W is the third unused axis. So you just loop the U,V and leave W as is. Each U,V has a basis vector (ux,uy,uz) , (vx,vy,vz) that describes the increment change in x,y,z coordinates.

I encoded it into my LED cube class in C++...

//---------------------------------------------------------------------------
class LED_cube
    {
public:
    int xs,ys,zs,***map;

    LED_cube()              { xs=0; ys=0; zs=0; map=NULL; }
    LED_cube(LED_cube& a)   { xs=0; ys=0; zs=0; map=NULL; *this=a; }
    ~LED_cube()             { _free(); }
    LED_cube* operator = (const LED_cube *a) { *this=*a; return this; }
    LED_cube* operator = (const LED_cube &a);
    void _free();
    void resize(int _xs,int _ys,int _zs);
    void cls(int col);                                  // clear cube with col 0x00BBGGRR
    void sphere(int x0,int y0,int z0,int r,int col);    // draws sphere surface with col 0x00BBGGRR
    void slice (char *uv,int slice,int col);            // draws (XY,XZ,YZ) slice with col 0x00BBGGRR
    void glDraw();                                      // render cube by OpenGL as 1x1x1 cube at 0,0,0
    };
//---------------------------------------------------------------------------
void LED_cube::slice(char *uv,int slice,int col)
    {
    // detect basis vectors from uv string
    int ux=0,uy=0,uz=0,us=0;
    int vx=0,vy=0,vz=0,vs=0;
    int x=slice,y=slice,z=slice,u,v,x0,y0,z0;
    if (uv[0]=='X') { x=0; ux=1; us=xs; }
    if (uv[0]=='Y') { y=0; uy=1; us=ys; }
    if (uv[0]=='Z') { z=0; uz=1; us=zs; }
    if (uv[1]=='X') { x=0; vx=1; vs=xs; }
    if (uv[1]=='Y') { y=0; vy=1; vs=ys; }
    if (uv[1]=='Z') { z=0; vz=1; vs=zs; }
    // render slice
    if ((x>=0)&&(x<xs)&&(y>=0)&&(y<ys)&&(z>=0)&&(z<zs))
     for (u=0;u<us;u++,x+=ux,y+=uy,z+=uz)
        {
        x0=x; y0=y; z0=z;
        for (v=0;v<vs;v++,x+=vx,y+=vy,z+=vz)
          map[x][y][z]=col;
        x=x0; y=y0; z=z0;
        }
    }
//---------------------------------------------------------------------------

As you can see it is quite nice and simple ... and still can be optimized much more. here usage and output example:

cube.resize(32,16,20);
cube.cls(0x00202020);
cube.slice("XY",5,0x000000FF);
cube.slice("XZ",5,0x0000FF00);
cube.slice("YZ",5,0x00FF0000);
cube.glDraw();

example

As you got your voxels stored in 1D array then just compute the address from x,y,z. so map[x][y][z] will became your voxels[(x*ys*zs)+(y*zs)+z] or what ever combination of axis order you got. This can be totally encoded into the basis vectors so you can have du=(ux*ys*zs)+(uy*zs)+uz and dv=... and increment the address directly not needing any multiplication latter ...

Upvotes: 2

Related Questions