0

我需要使用 CImg 库计算图像的平均值,如下所示:

int i = 0;
float mean = 0;
CImg<float> img("image.cimg");  
float *ptr = img.data(); //retrieves pointer to the first value
while(i<img.width()*img.height()*img.spectrum()){
    mean += *(ptr+i);
    ++i;
}
std::cout << "mean: " << mean/i << std::endl;

我知道这样img.mean()可以解决问题,但是在这里我想以低级别的方式进行。

当图像的大小增加太多时,我的代码中的第 3 行会消耗我计算机的太多资源,因为根据文档,它同时将所有图像像素存储在内存缓冲区中。

我想到了一个更低级别的解决方案,使用系统调用open()read()如下所示:

int i = 0;
int k = WIDTH*HEIGHT*SPECTRUM; //assuming this values are known
float mean = 0, aux;
int fd = open("image.cimg", O_RDONLY);
while(i<k){ 
    read(fd, &aux, sizeof(float));
    mean += aux; 
    ++i;
}
close(fd);
std::cout << "mean: " << mean/i << std::endl;

但是现在得到的结果没有任何意义。我想知道这个解决方案是否有任何意义,如果图像以与在内存中加载时相同的方式存储在磁盘上,以及最终这个解决方案是否会节省时间和内存。

4

1 回答 1

1

问题出在代码的第二行,因为您已经mean(尽管命名更好sum)一个简单的float. 由于图像中的每个像素也是 a float,如果您的图像是 10,000x10,000 ,您将遇到问题,因为您将尝试将 100Mfloat的总和存储在 a 中float

最简单的解决方案是将第 2 行更改为:

double mean=0;

作为替代方案,您可以逐步计算平均值,而不会像这样溢出:

float mean = 0;
int i = 1;
while(...){
  mean+= (x - mean)/i;
  ++i;
}

顺便说一句,如果你有非常大的图像,我可以推荐vips一下,它非常快速且非常高效,例如,如果我创建一个 10,000x10,000 像素的 TIF 并要求vips从命令行对其进行平均:

time vips avg image.tif --vips-leak
0.499994

memory: high-water mark 7.33 MB

real    0m0.384s
user    0m0.492s
sys     0m0.233s

您可以看到它需要 0.4 秒,并在 7MB 内存使用时达到峰值。

于 2016-09-30T10:18:53.160 回答