Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/blackberry/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 这个代码可以优化吗?_C#_.net_Optimization_Image Processing - Fatal编程技术网

C# 这个代码可以优化吗?

C# 这个代码可以优化吗?,c#,.net,optimization,image-processing,C#,.net,Optimization,Image Processing,我有一些图像处理代码,可以循环处理2个多维字节数组(大小相同)。它从源数组中获取一个值,对其执行计算,然后将结果存储到另一个数组中 int xSize = ResultImageData.GetLength(0); int ySize = ResultImageData.GetLength(1); for (int x = 0; x < xSize; x++) { for (int y = 0; y < ySize; y++) {

我有一些图像处理代码,可以循环处理2个多维字节数组(大小相同)。它从源数组中获取一个值,对其执行计算,然后将结果存储到另一个数组中

int xSize = ResultImageData.GetLength(0);
int ySize = ResultImageData.GetLength(1);

for (int x = 0; x < xSize; x++)
{                
   for (int y = 0; y < ySize; y++) 
   {                                                
      ResultImageData[x, y] = (byte)((CurrentImageData[x, y] * AlphaValue) +
                                    (AlphaImageData[x, y] * OneMinusAlphaValue));
   }
}

如果使用锁位获取图像缓冲区,则应在外循环中通过y循环,在内循环中通过x循环,因为这是存储在内存中的方式(按行,而不是按列)。我想说11ms是相当快的,但是…

图像数据必须存储在多维(矩形)阵列中吗?如果改用锯齿数组,您可能会发现JIT有更多的优化可用(包括删除边界检查)。

一个选项是使用不安全的代码:在内存中修复数组并使用指针操作。不过,我怀疑速度的提高是否会如此剧烈

一个注意事项:你的时间安排如何?如果您使用的是DateTime,那么请注意该类的分辨率很低。您应该添加一个外循环,然后重复该操作,比如说十次——我打赌结果小于110毫秒

for (int outer = 0; outer < 10; ++outer)
{
    for (int x = 0; x < xSize; x++)
    {                
         for (int y = 0; y < ySize; y++) 
         {                                                
              ResultImageData[x, y] = (byte)((CurrentImageData[x, y] * AlphaValue) +
                                             (AlphaImageData[x, y] * OneMinusAlphaValue));
         }
    }
}
for(int-outer=0;outer<10;++outer)
{
对于(int x=0;x
因为矩阵中的每个单元格的计算似乎完全独立于其他单元格。您可能需要考虑使用多个线程来处理此问题。为了避免创建线程的成本,可以使用线程池

如果矩阵足够大,它可能是一个非常好的速度增益。另一方面,如果它太小,它可能没有帮助(甚至伤害)。不过值得一试

示例(伪代码)可能如下所示:

void process(int x, int y) {
    ResultImageData[x, y] = (byte)((CurrentImageData[x, y] * AlphaValue) +
        (AlphaImageData[x, y] * OneMinusAlphaValue));
}

ThreadPool pool(3); // 3 threads big

int xSize = ResultImageData.GetLength(0);
int ySize = ResultImageData.GetLength(1);

for (int x = 0; x < xSize; x++) {
     for (int y = 0; y < ySize; y++)  {
         pool.schedule(x, y);  // this will add all tasks to the pool's work queue
     }
}

pool.waitTilFinished(); // wait until all scheduled tasks are complete
void进程(int x,int y){
结果图像数据[x,y]=(字节)((CurrentImageData[x,y]*字母值)+
(AlphaImageData[x,y]*OneMinusAlphaValue));
}
线程池池(3);//3线大
int xSize=ResultImageData.GetLength(0);
int-ySize=ResultImageData.GetLength(1);
对于(int x=0;x

编辑:在评论中提到plinq可能是一个合适的替代方案:

这些都是独立的计算,因此如果您有多核CPU,您应该能够通过并行计算获得一些好处。请注意,您需要保留线程,只需将工作交给它们即可,因为如果每次都重新创建线程,那么线程创建的开销可能会使其速度变慢而不是变快


另一个可行的方法是把工作交给图形处理器。查看一些想法,例如,使用。

我建议运行一些空测试来确定理论界限。例如,从循环内部进行计算,看看节省了多少时间。尝试将双循环替换为运行相同次数的单循环,看看可以节省多少时间。然后,您可以确定您正在沿着正确的路径进行优化(我看到的两条路径是将双循环平坦化为单循环,并使用乘法[可能使用查找表会更快]。

非常快,您可以通过反向循环并与0进行比较来获得优化。大多数CPU都有一个比较0的快速运算

例如


请参见

如果CurrentImageData和/或AlphaImageData没有在每次运行代码段时更改,则可以在运行显示的代码段之前存储产品,并避免循环中的乘法运算


编辑:我刚刚想到的另一件事:有时int运算比byte运算快。用处理器缓存利用率抵消这一点(您将大大增加数据大小,并承受更大的缓存未命中风险)。

您可能正遭受边界检查的痛苦。就像Jon Skeet所说的那样,一个锯齿状数组而不是多维数组(即
data[][]
而不是
data[,]
)会更快,尽管这看起来很奇怪

编译器将进行优化

for (int i = 0; i < data.Length; i++) 
for(int i=0;i
通过消除每元素范围检查。但这是一种特殊情况,它对Getlength()不起作用


出于同样的原因,缓存或提升Length属性(将其放入xSize之类的变量中)也曾经是一件坏事,尽管我无法验证在Framework 3.5中,要获取此代码的任何实际speadup,您需要使用指针来访问数组,这将删除所有索引计算和边界检查

int size = ResultImageData.Length;
unsafe 
{
   fixed(byte* rp = ResultImageData, cp = CurrentImageData, ap = AlphaImageData) 
   {
      byte* r = rp;
      byte* c = cp;
      byte* a = ap;
      while (size > 0) 
      {
         *r = (byte)(*c * AlphaValue + *a * OneMinusAlphaValue);
         r++;
         c++;
         a++;
         size--;
      }
   }
}
编辑:

固定变量无法更改,因此我添加了代码,将指针复制到可以更改的新指针。

442368加法和884736乘法运算我认为在现代CPU上,11ms实际上非常慢

虽然我对.net的细节不太了解,但我知道高速计算并不是它的强项。在过去,我构建过有类似问题的java应用程序,我总是使用C库来进行图像/音频处理

从硬件的角度来看,您希望确保内存访问是顺序的,即按缓冲区在内存中存在的顺序逐步通过缓冲区。您可能还需要对其重新排序,以便编译器利用可用指令,如SIMD。如何实现这一点最终将取决于您的编译器,我无法在vs.net上提供帮助

在嵌入式DSP上,我会突破

(AlphaImageData[x,y]*OneMinusAlp
for (int i = 0; i < data.Length; i++) 
int size = ResultImageData.Length;
unsafe 
{
   fixed(byte* rp = ResultImageData, cp = CurrentImageData, ap = AlphaImageData) 
   {
      byte* r = rp;
      byte* c = cp;
      byte* a = ap;
      while (size > 0) 
      {
         *r = (byte)(*c * AlphaValue + *a * OneMinusAlphaValue);
         r++;
         c++;
         a++;
         size--;
      }
   }
}
int xSize = ResultImageData.GetLength(0);
int ySize = ResultImageData.GetLength(1);

for (int y = 0; y < ySize; y++) 
{
    for (int x = 0; x < xSize; x++)
    {
        ResultImageData[x, y] = (byte)((CurrentImageData[x, y] * AlphaValue) +
            (AlphaImageData[x, y] * OneMinusAlphaValue));
    }
}