【问题标题】:C++ fast way to save image from array of valuesC ++快速方法从值数组中保存图像
【发布时间】:2017-06-12 14:34:48
【问题描述】:

现在,我正在使用 CImg。 由于this 问题,我无法使用 OpenCV。

我的 CImg 代码如下所示:

cimg_library::CImg<float> img(512,512); 
cimg_forXYC(img,x,y,c) { img(x,y,c) = (array[x][y]); } //array contains all float values between 0/1
img.save(save.c_str()); //taking a  lot of time

通过使用时钟,我能够确定第一步,for 循环需要 0-0.01 秒。但是,第二步,保存图片,需要 0.06 秒,由于我的图片数量太长了。

我保存为位图。 有没有更快的方法在 C++ 中完成相同的事情(从值数组创建图像并保存)?

【问题讨论】:

  • save.c_str() save 是什么?
  • @tobi303 它是一个字符串,该值大约为 110 个字符,具体取决于图像。它是 /home/user/folder/longname。
  • 保存时文件是什么格式的?你想要什么格式?你的数组里有什么?为什么float
  • @Omnifarious 文件路径以 .bmp 结尾。只要图像显示良好并且位图效果最佳,我并不真正关心格式。在我的数组中有一堆介于 0 和 1 之间的浮点值。我选择了浮点数,因为这就是我使用的教程所使用的。有更好的选择吗?感谢您的回复!
  • 你的图片格式是什么?什么是像素深度?每个元素都是一个像素吗?你的图片可以有小数像素吗?

标签: c++ opencv image-processing bitmap cimg


【解决方案1】:

这是一个小功能,可以将您的图像保存在pgm format 中,大多数东西都可以读取并且非常简单。它要求您的编译器支持 C++11,大多数情况下都支持。它还被硬编码为 512x512 图像。

#include <fstream>
#include <string>
#include <cmath>
#include <cstdint>

void save_image(const ::std::string &name, float img_vals[][512])
{
   using ::std::string;
   using ::std::ios;
   using ::std::ofstream;
   typedef unsigned char pixval_t;
   auto float_to_pixval = [](float img_val) -> pixval_t {
      int tmpval = static_cast<int>(::std::floor(256 * img_val));
      if (tmpval < 0) {
         return 0u;
      } else if (tmpval > 255) {
         return 255u;
      } else {
         return tmpval & 0xffu;
      }
   };
   auto as_pgm = [](const string &name) -> string {
      if (! ((name.length() >= 4)
             && (name.substr(name.length() - 4, 4) == ".pgm")))
      {
         return name + ".pgm";
      } else {
         return name;
      }
   };

   ofstream out(as_pgm(name), ios::binary | ios::out | ios::trunc);

   out << "P5\n512 512\n255\n";
   for (int x = 0; x < 512; ++x) {
      for (int y = 0; y < 512; ++y) {
         const pixval_t pixval = float_to_pixval(img_vals[x][y]);
         const char outpv = static_cast<const char>(pixval);
         out.write(&outpv, 1);
      }
   }
}

【讨论】:

  • 感谢您的回答!我在 auto float_to_pixval 行上收到错误 error: ISO C++ forbids declaration of ‘float_to_pixval’ with no type。这是您在代码上面提到的编译器问题吗?
  • @user8149522 - 我不知道您使用的是什么编译器,但请尝试将 -std=c++11 添加到编译器的命令行或执行任何您需要打开 C++ 的操作11 支持。此代码需要 C++11。是的,这就是我上面提到的问题。它可以重写为不需要 C++11……那会很痛苦,而且看起来也不那么好。
  • 抱歉,我知道这不是原始问题的一部分,但您是否知道我可以采用 pgm 并获取一组值的方法?换句话说,输出到输入?我可以将其作为一个单独的问题发布,我只是认为没有必要这样做。
【解决方案2】:

与@Omnifarious 的回答类似,您的浮点数据有一种极其简单的格式(也基于 NetPBM 概念)。它被称为PFM,并记录在here

好处是 CImgImageMagick 都能够读取和写入格式,无需任何额外的库,也无需您编写任何代码!另一个好处是您可以保留浮动的全部音调范围,而不仅仅是 256 步。不利的一面是,您确实需要每个像素完整的 4 个字节而不是 1 个字节。

因此,您的代码将变为:

CImg<float> img(512,512); 
cimg_forXYC(img,x,y,c) { img(x,y,c) = (array[x][y]); }
img.save_pfm("filename.pfm");

我通过创建 10,000 张图像并使用以下代码将它们保存到磁盘来对此进行基准测试:

#include <iostream>
#include <cstdlib>
#define cimg_display 0        // No need for X11 stuff
#include "CImg.h"

using namespace cimg_library;
using namespace std;

#define W   512
#define H   512
#define N   10000

int main() {
    // Create and initialise float image with radial gradient
   cimg_library::CImg<float> img(W,H); 
   cimg_forXY(img,x,y) {img(x,y) = hypot((float)(W/2-x),(float)(H/2-y)); }

   char filename[128];
   for(int i=0;i<N;i++){
      sprintf(filename,"f-%06d.pfm",i);
      img.save_pfm(filename);
   }
}

它在 21.8 秒内运行,这意味着每张图像 2.1 毫秒 (0.002 秒)。

正如我之前提到的,ImageMagick 也能够处理PFM 格式,因此您可以使用 GNU ParallelImageMagick @ 987654328@ 将这些图像转换为JPEG

parallel -X mogrify -format jpg -auto-level ::: *pfm

对于原始的 10,000 张图像,这需要 22 秒,即 2.2 毫秒/张图像。

【讨论】:

  • 感谢您的回答!它看起来很有希望,但是在运行之后,生成的 JPG 只是纯白色 :( 如果它有所作为,我无法使用 parallel 所以没有使用它。
  • 你需要使用-auto-level选项...convert input.pfm -auto-level output.jpg
  • 不,我使用了你的确切代码,在你得到径向渐变的地方,我得到了一张纯白色的图像:(
  • 你没看错,是Q16!有没有办法通过它来实现这一点?
  • 如果你想处理浮动,你必须有 Q32 - 没有办法。不确定您的平台/操作系统,但在大多数平台上构建 Q32 版本很容易。
猜你喜欢
  • 1970-01-01
  • 2020-12-04
  • 2011-08-02
  • 2013-08-10
  • 1970-01-01
  • 2016-10-07
  • 1970-01-01
  • 2018-09-23
  • 2023-03-12
相关资源
最近更新 更多