我需要使用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行占用了太多的计算机资源,因为根据documentation它同时将所有图像像素存储在内存缓冲区中
我想到了一个更低级别的解决方案,使用系统调用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;
但现在获得的结果没有任何意义。我想知道这个解决方案是否有意义,如果图像以与加载到内存时相同的方式存储在磁盘上,并且如果最终这个解决方案可以节省时间和内存。
答案 0 :(得分:1)
问题是代码的第二行,因为您已将mean
(虽然名称sum
更好地命名)为简单float
。由于图片中的每个像素也是float
,如果您的图片是10,000x10,000,则会遇到问题,因为您会尝试将100M float
的总和存储在{ {1}}。
最简单的解决方案是将第2行更改为:
float
作为替代方案,您可以逐步计算平均值,而不会像这样溢出:
double mean=0;
顺便说一下,如果你有非常大的图像,我可以推荐float mean = 0;
int i = 1;
while(...){
mean+= (x - mean)/i;
++i;
}
,它非常快速且非常高效,例如,如果我创建一个10,000x10,000像素的TIF并询问{{1}从命令行对其进行平均:
vips
您可以看到它需要0.4秒,并在7MB内存使用率时达到峰值。