Improving Opencv 1:The Core Functionality (core module) Mat - The Basic Image Container

Refs: https://docs.opencv.org/4.3.0/d6/d6d/tutorial_mat_the_basic_image_container.html

 

目录

Mat

简单的赋值操作是浅copy

浅copy何时销毁内存

深copy using clone(),copyTo()

案例说明

Storing methods

最简单的存储方式是灰度图

彩色图

常用的彩色表示方式

Creating a Mat object explicitly



 

In the above image you can see that the mirror of the car is nothing more than a matrix containing all the intensity values of the pixel points. How we get and store the pixels values may vary according to our needs, but in the end all images inside a computer world may be reduced to numerical matrices and other information describing the matrix itself. OpenCV is a computer vision library whose main focus is to process and manipulate this information. Therefore, the first thing you need to be familiar with is how OpenCV stores and handles images.

 

Mat

Mat is basically a class with two data parts: the matrix header (containing information such as the size of the matrix, the method used for storing, at which address is the matrix stored, and so on) and a pointer to the matrix containing the pixel values (taking any dimensionality depending on the method chosen for storing) . The matrix header size is constant, however the size of the matrix itself may vary from image to image and usually is larger by orders of magnitude.

简单的赋值操作是浅copy

The idea is that each Mat object has its own header, however a matrix may be shared between two Mat objects by having their matrix pointers point to the same address. Moreover, the copy operators will only copy the headers and the pointer to the large matrix, not the data itself.

All the above objects, in the end, point to the same single data matrix and making a modification using any of them will affect all the other ones as well. In practice the different objects just provide different access methods to the same underlying data.

浅copy何时销毁内存

Now you may ask – if the matrix itself may belong to multiple Mat objects who takes responsibility for cleaning it up when it's no longer needed. The short answer is: the last object that used it. This is handled by using a reference counting mechanism. Whenever somebody copies a header of a Mat object, a counter is increased for the matrix. Whenever a header is cleaned, this counter is decreased. When the counter reaches zero the matrix is freed. Sometimes you will want to copy the matrix itself too, so OpenCV provides cv::Mat::clone() and cv::Mat::copyTo() functions.

深copy using clone(),copyTo()

Now modifying F or G will not affect the matrix pointed by the A's header.

What you need to remember from all this is that:

  • Output image allocation for OpenCV functions is automatic (unless specified otherwise).
  • You do not need to think about memory management with OpenCV's C++ interface.
  • The assignment operator and the copy constructor only copies the header.
  • The underlying matrix of an image may be copied using the cv::Mat::clone() and cv::Mat::copyTo() functions.

案例说明

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

using namespace cv;


void main()
{
	cv::Mat image_bee = cv::imread("honeybee.jpg");
	Mat image_grass = imread("Grass.jpg");

	if (image_bee.data)
	{

		Mat image_recv(image_bee);
		Mat image_mem = image_bee;

		//clone
		Mat image_bee_clone = image_bee.clone();
		Mat image_copy;
		image_bee.copyTo(image_copy);

		std::cout << "the address show the deep/shallow copy" << std::endl;

		pyrDown(image_mem, image_mem, Size(image_mem.cols / 2, image_mem.rows / 2));

		cv::imshow("bee", image_mem);

		pyrDown(image_grass, image_grass, Size(image_grass.cols / 2, image_grass.rows / 2));
		Mat part_grass(image_grass, Rect(100, 100, (int)image_grass.size().width*0.75, image_grass.size().height / 2));

		imshow("grass", image_grass);
		imshow("part", part_grass);
		cv::waitKey();

	}
	else
	{
		std::cout << "there is on data!" << std::endl;
	}

	return;
}

以上代码,可以通过监视变量的变化来证明深和浅copy

浅copy三者指针指向的数据地址相同

data是指针,指向Mat数据的首地址,因为是浅copy,所以只是指向相同

 

data:  
       uchar类型的指针,指向Mat数据矩阵的首地址。可以理解为标示一个房屋的门牌号;

dims: 
        Mat矩阵的维度,若Mat是一个二维矩阵,则dims=2,三维则dims=3,大多数情况下处理的都是二维矩阵,是一         个平面上的矩阵。
        可以理解为房屋是一个一层的平房,三维或更多维的则是多层楼房;


rows:
        Mat矩阵的行数。可理解为房屋内房间行数;

cols: 
        Mat矩阵的列数。可理解为房屋内房间列数;

size():
        首先size是一个结构体,定义了Mat矩阵内数据的分布形式,数值上有关系式:
         image.size().width==image.cols;        image.size().height==image.rows                                                      

         可以理解为房屋内房间的整体布局,这其中包括了房间分别在行列上分布的数量信息;


channels():
        Mat矩阵元素拥有的通道数。例如常见的RGB彩色图像,channels==3;而灰度图像只有一个灰度分量信息,             channels==1。
 

深copy,后面的变量各自拥有一份独立的数据,所以其地址不同。

Storing methods

最简单的存储方式是灰度图

This is about how you store the pixel values. You can select the color space and the data type used. The color space refers to how we combine color components in order to code a given color. The simplest one is the grayscale where the colors at our disposal are black and white. The combination of these allows us to create many shades of gray.

彩色图

四通道,三个颜色和一个透明通道

For colorful ways we have a lot more methods to choose from. Each of them breaks it down to three or four basic components and we can use the combination of these to create the others. The most popular one is RGB, mainly because this is also how our eye builds up colors. Its base colors are red, green and blue. To code the transparency of a color sometimes a fourth element: alpha (A) is added.

常用的彩色表示方式

There are, however, many other color systems each with their own advantages:

  • RGB is the most common as our eyes use something similar, however keep in mind that OpenCV standard display system composes colors using the BGR color space (red and blue channels are swapped places).
  • The HSV and HLS decompose colors into their hue, saturation and value/luminance components, which is a more natural way for us to describe colors. You might, for example, dismiss the last component, making your algorithm less sensible to the light conditions of the input image.
  • YCrCb is used by the popular JPEG image format.
  • CIE L*a*b* is a perceptually uniform color space, which comes in handy if you need to measure the distance of a given color to another color.

 

Each of the building components has its own valid domains. This leads to the data type used. How we store a component defines the control we have over its domain. The smallest data type possible is char, which means one byte or 8 bits. This may be unsigned (so can store values from 0 to 255) or signed (values from -127 to +127). Although in case of three components this already gives 16 million possible colors to represent (like in case of RGB) we may acquire an even finer control by using the float (4 byte = 32 bit) or double (8 byte = 64 bit) data types for each component. Nevertheless, remember that increasing the size of a component also increases the size of the whole picture in the memory.

 

Creating a Mat object explicitly

For two dimensional and multichannel images we first define their size: row and column count wise.

 

Then we need to specify the data type to use for storing the elements and the number of channels per matrix point. To do this we have multiple definitions constructed according to the following convention:

CV_[The number of bits per item][Signed or Unsigned][Type Prefix]C[The channel number]

C以三为例则表示列有3C个元素,C*(B, G, R)

 

For instance, CV_8UC3 means we use unsigned char types that are 8 bit long and each pixel has three of these to form the three channels. There are types predefined for up to four channels. The cv::Scalar is four element short vector. Specify it and you can initialize all matrix points with a custom value.

 

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

using namespace cv;
using namespace std;


void main()
{
	Mat M(2, 2, CV_8UC3, Scalar(0, 0, 255));
	cout << "M = " << endl << " " << M << endl << endl;

	//int sz[3] = { 2, 2, 2 };
	//Mat L(3, sz, CV_8UC(1), Scalar::all(0));
	//cout << "L = " << endl << " " << L << endl << endl;
	//The upper example shows how to create a matrix with more than two dimensions.Specify its dimension, 
	//	then pass a pointer containing the size for each dimension and the rest remains the same.


	M.create(4, 4, CV_8UC(2));
	cout << "M = " << endl << " " << M << endl << endl;
	//You cannot initialize the matrix values with this construction.
	//	It will only reallocate its matrix data memory if the new size will not fit into the old one.


	//MATLAB style initializer : cv::Mat::zeros, cv::Mat::ones, cv::Mat::eye.Specify size and data type to use :
	Mat E = Mat::eye(4, 4, CV_64F);
	cout << "E = " << endl << " " << E << endl << endl;
	Mat O = Mat::ones(2, 2, CV_32F);
	cout << "O = " << endl << " " << O << endl << endl;
	Mat Z = Mat::zeros(3, 3, CV_8UC1);
	cout << "Z = " << endl << " " << Z << endl << endl;

	Mat Zmore = Mat::zeros(3, 3, CV_8UC3);
	cout << "Zmore = " << endl << " " << Zmore << endl << endl;

	//For small matrices you may use comma separated initializers or initializer lists(C++11 support is required in the last case) :
	Mat C = (Mat_<double>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
	cout << "C = " << endl << " " << C << endl << endl;

	//You can fill out a matrix with random values using the cv::randu() function.
	//	You need to give a lower and upper limit for the random values :
	Mat R = Mat(3, 2, CV_8UC3);
	randu(R, Scalar::all(0), Scalar::all(255));
	cout << "R (default) = " << endl << R << endl << endl;

	return;
}

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值