问题
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:
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;
}
回答4:
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;
来源:https://stackoverflow.com/questions/24769623/opencv-imread-on-windows-for-non-ascii-file-names