OPENCV学习笔记3_Mat 保存

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OPENCV学习笔记3_Mat 保存相关的知识,希望对你有一定的参考价值。

1.1   Storing methods(Mat存储方法)

     1. color space    

    储像素值需要指定颜色空间和数据类型。颜色空间是指对一个给定的颜色,如何组合颜色元素以对其编码。最简单的颜色空间要属灰度级空间,只处理黑色和白色,对它们进行组合可以产生不同程度的灰色。对于 彩色 方式则有更多种类的颜色空间,但不论哪种方式都是把颜色分成三个或者四个基元素,通过组合基元素可以产生所有的颜色。RGB颜色空间是最常用的一种颜色空间,这归功于它也是人眼内部构成颜色的方式。它的基色是红色、绿色和蓝色,有时为了表示透明颜色也会加入第四个元素 alpha (A)。有很多的颜色系统,各有自身优势:   

  • RGB是最常见的,这是因为人眼采用相似的工作机制,它也被显示设备所采用。
  • HSV(hue、saturation、value)和HSL(、lightness)把颜色分解成色调、饱和度和亮度/明度。这是描述颜色更自然的方式,比如可以通过抛弃最后一个元素,使算法对输入图像的光照条件不敏感。
  • YCrCb在JPEG图像格式中广泛使用。
  • CIE L*a*b*是一种在感知上均匀的颜色空间,它适合用来度量两个颜色之间的距离 。
    2. data type  

    每个组成元素都有其自己的定义域,取决于其数据类型。最小的数据类型是 char ,占一个字节或者8位,可以是有符号型(0到255之间)或无符号型(-127到+127之间)。尽管使用三个 char 型元素已经可以表示1600万种可能的颜色(使用RGB颜色空间),但若使用float(4字节,32位)或double(8字节,64位)则能给出更加精细的颜色分辨能力。但同时也要切记增加元素的尺寸也会增加了图像所占的内存空间。

1.2   Mat accessing pixels(at)

    1. vector(向量) 

    vector是STL中最常见的容器,它是一种顺序容器,支持随机访问。vector是一块连续分配的内存,从数据安排的角度来讲,和数组极其相似,不同的地方就是:数组是静态分配空间,一旦分配了空间的大小,就不可再改变了;而vector是动态分配空间,随着元素的不断插入,它会按照自身的一套机制不断扩充自身的容量, 当程序员无法知道自己需要的数组的规模多大时,用其来解决问题可以达到最大节约空间的目的。

#include<vector>
#include <iostream>
using namespace std;
int main()
{
   int i =0;
   vector<int>  g;           //Vector to store integers
   for( i = 0; i < 5; i++ )
   {
        g.push_back( i );
   }
   for( i = 0; i < g.size(); i++ )
   {
        cout << g[ i ] << "  ";
   }
   cout << endl;
   return 0;
}

技术分享

    例如 8U 类型的 RGB 彩色图像可以使用 <Vec3b>,3 通道 float 类型的矩阵可以使用 <Vec3f>

    2. .at(int x, int y)

    可以用来存取图像中对应坐标为(x,y)的元素坐标。

    假设提前已知一幅图像img的数据类型为 unsigned char型灰度图(单通道),要对坐标为(14,25)的像素重新赋值为25,则对应操作如下:

Mat grayim(600, 800, CV_8UC1);

uchar value = grayim.at<uchar>(i, j);    // 读出第 i行第 j列像素值

grayim.at<uchar>(i, j) = 128;           // 将第 i行第 j列像素值设置为 128 128

    如果要操作的图片img是一幅数据类型同样为unsigned char的彩色图片,再次要求将坐标(14,25)的像素赋值为25,需要对这个像素三个通道的每个对应元素赋值,Opencv中图像三原色在内存中的排列顺序为B-G-R,操作过程如下:

img.at< Vec3b >(14, 25)[0] = 25;//B   

img.at< Vec3b >(14, 25)[1] = 25;//G   

img.at< Vec3b >(14, 25)[2] = 25;//R

    需要注意的是,如果要遍历图像,并不推荐使用at()函数。使用这个函数的优点是代码的可读性高,但是效率并不是很高。

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main()
{
    Mat    image(600, 800, CV_8UC1);
    Mat    image2(600, 800, CV_8UC3);
    for (int i = 0; i < image.rows; ++i)
    {
        for (int j = 0; j < image.cols; ++j)
        {
            image.at<uchar>(i, j) = 0;
        }
    }
    for (int i = 0; i < image2.rows; ++i)
    {
        for (int j = 0; j < image2.cols; ++j)
        {
            image2.at<Vec3b>(i, j)[0] = 50;
            image2.at<Vec3b>(i, j)[1] = 150;
            image2.at<Vec3b>(i, j)[2] = 250;
        }
    }
    imshow("image", image);
    imshow("image2", image2);
    waitKey(0);

}

技术分享

    3. imwrite函数

  bool imwrite( const String& filename, InputArray img, const std::vector<int>& params = std::vector<int>());

  •   filename,扩展名来指定图像的保存格式(.jpg .png .bmp)
  •   params,用来指定图像的保存编码方式,对于不同的图像保存类型,params是不同的值:

    JPEG,参数为CV_IMWRITE_JPEG_QUALITY(图片质量),值是从0到100,值越小压缩的越多,默认值是95;

    PNG, 参数为CV_IMWRITE_PNG_COMPRESSION(压缩级别),值是从0到9,值越大表示图片尺寸越小,压缩时间越长。默认值是3;

    PPM,PGM或者PBM,参数为CV_IMWRITE_PXM_BINARY(二进制格式标志),值是0或者1。默认值是1。

  imwrite只能保存8位(或者是16位无符号(CV_16UC)的PNG,JPEG200或者TIFF图像)单通道或者三通道的图像,如果要保存的不是这样的图片,可以使用convertTo或者cvtColor来进行转变。

  下面代码展示了如果使用imwrite向文件中写入一个4通道的png图像

#include<iostream>  
#include<opencv2/opencv.hpp>  
using namespace std;  
using namespace cv;
/*
阿尔法通道(Alpha Channel)是指一张图片的透明和半透明度。一个使用32位存储的图片,每8位表示红绿蓝,和阿尔法通道。
在这种情况下,就不光可以表示透明还是不透明,阿尔法通道还可以表示256级的半透明度。
*/
void createAlphaMat(Mat &mat) // 创建带Alpha通道的Mat,MAT 实体
{
    for(int i = 0 ; i < mat.rows ; i ++) {
        for(int j = 0 ; j < mat.cols ; j ++) {
            Vec4b &rgba = mat.at<Vec4b>(i,j);
            //UCHAR_MAX的宏定义为0xff,对应的是R通道
            rgba[0] = UCHAR_MAX ; 
            //对于G通道,表示越往右占的百分比就越少,颜色也就越深
            //saturate_cast,限制数据范围为0~255,超过255的值取255,小于0的值取03
            rgba[1] = saturate_cast<uchar>((float (mat.cols - j)) / ((float)mat.cols) * UCHAR_MAX);
            //对于B通道,表示越往下占的百分比就越少,颜色也就越深
            rgba[2] = saturate_cast<uchar>((float (mat.rows - i)) / ((float)mat.rows) * UCHAR_MAX);
            //最后的透明度,是取G和B通道的平均值
            rgba[3] = saturate_cast<uchar>(0.5 * (rgba[1] + rgba[2]));
        }
    }
}

int main()
{
    Mat mat(480,640,CV_8UC4);
    
    createAlphaMat(mat);
    //定义一个容器compression_params,容器内的值为int类型
    vector<int> compression_params ;
    //向compression_params里面添加值
    compression_params.push_back(CV_IMWRITE_PNG_COMPRESSION); 
    compression_params.push_back(9);
    imwrite("alpha.png",mat,compression_params);
    // CV_IMWRITE_PNG_COMPRESSION = 9

    return 0;
}

技术分享

 

以上是关于OPENCV学习笔记3_Mat 保存的主要内容,如果未能解决你的问题,请参考以下文章

OPENCV学习笔记2-8_Mat_类

[OpenCV学习笔记2][Mat数据类型和操作]

OPENCV学习笔记1_Mat 创建

OPENCV学习笔记2_Mat 加载, 显示

opencv学习笔记opencv加载图像修改图像显示图像保存图像以及代码举例

OPENCV学习笔记1-8_选取图像局部区域