如果为了节省时间,你可以直接跳到第三节看结论,O(∩_∩)O
一、先来看imread
默认写法是:
QString m_strPathNameImageOrg;
cv::Mat Image1 = cv::imread(m_strPathNameImageOrg.toStdString().c_str());
但是这样写是不支持中文路径的。
解决办法1,需要满足以下3个条件
(1)源码修改为:
cv::Mat Image1 = cv::imread(m_strPathNameImageOrg.toLocal8Bit().toStdString());
(2)源文件添加:
#pragma execution_character_set("utf-8")
(3)main函数的入口,去掉字符集"utf-8"
//QTextCodec *codec = QTextCodec::codecForName("utf-8");
//QTextCodec::setCodecForLocale(codec);
解决办法2,使用QImage读图片,然后再转换为cv::Mat
QImage image(m_strPathNameImageOrg); //用QImage读取带中文路径图片
image = image.convertToFormat(QImage::Format_RGB888); //将img转换成需要的类型
cv::Mat Image1 = UTIL->QImage2cvMat(image);
其中QImage2cvMat函数,请参见我的另一篇博文:
解决办法3,使用cv::imdecode【推荐】
#include <opencv2/imgcodecs/legacy/constants_c.h>
cv::Mat Image1;
QFile file(m_strPathNameImageOrg);
if (file.open(QIODevice::ReadOnly))
{
QByteArray byteArray = file.readAll();
std::vector<char> data(byteArray.data(), byteArray.data() + byteArray.size());
Image1 = cv::imdecode(cv::Mat(data), CV_LOAD_IMAGE_COLOR); //等同于cv::IMREAD_COLOR,Return a 3-channel color image
file.close();
}
二、再来看imwrite
默认的写法是:
vector<int> compression_params;
compression_params.push_back(cv::IMWRITE_JPEG_QUALITY); //选择jpeg
compression_params.push_back(100); //在这个填入你要的图片质量,默认值是95,100代表满分
std::string path;
cv::imwrite(path, Image1, compression_params); //根据路径,保存为jpg格式
但是这样写是不支持中文路径的。
解决办法,使用cv::imencode:
vector<int> compression_params;
compression_params.push_back(cv::IMWRITE_JPEG_QUALITY); //选择jpeg
compression_params.push_back(100); //在这个填入你要的图片质量,默认值是95,100代表满分
std::vector<unsigned char> buf;
cv::imencode(".jpg", Image1, buf, compression_params); //把Image1的内容写入缓存buf
QFile file2("d:/入学/测试一.jpg");
if (file2.open(QIODevice::WriteOnly))
{
file2.write((char *)&buf[0], buf.size()); //保存buf到文件
file2.close();
}
或者是:
#include <fstream>
char *wcharToChar(const wchar_t *wstr)
{
if (!wstr || wstr == NULL)
{
return NULL;
}
unsigned int len = WideCharToMultiByte(CP_ACP, 0, wstr, wcslen(wstr) + 1, NULL, 0, NULL, NULL);
char *cchar = new char[len];
memset(cchar, 0, len);
WideCharToMultiByte(CP_ACP, 0, wstr, wcslen(wstr) + 1, cchar, len, NULL, NULL);
return cchar;
}
wchar_t *charToWchar(const char *str)
{
if (!str || str == NULL)
{
return NULL;
}
unsigned int len = MultiByteToWideChar(CP_ACP, 0, str, strlen(str) + 1, NULL, 0);
wchar_t *tchar = new wchar_t[len + 1];
memset(tchar, '\0', len + 1);
MultiByteToWideChar(CP_ACP, 0, str, strlen(str) + 1, &tchar[0], len);
return &tchar[0];
}
void save(const cv::Mat &img1, const std::wstring &path)
{
cv::Mat img2 = img1;
CUtil utl;
char *p = utl.wcharToChar(path.c_str());
std::string str = p;
//根据扩展名来决定储存jpg还是bmp
if (str.find("jpg") != path.npos) //找到了jpg,一个特别的标志c++中用npos表示
{
#if 1 //可以保存中文路径
std::vector<int> compression_params;
compression_params.push_back(cv::IMWRITE_JPEG_QUALITY); //选择jpeg
compression_params.push_back(100); //在这个填入你要的图片质量,默认值是95,100代表满分
cv::imwrite(p, img2, compression_params); //根据路径,保存为jpg格式
#else //也可以保存中文路径
std::vector<int> compression_params;
compression_params.push_back(cv::IMWRITE_JPEG_QUALITY); //选择jpeg
compression_params.push_back(100); //在这个填入你要的图片质量,默认值是95,100代表满分
std::vector<unsigned char> buf;
cv::imencode(".jpg", img2, buf, compression_params); //把Image的内容写入缓存buf
ofstream ofp(p, ios_base::binary);
ofp.write((const char *)&buf[0], buf.size());
ofp.close();
#endif
delete []p;
}
三、个人总结的读写函数,推荐使用
cv::Mat CUtil::readMat(const QString &pathname, int flags) //支持中文路径读
{
cv::Mat image;
QFile file(pathname);
if (file.open(QIODevice::ReadOnly))
{
QByteArray byteArray = file.readAll();
std::vector<char> data(byteArray.data(), byteArray.data() + byteArray.size());
image = cv::imdecode(cv::Mat(data), flags);
//flags==CV_LOAD_IMAGE_COLOR等同于cv::IMREAD_COLOR,Return a 3-channel color image
//CV_LOAD_IMAGE_COLOR依赖头文件,#include <opencv2/imgcodecs/legacy/constants_c.h>
file.close();
}
return image;
}
void CUtil::writeMat(const QString &pathname, const cv::Mat &image) //支持中文路径写
{
QString abs_path, base_name, file_name, file_suffix;
splitPath(pathname, abs_path, base_name, file_name, file_suffix);
if (file_suffix == "PNG")
{
writeMatPng(pathname, image);
}
else if (file_suffix == "JPG")
{
writeMatJpg(pathname, image);
}
else if (file_suffix == "BMP")
{
writeMatBmp(pathname, image);
}
else
{
return; //输出的文件扩展名不支持
}
}
void CUtil::writeMatPng(const QString &pathname, const cv::Mat &image)
{
std::vector<int> compression_params;
compression_params.push_back(cv::IMWRITE_PNG_COMPRESSION); //选择png
compression_params.push_back(2); //在这个填入你要的图片质量,默认值是3,取值范围[0,9],数字越大,文件越小
std::vector<unsigned char> buf;
cv::imencode(".png", image, buf, compression_params); //把Image的内容写入缓存buf
QFile file(pathname);
if (file.open(QIODevice::WriteOnly))
{
file.write((char *)&buf[0], buf.size()); //保存buf到文件
file.close();
}
}
void CUtil::writeMatJpg(const QString &pathname, const cv::Mat &image)
{
std::vector<int> compression_params;
compression_params.push_back(cv::IMWRITE_JPEG_QUALITY); //选择jpeg
compression_params.push_back(95); //在这个填入你要的图片质量,默认值是95,100代表满分,数字越大,文件越大
std::vector<unsigned char> buf;
cv::imencode(".jpg", image, buf, compression_params); //把Image的内容写入缓存buf
QFile file(pathname);
if (file.open(QIODevice::WriteOnly))
{
file.write((char *)&buf[0], buf.size()); //保存buf到文件
file.close();
}
}
void CUtil::writeMatBmp(const QString &pathname, const cv::Mat &image)
{
std::vector<unsigned char> buf;
cv::imencode(".bmp", image, buf); //把Image的内容写入缓存buf
QFile file(pathname);
if (file.open(QIODevice::WriteOnly))
{
file.write((char *)&buf[0], buf.size()); //保存buf到文件
file.close();
}
}
void CUtil::splitPath(const QString &pathname, QString &abs_path, QString &base_name, QString &file_name, QString &file_suffix)
{
QFileInfo file_info = QFileInfo(pathname);
//绝对路径(不含文件名和扩展名)
abs_path = file_info.absolutePath();
//文件名(不含扩展名,文件名遇到小数点会截断)
base_name = file_info.baseName();
//文件名(不含扩展名,文件名不怕遇到小数点)
base_name = file_info.completeBaseName();
//文件名(含扩展名)
file_name = file_info.fileName();
//文件后缀(扩展名)
file_suffix = file_info.suffix();
file_suffix = file_suffix.toUpper();
}