我目前正参与一个项目,我的图像量非常大。此卷必须非常快速地处理(加,减,阈值等)。此外,大多数卷都非常大,以至于它们的事件不适合系统的内存。 出于这个原因,我创建了一个抽象卷类(VoxelVolume),它承载卷和图像数据并重载运算符,以便可以对卷执行常规数学运算。因此打开了另外两个问题,我将把它们放入另外两个线程的堆栈流中。
这是我的第一个问题。我的卷的实现方式只能包含float数组,但大多数包含的数据来自UInt16图像源。只有卷上的操作才能创建浮点数组图像。
当我开始实现这样一个卷时,该类看起来如下:
public abstract class VoxelVolume<T>
{
...
}
然后我意识到重载运算符或返回值会变得更复杂。一个例子是:
public abstract class VoxelVolume<T>
{
...
public static VoxelVolume<T> Import<T>(param string[] files)
{
}
}
同时添加两个重载运算符会更复杂:
...
public static VoxelVolume<T> operator+(VoxelVolume<T> A, VoxelVolume<T> B)
{
...
}
让我们假设我可以克服上述问题,但是我有不同类型的包含图像数据的数组。因为我已经修改了我的卷中的类型浮动没有问题,我可以在添加两个图像卷数组的内容时进行不安全的操作。我在这里阅读了几个主题并浏览了一下网页,但是当我想快速添加两个不同类型的数组时,却没有找到真正好的解释。不幸的是,对泛型的每个数学运算都是不可能的,因为C#无法计算基础数据类型的大小。当然可以通过使用C ++ / CLR解决这个问题,但目前我所做的一切都是在32位和64位运行而不必做任何事情。在我看来切换到C ++ / CLR(很高兴纠正我,如果我错了),我已经绑定到某个平台(32位),当我让应用程序在另一个平台(64位)上运行时,我必须编译两个程序集。这是真的吗?
很快就被问到:如何以快速的方式添加两个不同类型的两个数组呢?是不是C#的开发人员没有想到这一点。切换到另一种语言(C# - &gt; C ++)似乎不是一种选择。
我意识到只是执行此操作
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)
{
// Assume the length of both arrays is equal
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;
}
}
如果上面的代码不太正确,请原谅,我是在不使用C#编辑器的情况下编写的。上面显示的这种解决方案是否可以理解?如果我犯了错误或者描述了一些不完整的东西,请随时询问。
感谢您的帮助 马丁
答案 0 :(得分:1)
这似乎是“为什么我们没有INumerical接口”的(复杂)版本。
对最后一个问题的简短回答是:不,转向不安全的指针是没有解决办法的,编译器仍然无法找出+
中的((T1)*ptrA + (T2)*ptrB))
。
答案 1 :(得分:1)
如果您只有float
和UInt32
等几种类型,请提供所有需要的转化功能,例如从VoxelVolume<UInt32>
到VoxelVolume<float>
,并对{{VoxelVolume<float>
进行数学运算1}}。对于大多数实际情况来说,这应该足够快。您甚至可以提供从VoxelVolume<T1>
到VoxelVolume<T2>
的通用转换函数(如果T1可以转换为T2)。另一方面,如果你真的需要一个
public static VoxelVolume<T2> operator+(VoxelVolume<T1> A,VoxelVolume<T2> B)
每个数组元素的类型从T1
转换为T2
,是什么阻碍了您编写此类运算符?
答案 2 :(得分:1)
导入,作为泛型类的成员,可能也不需要本身是通用的。如果是这样,你绝对不应该对类的泛型参数和函数的泛型参数使用相同的名称T
。
你可能正在寻找的是Marc Gravell的Generic Operators
至于你关于C ++ / CLI的问题,如果你使用模板而不是泛型,这可能会有所帮助,因为typename T
的所有可能值都在编译时被控制,编译器会查找每个的运算符。此外,您可以使用/clr:pure
或/clr:safe
,在这种情况下,您的代码将是MSIL,可以在AnyCPU
上运行,就像C#一样。
答案 3 :(得分:0)
不可否认,我没有阅读整个问题(这有点太长了),但是:
VoxelVolume<T> where T : ISummand ... T a; a.Add(b)
static float Sum (this VoxelVolume<float> self, VoxelVolume<float> other) {...}