【问题标题】:opencv imread() on Windows for non-ASCII file namesWindows 上的 opencv imread() 用于非 ASCII 文件名
【发布时间】:2014-09-06 07:44:45
【问题描述】:

我们有一个 OpenCV 问题,即在 Windows 上打开(和写入)包含非 Ascii 字符的文件路径。 我看到了问题OpenCV imread with foreign charactersimread(openCV),QString unicodes,但仍然不明白解决问题的正确方法。

据我在 OpenCV 源代码中看到的,它甚至在 Windows 上也使用 fopen(而不是 _wfopen),并且 afaik fopen 不处理 Windows 上的非 ascii 字符。从上面的问题中,我看到使用 QStrings 可能会有一些技巧,但如果它有效,它究竟做了什么?它如何将 unicode 字符串转换为 Windows 的 fopen() 将接受的字符数组?

附:我们不使用 QT

提前致谢!

【问题讨论】:

    标签: c++ qt winapi opencv unicode


    【解决方案1】:

    Microsoft 在 Visual Studio 中的 fopen() 版本支持非标准的 css 模式标志,用于启用 Unicode 数据的读/写,但它不支持 Unicode 文件名。为此,您必须使用 _wfopen(),因此您必须调整 OpenCV 的源代码,以便可以传入 Unicode 文件名并使用 _wfopen() 而不是 fopen() 打开它。

    【讨论】:

      【解决方案2】:

      在不破解 OpenCV 源代码的情况下执行此操作的方法是使用_wfopen(如 Remy 建议的那样)将整个文件读入内存缓冲区。然后使用 OpenCV 的函数 imdecode 从该缓冲区创建一个 cv::Mat

      如果需要,您也可以反过来做 - 即使用 imencode 将图像写入内存缓冲区,然后使用 _wfopen 打开具有 UNICODE 名称的文件并将缓冲区写入它(或者,您可以只是 imwrite 到一个临时文件,然后使用适当的 API 函数移动/重命名它)。

      【讨论】:

      • 谢谢!我可以确认这个解决方案对我们有用
      • 我有同样的问题,我想试试你的解决方案。我可以使用wfopen 在我的文件中获得FILE*,但是我不知道如何正确使用imdecode 从中获得cv::Mat。除此之外:OpenCV 是否仍然不支持本地非 ASCII 文件名,也在 3.0 版中? PS:如果我确实使用 Qt(我的意思是不阅读 QImages 并在之后转换),是否有一种更简单但仍然有效的方法?
      【解决方案3】:

      这是我使用std::ifstream的解决方案:

      std::ifstream file(path.toStdWString(), std::iostream::binary);
      if (!file.good()) {
          return cv::Mat();
      }
      file.exceptions(std::ifstream::badbit | std::ifstream::failbit | std::ifstream::eofbit);
      file.seekg(0, std::ios::end);
      std::streampos length(file.tellg());
      std::vector<char> buffer(static_cast<std::size_t>(length));
      if (static_cast<std::size_t>(length) == 0) {
          return cv::Mat();
      }
      file.seekg(0, std::ios::beg);
      try {
          file.read(buffer.data(), static_cast<std::size_t>(length));
      } catch (...) {
          return cv::Mat();
      }
      file.close();
      cv::Mat image = cv::imdecode(buffer, CV_LOAD_IMAGE_COLOR);
      return image;
      

      或者使用 Qt 更短一点:

      QFile file(path);
      std::vector<char> buffer;
      buffer.resize(file.size());
      if (!file.open(QIODevice::ReadOnly)) {
          return cv::Mat();
      }
      file.read(buffer.data(), file.size());
      file.close();
      cv::Mat image = cv::imdecode(buffer, CV_LOAD_IMAGE_COLOR);
      return image;
      

      【讨论】:

        【解决方案4】:

        试试这个:

        cv::Mat ReadImage(const wchar_t* filename)
        {
            FILE* fp = _wfopen(filename, L"rb");
            if (!fp)
            {
                return Mat::zeros(1, 1, CV_8U);
            }
            fseek(fp, 0, SEEK_END);
            long sz = ftell(fp);
            char* buf = new char[sz];
            fseek(fp, 0, SEEK_SET);
            long n = fread(buf, 1, sz, fp);
            _InputArray arr(buf, sz);
            Mat img = imdecode(arr, CV_LOAD_IMAGE_COLOR);
            delete[] buf;
            fclose(fp);
            return img;
        }
        

        【讨论】:

          猜你喜欢
          • 2018-04-12
          • 2020-10-03
          • 1970-01-01
          • 2018-07-13
          • 1970-01-01
          • 1970-01-01
          • 2023-03-28
          • 2012-11-09
          • 2016-10-11
          相关资源
          最近更新 更多