I can perform the task of chopping up a 2D images into small "tiles" and then stack these tiles as a 3D image stack by the following example codes:
// create a test image
number imgWd = 256, imgHt = 32;
image img := exprsize( imgWd, imgHt, iradius );
img.SetName( "data" );
img.ShowImage();
// define "tile" size
number size = 32;
// number of tiles
number count = imgWd/size;
// create a 3D stack of tiles
//
// ====== can we use SlicN() to replace the following code? ============
image rst := exprsize(size, size, count, img[icol + iplane*size, irow]);
// =====================================================================
//
rst.SetName( "tiles" );
rst.ShowImage();
How do we use the "SliceN" function to accomplish the same task? The logic is kind of tricky for me to figure it out.
Thanks ahead.
Mike's answer is correct in that sliceN cannot be used (without iteration) to directly create a higher dimensional image out of "chunked" pieces.
While it can create image of higher dimension from lower dimensional sources, all the new image's dimensions can only be mapped onto continuous sampling stretches from a single origin in the source along one of its dimensions. So one can "duplicate" sampling dimensions like this:
image img1D := exprsize( 100, sin(icol/iwidth*pi()))
img1D.ShowImage()
image img2D := img1D.SliceN(1,2, 50, 0,25,1, 0,25,-1)
img2D.ShowImage()
But one can not define differnt sampling "starting points" as would be needed for the piecewise resampling.
Besides the for-loop over slice (which is faster than the single expression), the link Mike provided shows one even faster solution for this particular use case:
Both images - the 2D "tiled stretch" - and the "3D Stack of tiles" actually would have the same memory outline, if it were a vertical stripe. This is so because DigitalMicrograph stores X as "inner" dimension, then Y, then Z. The trick is to use streaming in/out of a taggroup, as the taggroup only holds the array, but no shape information. So, for a vertical stripe one could do the below (which again is a lot faster than the slice2):
number count = 10;
number size = 256;
number imgWd = size, imgHt = size*count ;
image img := exprsize( imgWd, imgHt, irow % (size+icol));
img.SetName( "data" );
image rst:= RealImage("tiles", 4, size, size, count);
object dStream = NewStreamFromBuffer(0);
ImageWriteImageDataToStream(img,dStream,0);
dStream.StreamSetPos(0,0);
ImageReadImageDataFromStream(rst ,dStream,0);
img.ShowImage()
rst.ShowImage()
If your input has to be a horizontal strip you can work around this by flipping X&Y both in the 2D input and the 3D output with the 'slice' command. It's still rather fast, as the data access with slice is taking nearly no time. (It doesn't copy any values.)
// create a test image
number count = 5000;
number size = 64;
number imgWd = size*count, imgHt = size ;
image img := exprsize( imgWd, imgHt, icol % (size+irow));
img.SetName( "data" );
img.ShowImage();
number tickStart ,tickStart2,tickStart3,tickStart4,tickEnd
number TPS = GetHighResTicksPerSecond()
{
tickStart = GetHighResTickCount()
image test1 := exprsize(size, size, count, img[icol + iplane*size, irow])
test1.SetName("Tiles (direct)")
Result("\n\n Direct exprsize: ")
tickEnd = GetHighResTickCount()
Result("\n expression : "+ ((tickEnd-tickStart)/TPS*100) + " ms")
Result("\n TOTAL time : "+ ((tickEnd-tickStart)/TPS*100) + " ms")
test1.ShowImage()
}
{
tickStart = GetHighResTickCount()
image test2 := RealImage("Tiles (Slice2)", 4, size, size, count)
tickStart2 = GetHighResTickCount()
for (number islice = 0; islice < count; islice++)
test2.Slice2(0, 0, islice, 0, size, 1, 1, size, 1) = img.Slice2(islice * size, 0, 0, 0, size, 1, 1, size, 1);
tickEnd = GetHighResTickCount()
Result("\n\n Slice2 & Loop: ")
Result("\n image creation : "+ ((tickStart2-tickStart)/TPS*100) + " ms")
Result("\n slice2 loop : "+ ((tickEnd-tickStart2)/TPS*100) + " ms")
Result("\n TOTAL time : "+ ((tickEnd-tickStart)/TPS*100) + " ms")
test2.ShowImage()
}
{
tickStart = GetHighResTickCount()
image test3 := RealImage("Tiles (Flip & Stream)", 4, size, size, count)
tickStart2 = GetHighResTickCount()
object dStream = NewStreamFromBuffer(0)
ImageWriteImageDataToStream(img.slice2(0,0,0,1,imgHt,1,0,imgWd,1),dStream,0)
tickStart3 = GetHighResTickCount()
dStream.StreamSetPos(0,0)
ImageReadImageDataFromStream(test3 ,dStream,0)
tickStart4 = GetHighResTickCount()
test3 := test3.slice3(0,0,0, 1,size,1, 0,size,1, 2,count,1)
tickEnd = GetHighResTickCount()
Result("\n\n Streaming & Flip: ")
Result("\n image creation : "+ ((tickStart2-tickStart)/TPS*100) + " ms")
Result("\n flip & stream out: "+ ((tickStart3-tickStart2)/TPS*100) + " ms")
Result("\n stream back in : "+ ((tickStart4-tickStart3)/TPS*100) + " ms")
Result("\n flip result : "+ ((tickEnd-tickStart4)/TPS*100) + " ms")
Result("\n TOTAL time : "+ ((tickEnd-tickStart)/TPS*100) + " ms")
test3.ShowImage()
}