gpt4 book ai didi

C++,OpenCV : Fastest way to read a file containing non-ASCII characters on windows

转载 作者:太空宇宙 更新时间:2023-11-03 23:16:11 25 4
gpt4 key购买 nike

我正在使用 OpenCV 编写一个程序,它可以在 Windows 和 Linux 上运行。现在 OpenCV 的问题是,它的 cv::imread 函数无法处理 Windows 上包含非 ASCII 字符的文件路径。解决方法是先使用其他库(例如 std-libraries 或 Qt)将文件读入缓冲区,然后使用 cv::imdecode 函数从该缓冲区读取文件。这就是我目前所做的。但是,它不是很快,而且比仅使用 cv::imread 慢得多。我有一个大约 1GB 大小的 TIF 图像。用 cv::imread 读取它大约需要。 1s,用buffer方式读取大概需要14s。我假设 imread 只是读取显示图像所需的 TIF 部分(无图层等)。要么是这个,要么是我将文件读入缓冲区的代码很糟糕。

现在我的问题是是否有更好的方法来做到这一点。要么是关于 OpenCV 的更好方法,要么是关于将文件读入缓冲区的更好方法。

我尝试了两种不同的缓冲方法,一种使用 std 库,另一种使用 Qt(实际上它们都使用 QT 来做某些事情)。它们都同样慢。:

方法一

std::shared_ptr<std::vector<char>> readFileIntoBuffer(QString const& path) {

#ifdef Q_OS_WIN
std::ifstream file(path.toStdWString(), std::iostream::binary);
#else
std::ifstream file(path.toStdString(), std::iostream::binary);
#endif
if (!file.good()) {
return std::shared_ptr<std::vector<char>>(new std::vector<char>());
}
file.exceptions(std::ifstream::badbit | std::ifstream::failbit | std::ifstream::eofbit);
file.seekg(0, std::ios::end);
std::streampos length(file.tellg());
std::shared_ptr<std::vector<char>> buffer(new std::vector<char>(static_cast<std::size_t>(length)));
if (static_cast<std::size_t>(length) == 0) {
return std::shared_ptr<std::vector<char>>(new std::vector<char>());
}
file.seekg(0, std::ios::beg);
try {
file.read(buffer->data(), static_cast<std::size_t>(length));
} catch (...) {
return std::shared_ptr<std::vector<char>>(new std::vector<char>());
}
file.close();
return buffer;
}

然后从缓冲区读取图像:

std::shared_ptr<std::vector<char>> buffer = utility::readFileIntoBuffer(path);
cv::Mat image = cv::imdecode(*buffer, cv::IMREAD_UNCHANGED);

方法二

QByteArray readFileIntoBuffer(QString const & path) {
QFile file(path);
if (!file.open(QIODevice::ReadOnly)) {
return QByteArray();
}
return file.readAll();
}

解码图像:

QByteArray buffer = utility::readFileIntoBuffer(path);
cv::Mat matBuffer(1, buffer.size(), CV_8U, buffer.data());
cv::Mat image = cv::imdecode(matBuffer, cv::IMREAD_UNCHANGED);

更新

方法三

此方法使用QFileDevice::map 将文件映射到内存,然后使用cv::imdecode

            QFile file(path);
file.open(QIODevice::ReadOnly);
unsigned char * fileContent = file.map(0, file.size(), QFileDevice::MapPrivateOption);
cv::Mat matBuffer(1, file.size(), CV_8U, fileContent);
cv::Mat image = cv::imdecode(matBuffer, cv::IMREAD_UNCHANGED);

但是,这种方法也没有导致比其他两种方法更短的时间。我也做了一些时间测量,发现读取内存中的文件或者映射到内存其实不是瓶颈。占用大部分时间的操作是 cv::imdecode。我不知道为什么会这样,因为对同一图像使用 cv::imread 只需要一小部分时间。

可能的解决方法

我尝试使用以下代码在 Windows 上为包含非 ASCII 字符的文件获取 8.3 路径名:

QString getShortPathname(QString const & path) {
#ifndef Q_OS_WIN
return QString();
#else
long length = 0;
WCHAR* buffer = nullptr;
length = GetShortPathNameW(path.toStdWString().c_str(), nullptr, 0);
if (length == 0) return QString();
buffer = new WCHAR[length];
length = GetShortPathNameW(path.toStdWString().c_str(), buffer, length);
if (length == 0) {
delete[] buffer;
return QString();
}
QString result = QString::fromWCharArray(buffer);
delete[] buffer;
return result;
#endif
}

但是,我不得不发现 8.3 路径名生成在我的机器上被禁用,所以它可能在其他机器上也是如此。所以我还不能测试这个,它似乎没有提供可靠的解决方法。我还有一个问题,该函数没有告诉我 8.3 路径名生成已禁用。

最佳答案

OpenCV GitHub 中有关于此的公开票证:https://github.com/opencv/opencv/issues/4292

其中一条评论提出了一种解决方法,无需使用内存映射文件(在 Boost 的帮助下)将整个文件读入内存:

mapped_file map(path(L"filename"), ios::in);
Mat file(1, numeric_cast<int>(map.size()), CV_8S, const_cast<char*>(map.const_data()), CV_AUTOSTEP);
Mat image(imdecode(file, 1));

关于C++,OpenCV : Fastest way to read a file containing non-ASCII characters on windows,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39356362/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com