Windows上的opencv imread()用于非ASCII文件名

时间:2014-07-15 23:07:10

标签: c++ qt winapi opencv unicode

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

就像我在OpenCV源代码中看到的那样,它甚至在Windows上使用fopen(而不是_wfopen),并且afaik fopen在Windows上不处理非ascii字符。从上面的问题我看到可能有一些使用QStrings的技巧,但如果它的工作原理是什么呢?它如何将unicode字符串转换为Windows'fopen()接受的字符数组?

P.S。我们不使用QT

提前致谢!

4 个答案:

答案 0 :(得分:10)

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

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

答案 1 :(得分:3)

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

答案 2 :(得分:2)

试试这个:

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;
}

答案 3 :(得分:1)

这是我使用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;