解决OpenCV的imread/imwrite在Qt环境不支持中文路径的问题

64 篇文章 131 订阅

如果为了节省时间,你可以直接跳到第三节看结论,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函数,请参见我的另一篇博文: 

https://blog.csdn.net/libaineu2004/article/details/115721170

解决办法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();
}

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值