【问题标题】:Read a series of images row by row or entire image for performance?逐行或整个图像读取一系列图像以获得性能?
【发布时间】:2011-03-28 00:25:43
【问题描述】:

我正在编写一个应用程序,它对目标进行一系列曝光并计算它们的平均值并保存生成的图像。该技术广泛用于天文摄影,以减少最终图像中的噪点。基本上,计算像素的平均值并在输出文件中写出值。

曝光次数可能非常高,从 20 到 30(有时甚至更多),而且使用当今的大型 CCD 传感器,分辨率也可能非常高。所以数据量可能非常非常大。

我的问题是,在性能方面,我应该逐行读取图像(方法#1)还是应该读取所​​有数组的整个图像数组(方法#2)?使用前一种方法,我将不得不加载每个相应的行。所以,如果我有 10 张图像并且我正在读取第 1 行 - 我将不得不从每张图像中读取第一行,计算它们的平均值并写出该行。

使用后一种方法,我完整读取所有图像,计算并写出整个图像。

理论上,后一种方法应该更快,但更占用内存。然而,在实践中,我发现性能差异并不大,这令人费解。最多,方法#2 只比方法#1 快2 到3 秒。但是,方法 #2 使用高达 1.3 GB 的内存来存储 24 个 8 兆像素的图像。另一方面,方法 #1 最多使用 70MB。平均而言,这两种方法都需要大约 20 秒来处理 24 张 8 兆像素的图像。

我是用 Objective-C 编写的,在调用 CFITSIO 时加入了大量的 C。

这是方法#1:

pixelRows = (double**)malloc(self.numberOfImages * sizeof(double*)); //alloc. pixel array.
for(i=0;i<self.numberOfImages;i++)
{
    pixelRows[i] = (double*)malloc(width*sizeof(double));
}
apix = (double*)malloc(width*sizeof(double));
for(firstpix[1]=1;firstpix[1]<=size[1];firstpix[1]++)
{
    [self gatherRowsFromImages:firstpix[1] withRowWidth:theWidth thePixelMap:pixelRows];
    [self averageRows:pixelRows width:width theAveragedRow:apix];
    fits_write_pix(outfptr, TDOUBLE, firstpix, width,apix, &status);
    //NSLog(@"Row %ld written.",firstpix[1]);
}

fits_close_file(outfptr,&status);
NSLog(@"End");
if(!status)
{
    NSLog(@"File written successfully.");
}
for(i=0;i<self.numberOfImages;i++)
{
    free(pixelRows[i]);
}
free(pixelRows);
free(apix);

这是方法#2:

imageArray = (double**)malloc(files.count * sizeof(double*));
for(i=0;i<files.count;i++)
{
    imageArray[i] = (double*)malloc(size[0] * size[1] * sizeof(double));
    fits_read_pix(fptr[i],TDOUBLE,firstpix,size[0] * size[1],NULL,imageArray[i],NULL,&status);
    //NSLog(@"%d",status);
}
int fileIndex;

NSLog(@"%d",files.count);
apix = (double*)malloc(size[0] * size[1] * sizeof(double));
for(i=0;i<(size[0] * size[1]);i++)
{
    apix[i] = 0.0;
    for(fileIndex=0;fileIndex<files.count;fileIndex++)
    {
        apix[i] = apix[i] + imageArray[fileIndex][i];
    }
    //NSLog(@"%f",apix[i]);
    apix[i] = apix[i] / files.count;
}

fits_create_file(&outfptr,[outPath UTF8String],&status);
fits_copy_header(fptr[0],outfptr,&status);
fits_write_pix(outfptr, TDOUBLE, firstpix, size[0] * size[1],apix, &status);
fits_close_file(outfptr,&status);

对此有什么建议吗?我是否期望通过完整阅读每张图片来获得太多收益?

【问题讨论】:

  • 您好。我正在开发一个项目,我需要能够在objective-c 中使用cfitsio,并且在将库集成到Xcode 项目中时遇到了一些麻烦。你认为你可以帮助我吗,因为听起来你已经完成了我需要做的事情?顺便说一句,这是我通过 UCSB 做的一个开源项目。谢谢!我的电子邮件是 roxanne.brittain@gmail.com

标签: objective-c performance image


【解决方案1】:

我总是采用逐行方法,因为它是可扩展的。它也可能更快,因为内存占用更小,这意味着无需将任何程序换出到磁盘上,只为你的内存消耗工具。

此外,为了优化逐行方法,您还应该考虑每 8 行(或其他数字)读取图像。例如。 JPEG 存储在 8x8 块中,因此读取少于 8 行将毫无意义。当然,这取决于您使用的图像格式和库。

关于 cpu 使用缓存内存还有其他注意事项。经常使用的内存位置不必移动到“慢”内存,但可以更靠近 cpu。有几个级别的缓存,它们的大小因 CPU 类型而异。 (在撰写本文时,其中最大的通常为 8 或 16 mb)

要考虑的另一件事是执行实际平均的代码。调整这个也会收获很多,特别是对于你正在做的那种操作,看看 SSE 和相关主题。同样使用整数计算可能会击败浮点运算。使用移位进行除法也可能比真正的除法更快,但它只允许您除以 2^n。

【讨论】:

  • 非常感谢您的回复。我相信 CFITSIO 具有某种迭代器功能,可以自动从文件中读取最佳数量的块。我认为这应该会有所帮助。您能否详细说明什么是 SSE?是否可以在 OS X 和 C/Objective-C 上完成?
  • 但是,如果您有 20 个文件,您将在前 8 个图像行上循环 20*8 次,而您可以在每个图像中只通过一次。函数调用自己形成开销。如果你可以平均一个 X 字节块,它会比平均 N 行乘以 P 像素更快。
  • Google 是您的朋友。 SSE 是指英特尔 cpu 上的一组专用 cpu 指令。 AMD有自己的一套。它们通常可用于对大块内存进行操作。我想你可以使用一些库来利用它们的魔力。否则你需要使用内联汇编(你真的不想要)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-05
  • 1970-01-01
相关资源
最近更新 更多