I am currently participating in a project where I have very large volumes of images. These volumes must be processed very quickly (addition, subtraction, threshold value, etc.). In addition, most of the volume is so large that they do not fit into the system’s memory. For this reason, I created an abstract volume class (VoxelVolume), which places volume and image data and overloads operators so that regular mathematical operations on volumes can be performed. This opened up two more questions, which I will put in stackoverflow in two additional threads.
Here is my first question. My volume is implemented in such a way that it can contain only the data of the float array, but most of the data contained is from the image source UInt16. Only volume operations can create floating-point images.
When I started to implement such a volume, the class looked like this:
public abstract class VoxelVolume<T>
{
...
}
but then I realized that overloading statements or return values would become more complicated. An example is:
public abstract class VoxelVolume<T>
{
...
public static VoxelVolume<T> Import<T>(param string[] files)
{
}
}
also adding two overload operators would be more complicated:
...
public static VoxelVolume<T> operator+(VoxelVolume<T> A, VoxelVolume<T> B)
{
...
}
, , , . , , , . , , , . , , # . , , ++/CLR, , , 32- 64- -. , ++/CLR ( , ), (32 ), , (64-). ?
: . , # . (# → ++) .
,
float []A = new float[]{1,2,3};
byte []B = new byte[]{1,2,3};
float []C = A+B;
, , . , , :
public static class ArrayExt
{
public static unsafe TResult[] Add<T1, T2, TResult>(T1 []A, T2 []B)
{
TResult[] result = new TResult[A.Length];
GCHandle h1 = GCHandle.Alloc (A, Pinned);
GCHandle h2 = GCHandle.Alloc (B, Pinned);
GCHandle hR = GCHandle.Alloc (C, Pinned);
void *ptrA = h1.ToPointer();
void *ptrB = h2.ToPointer();
void *ptrR = hR.ToPointer();
for (int i=0; i<A.Length; i++)
{
*((TResult *)ptrR) = (TResult *)((T1)*ptrA + (T2)*ptrB));
}
h1.Free();
h2.Free();
hR.Free();
return result;
}
}
, , #. ? , , .