可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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(openCV),QString unicodes but still didn't understand a proper way of solving the problem.
As far I as I saw in the OpenCV source code, it uses fopen even on Windows (instead of _wfopen) and afaik fopen does not handle non-ascii characters on Windows. From the questions above I saw that there could be some trick using QStrings, but if it works what does it exactly do? How does it transform a unicode string to a character array that will be accepted by Windows' fopen()?
P.S. We don't use QT
Thanks in advance!
回答1:
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).
回答2:
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()
.
回答3:
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 buffer(static_cast<:size_t>(length)); if (static_cast<:size_t>(length) == 0) { return cv::Mat(); } file.seekg(0, std::ios::beg); try { file.read(buffer.data(), static_cast<: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 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:
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; }