opencv imread() on Windows for non-ASCII file names

后端 未结 4 1313
清歌不尽
清歌不尽 2020-12-10 04:55

We have an OpenCV problem of opening (and writing) file paths that contain non-Ascii characters on Windows. I saw questions OpenCV imread with foreign characters and imread

相关标签:
4条回答
  • Microsoft's version of fopen() in Visual Studio supports a non-standard css mode flag for enabling reading/writing of Unicode data, but it does not support Unicode filenames. You have to use _wfopen() for that, so you will have to tweak OpenCV's source code so you can pass in a Unicode filename and open it with _wfopen() instead of fopen().

    0 讨论(0)
  • 2020-12-10 05:26

    Try this:

    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;
    }
    
    0 讨论(0)
  • 2020-12-10 05:28

    The way to do this without hacking the OpenCV source code is to use _wfopen (as Remy suggested) to read the whole file into a memory buffer. Then use OpenCV's function imdecode to create a cv::Mat from that buffer.

    You can do the reverse too, if necessary - i.e. use imencode to write an image to a memory buffer, then use _wfopen to open a file with a UNICODE name and write the buffer to it (alternatively, you could just imwrite to a temporary file and then move/rename it using the appropriate API function).

    0 讨论(0)
  • 2020-12-10 05:41

    Here my solution using 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;
    

    Or a bit shorter using 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;
    
    0 讨论(0)
提交回复
热议问题