• 【OpenCV】生成透明的PNG图像


    本文从三个方面讲解如何使用opencv的cv::imwrite()函数生成透明/不透明的PNG图像:

    1. PNG图像简单介绍

    2. cv::imwrite()函数介绍

    3. 示例代码

    1. PNG图像简单介绍

    PNG是20世纪90年代开发的一种取代GIF和TIFF的图像文件存储格式,适用于网络传播的轻便图片文件格式。

    • PNG图像具有流式读写性,允许连续读出和写入图像数据,因此适用于网络传播。
    • PNG图像可以逐次逼近显示,这种特性可以使在通信链路上传输图像文件的同时就在终端上显示图像,把整个轮廓显示出来之后逐步显示图像的细节。
    • PNG图像可以是透明的,可以使图像中某些部分不显示出来,用来创建一些特色的图像。
    • PNG图像独立于计算机软硬件环境,使用无损压缩,可以在一个文件中存储多幅图像。

    上面这么多特性,本文中使用到的是PNG的透明性。

    PNG的文件结构

    PNG图像格式由文件署名和数据块组成。

    PNG文件署名有8字节,用来识别PNG格式,所有的PNG图片文件内容开头都有文件署名。这8个字节的分别是:89H 50H 4EH 47H 0DH 0AH 1AH 0AH

    • 89H:用于检测传输系统是否支持8位的字符编码,用以减少将文本文件被错误的识别成PNG文件的机会;
    • 50H 4EH 47H:PNG每个字母对应的ASCII,识别出是PNG文件;
    • 0DH 0AH:DOS风格的换行符,用于DOS-Unix数据的换行符转换;
    • 1AH:在DOS命令行下,用于阻止文件显示的文件结束符;
    • 0AH:Unix风格的换行符,用于Unix-DOS换行符的转换;

    利用文件头标志判断文件类型 (mythsman.com)列举了更多文件格式的文件头标志。

    PNG数据块定义了两种类型的数据块,一种是称为关键数据块,是必需的数据块,另一种叫做辅助数据块,是可选的数据块。每个数据块都包含长度、数据块类型、数据块数据、循环冗余检测四个部分。

    更详细的信息参考:PNG文件格式详解 - maxiongying - 博客园 (cnblogs.com)

    2. cv::imwrite()函数介绍

    cv::imwrite()函数是Opencv提供的保存图片的函数,函数原型:

    1. bool cv::imwrite(
    2. const string& filename,
    3. cv::InputArray image,
    4. const vector<int>& params =vector<int>());

    参数params是表示为特定格式保存的参数编码,是STL vector类型,具体内容为:一系列的参数ID以及与该参数对应的参数值。对于本文,保存PNG格式,那么参数params可以这样定义:

    1. vector<int> compression_params;
    2. compression_params.push_back(CV_IMWRITE_PNG_COMPRESSION);
    3. compression_params.push_back(9);

    CV_IMWRITE_PNG_COMPRESSION表示压缩PNG;9表示压缩的强度,值越大意味着更多的压缩,范围是0~9,默认是3。

    3.  示例代码

    1. #include
    2. #include
    3. using namespace std;
    4. using namespace cv;
    5. int main()
    6. {
    7. // 创建带有alpha(透明)通道的Mat
    8. cv::Mat pngAlphaMat(480, 640, CV_8UC4);
    9. cv::Mat pngMat(480, 640, CV_8UC3);
    10. for (int i = 0; i < pngAlphaMat.rows; i++)
    11. {
    12. for (int j = 0; j < pngAlphaMat.cols; j++)
    13. {
    14. Vec4b &rgba = pngAlphaMat.at(i, j);
    15. Vec3b &rgb = pngMat.at(i, j);
    16. rgba[0] = UCHAR_MAX;
    17. rgba[1] = saturate_cast((float(pngAlphaMat.cols - j) / ((float)pngAlphaMat.cols))*UCHAR_MAX);
    18. rgba[2] = saturate_cast((float(pngAlphaMat.rows - i) / ((float)pngAlphaMat.rows))*UCHAR_MAX);
    19. rgba[3] = saturate_cast(0.5 * (rgba[1] + rgba[2]));
    20. rgb[0] = saturate_cast((float(pngMat.cols - j) / ((float)pngMat.cols))*UCHAR_MAX);
    21. rgb[1] = saturate_cast((float(pngMat.rows - i) / ((float)pngMat.rows))*UCHAR_MAX);
    22. rgb[2] = saturate_cast(0.5 * (rgb[1] + rgb[2]));
    23. }
    24. }
    25. vector<int> compression_params;
    26. compression_params.push_back(CV_IMWRITE_PNG_COMPRESSION);
    27. compression_params.push_back(9);
    28. cv::imwrite("透明Alpha图.png", pngAlphaMat, compression_params);
    29. cv::imwrite("不透明图.png", pngMat, compression_params);
    30. cv::imshow("透明PNG图", pngAlphaMat);
    31. cv::imshow("非透明PNG图", pngMat);
    32. cv::waitKey(0);
    33. return 0;
    34. }

    保存的图片:

  • 相关阅读:
    《java练级之路》之继承!!!
    记一次密码控制功能
    lock、tryLock、lockInterruptibly有什么区别?
    [RoarCTF 2019]Online Proxy
    Vue3+element-plus日期选择器 el-date-picker 设置可选最小时间方法
    驱动开发day2
    vuex是什么?如何使用?使用他的功能场景?
    分布式工厂如何使用工业物联网云平台去提高效率
    HTML小游戏8 —— 小霸王游戏机网页版(附完整源码)
    【Postman&JMeter】使用Postman和JMeter进行signature签名
  • 原文地址:https://blog.csdn.net/sinat_41752325/article/details/126011384