C++开发,使用openCV API对图片进行压缩

我们这里利用openCV对图片的尺寸和质量进行压缩,来达到图片大小的压缩

下面来介绍一下,改变尺寸和质量的相关API

图像缩放

进行图像缩放的API为cv::resize

复制代码
CV_EXPORTS_W void resize(InputArray src, OutputArray dst, Size dsize, double fx, double fy, int interpolation);
// src     需要进行缩放的图像数据,通常类型为cv::Mat
// dst     输出图像,通常类型为cv::Mat
// dsize   目标图像的尺寸,cv::Size类型的变量,通常为(width, height)可以设置为0
// fx      水平方向缩放因子,也就是宽的缩放,可以为0,0则表示不进行缩放
// fy      垂直方向缩放因子,也就是高的缩放,可以为0,0则表示不进行缩放
// interpolation 插值方法 默认为INTER_LINEAR
// 			cv::INTER_NEAREST    最近邻插值,速度最快,但质量最差
// 			cv::INTER_LINEAR     线性插值,速度较快,质量较好
// 			cv::INTER_AREA       区域插值,适用于图像缩小,速度较慢,质量最好
// 			cv::INTER_CUBIC      三次样条插值,速度适中,质量较好
//			cv::INTER_LANCZOS4   Lanczos插值,速度适中,质量较好

通过上面的参数我们可以得知,可以利用两种方式来对图像进行缩放,第一种就是通过dsize这个参数指定目标图像的大小来进行缩放,第二种就是设置宽高的缩放因子对图像进行缩放,这两种方式互不影响,使用一种将另一种设置为0即可

图像质量

改变图像质量的API为cv::imencode

复制代码
CV_EXPORTS_W bool imencode(const String& ext, InputArray img, CV_OUT std::vector<uchar>& buf, const std::vector<int>& params);
// ext    指定要使用的图像格式的文件扩展名
// img    输入的图像,通常为cv::Mat类型
// buf    输出的字节流,即编码后图像数据的存储变量
// params 可选参数用来设置编码选项,图像质量等

示例代码

通过之前讲过的Windows截图和今天说的图像压缩的API,我们来实现一个示例,就是对屏幕进行截图然后使用opencv进行图像压缩处理(尺寸缩小一半,质量降低一半),然后进行压缩前和压缩后的图像比较

代码:

复制代码
int main(std::string& imageData, cv::Rect& recv) {
    /// 利用CImage类实现屏幕截图
    HDC hDC = GetDC(NULL);
    // 在创建时,创建指定尺寸的Image
    CImage image;
    if (image.Create(
        recv.width,
        recv.height,
        GetDeviceCaps(hDC, BITSPIXEL)) == FALSE)
    {
        TRACE("图片创建失败");
        return -1;
    }
    // 复制指定区域的屏幕,到Image中
    if (BitBlt(
        image.GetDC(),
        0, 0,
        image.GetWidth(), image.GetHeight(),
        hDC, 0, 0,
        SRCCOPY) == FALSE)
    {
        TRACE("图片复制失败");
        image.ReleaseDC();
        return -2;
    }
    ReleaseDC(WindowFromDC(hDC), hDC);
    // 创建图片数据的缓冲区
    HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, 0);
    if (hMem == NULL) {
        image.ReleaseDC();
        return -3;
    }
    IStream* pStream = NULL;
    HRESULT ret = CreateStreamOnHGlobal( // 缓冲区与输入流绑定
        hMem,
        TRUE,
        &pStream);
    if (ret != S_OK) {
        TRACE("内存绑定创建失败");
        GlobalFree(hMem);
        image.ReleaseDC();
        return -4;
    }
    // 保存图片到流中
    image.Save(pStream, Gdiplus::ImageFormatJPEG);
    image.ReleaseDC();
    LARGE_INTEGER bg = {};
    pStream->Seek(bg, STREAM_SEEK_SET, NULL); // 流指针移到开头
    PBYTE pData = (PBYTE)GlobalLock(hMem);    // 将数据锁定提取
    if (pData == NULL) {
        pStream->Release();
        GlobalFree(hMem);
        TRACE("数据大小为0\r\n");
        return -5;
    }
    SIZE_T nSize = GlobalSize(hMem);      // 获取数据大小
    do {
        std::string data(nSize, '\0');
        memcpy((char*)data.c_str(), pData, nSize);
        GlobalUnlock(hMem);
        pStream->Release();
        GlobalFree(hMem);
#if 1
        FILE* pFile = fopen("./original.jpg", "wb+");
        if (pFile == NULL) {
            TRACE(_T("文件创建失败\r\n"));
            return -1;
        }
        fwrite(data.c_str(), 1, data.size(), pFile);
        fclose(pFile);
#endif
        //*** 进行图片质量压缩 ***
        // cv::imread() 该函数可以从磁盘中读取一张图片
        cv::_InputArray src_arr((char*)data.c_str(), (int)data.size());
        cv::Mat src_mat = cv::imdecode(src_arr, cv::IMREAD_COLOR);
        {
            std::string str;
            data.swap(str);
        }
        if (src_mat.data == NULL) {
            // 图片加载失败
            TRACE("图片加载失败");
            break;
        }
        cv::Mat amplify1;
        cv::resize(src_mat, amplify1, cv::Size(), 0.5, 0.5, cv::INTER_AREA);
        std::vector<uchar> pic_buff; // 保存图片的缓冲区
        // 图片质量压缩
        // IMWRITE_JPEG_QUALITY   jpg   IMWRITE_WEBP_QUALITY  webp
        std::vector<int> compression_params = { cv::IMWRITE_JPEG_QUALITY/*图片类型参数*/ ,50/*图片质量参数*/ };  // 图片处理参数
        bool ret = cv::imencode(".jpg", amplify1, pic_buff, compression_params);
        if (ret == false) {
            pic_buff.clear();
            break;
        }
        imageData.resize(pic_buff.size());
        memcpy((char*)imageData.c_str(), pic_buff.data(), imageData.size());
#if 1
        FILE* pFile = fopen("./dispose.jpg", "wb+");
        if (pFile == NULL) {
            TRACE(_T("文件创建失败\r\n"));
            return -1;
        }
        fwrite(imageData.c_str(), 1, imageData.size(), pFile);
        fclose(pFile);
#endif
        cv::destroyAllWindows();
    } while (false);
    return 0;
}

可以看到处理后比处理前图片大小减小了75%,在网络传输中将大大减少带宽的消耗

到这里,使用openCV对图像进行压缩就介绍完了

感谢观看学习,大佬们多多指点,愿明天的自己会感谢当下的努力!!!!

相关推荐
大鹏的NLP博客15 分钟前
ONNX Runtime CUDA 推理优化实战:破解 C++ 比 Python 慢 28 倍的假象
c++·onnx·推理优化
z落落15 分钟前
C# WinForm NModbus 串口通信+WinForm Modbus4 串口通信
开发语言·单片机·c#
Mojitocean18 分钟前
Win开发环境配置(持续更新)
开发语言·python
CoderIsArt39 分钟前
C#环境中部署MQTT客户端
开发语言·c#
HugoStudio_SWAN1 小时前
【按键反馈】C++ 实现键盘烟花秀
开发语言·c++·学习·程序人生
间歇性努力持续性发呆的野生快乐选手1 小时前
二分模板(整型,浮点型)
数据结构·c++·算法
艾莉丝努力练剑1 小时前
【AI大模型接入SDK】DeepSeek API 基础概述
c++·人工智能·学习·ai·面试·deepseek
AI 编程助手GPT1 小时前
Bun 1.4 正式发布:从 Zig 改写为 Rust,内置浏览器、图片处理和并行测试
开发语言·人工智能·后端·ai·chatgpt
paopaokaka_luck1 小时前
基于springboot3+vue3的飞行器模型实验室预约管理系统(协同过滤算法、Echarts图形化分析)
开发语言·推荐算法