Mat对象OpenCV2.0之后引进的图像数据结构、自动分配内存、不存在内存泄漏的问题,是面向对象的数据结构。分了两个部分,头部与数据部分
IplImage是从2001年OpenCV发布之后就一直存在,是C语言风格的数据结构,需要开发者自己分配与管理内存,对大的程序使用它容易导致内存泄漏问题,不建议使用了
Mat对象构造函数:(部分)
Mat();
Mat(int rows, int cols, int type);
Mat(Size size, int type);
Mat(int rows, int cols, int type, const Scalar& s);
Mat(Size size, int type, const Scalar& s);
Mat(int ndims, const int* sizes, int type);
Mat(int ndims, const int* sizes, int type, const Scalar& s);
常用方法:
void copyTo(Mat mat) //完全复制一份
void convertTo(Mat dst, int type) //转换,比如8位的转换为float
Mat clone() //完全复制一份
int channels() //通道数
int depth() //深度
bool empty(); //是否空
uchar* ptr(i=0) //矩阵数据指针
Mat对象使用-四个要点:
输出图像的内存是自动分配的
使用OpenCV的C++接口,不需要考虑内存分配问题
赋值操作和拷贝构造函数只会复制头部分
使用clone与copyTo两个函数实现数据完全复制
创建多维数组cv::Mat::create
int sz[3] = {2,2,2};
Mat L(3,sz, CV_8UC1, Scalar::all(0)); //这里的3表示3维数组
vs代码
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
void main(int argc, char** argv)
{
Mat src;
double time, timeconsume;
src = imread("D:/hankin/opencv/images/test1_3.png", IMREAD_COLOR);
if (!src.data)
{
printf("could not load image..");
return;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", src);
Mat dst = Mat(src.size(), src.type());
dst = Scalar(127, 0, 255);//给矩阵所有的像素点设置颜色数据,绯红,这里的 = 号运算符重载了。。 Scalar参数顺序是 B G R
//Mat dst = src.clone();//完全拷贝
/*Mat dst;
src.copyTo(dst);//完全拷贝*/
//Mat dst = imread("...");//只是复制部分,Mat对象头部与数据的指针,不会复制数据
//Mat dst(src);//只是复制部分,Mat对象头部与数据的指针,不会复制数据
namedWindow("output image", CV_WINDOW_AUTOSIZE);
imshow("output image", dst);
cvtColor(src, dst, CV_BGR2GRAY);//dst对象输出图像的内存是自动分配的
printf("rgb.channels=%d, gray.channels=%d,%d,%d\n", src.channels(), dst.channels(), src.type(), dst.type());//rgb通道数为3,gray通道数为1,16,0
const uchar* firstRow = dst.ptr<uchar>(0);//图像第一行颜色数据
printf("first pixel value : %d\n", *firstRow);
printf("dst.cols=%d, dst.rows=%d\n", dst.cols, dst.rows);
// CV_8UC1 8表示8位,UC表示unsigned char,1表示1个通道, Scalar表示向量长度,要与通道数目一致
Mat m(3, 3, CV_8UC3, Scalar(0, 0, 255));//3*3个像素点,CV_8UC3表示像素点为三个通道颜色数据,CV_8UC1表示像素点为单通道,对应的传 Scalar(255)
cout << "m = " << endl << m << endl;//打印每个通道颜色数据
/* m =
[ 0, 0, 255, 0, 0, 255, 0, 0, 255;
0, 0, 255, 0, 0, 255, 0, 0, 255;
0, 0, 255, 0, 0, 255, 0, 0, 255]
*/
imshow("scalar", m);
Mat m1;
m1.create(src.size(), src.type());//以create方式创建Mat
m1 = Scalar(0, 0, 255);//Scalar参数顺序是 B G R
imshow("create", m1);
//Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0); //定义小数组,以 << 运算符重载 创建Mat
Mat zeros = Mat::zeros(2, 2, CV_8UC1);//初始值0
cout << "zeros = " << endl << zeros << endl;
/*
zeros =
[0, 0;
0, 0]
eye =
[1, 0;
0, 1;
0, 0]
*/
Mat eye = Mat::eye(3, 2, CV_8UC1);//沿着主对角线的像素点(不是通道)的第一个通道的数据设置为1,其他都为0,对于CV_8UC1的方阵可以生成单一矩阵
cout << "eye = " << endl << eye << endl;
waitKey(0);
}
效果图
android代码
@BindView(R.id.iv_opencv1_4_origin) ImageView mOriginIv;
@BindView(R.id.iv_opencv1_4_convert1) ImageView mConvert1Iv;
@BindView(R.id.iv_opencv1_4_convert2) ImageView mConvert2Iv;
private Bitmap mOriginBmp;
private Bitmap mConvert1Bmp;
private Bitmap mConvert2Bmp;
private Mat mOriginMat = new Mat();
private Mat mConvert1Mat;
private Mat mConvert2Mat = new Mat();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cv1_4);
mUnbinder = ButterKnife.bind(this);
//origin
mOriginBmp = CV310Utils.getBitmapFromAssets(this, "opencv/test1_3.png");//格式是Bitmap.Config.ARGB_8888
mOriginIv.setImageBitmap(mOriginBmp);
mConvert1Bmp = Bitmap.createBitmap(mOriginBmp.getWidth(), mOriginBmp.getHeight(), Bitmap.Config.RGB_565);
mConvert2Bmp = Bitmap.createBitmap(mOriginBmp.getWidth(), mOriginBmp.getHeight(), Bitmap.Config.ARGB_8888);
Utils.bitmapToMat(mOriginBmp, mOriginMat);//只支持RGB_565或ARGB_8888,Mat生成的是4通道的RGBA
LogUtils.d("mydebug---", "origin.channels="+mOriginMat.channels()+",origin.type="+mOriginMat.type());//origin.channels=4,origin.type=24
//convert1
mConvert1Mat = new Mat(mOriginMat.size(), mOriginMat.type());
Scalar scalar1 = new Scalar(255, 0, 127, 64);//c++中scalar参数是BGR排列顺序,java中是RGBA ,因为mConvert1Bmp是 RGB_565 所以 alpha 在Scalar不起作用
mConvert1Mat.setTo(scalar1);//给矩阵所有的像素点设置颜色数据,绯红
Utils.matToBitmap(mConvert1Mat, mConvert1Bmp);
LogUtils.d("mydebug---", "rgb565.channels="+mOriginMat.channels()+",rgb565.type="+mOriginMat.type());//rgb565.channels=4,rgb565.type=24
mConvert1Iv.setImageBitmap(mConvert1Bmp);
//convert2
mConvert2Mat.create(mOriginMat.size(), mOriginMat.type());//create方式创建Mat
Scalar scalar2 = new Scalar(255, 0, 127, 64);//由于mConvert2Bmp是 ARGB_8888,所以 alpha 会在Scalar起作用
mConvert2Mat.setTo(scalar2);
Utils.matToBitmap(mConvert2Mat, mConvert2Bmp);
LogUtils.d("mydebug---", "argb8888.channels="+mOriginMat.channels()+",argb8888.type="+mOriginMat.type());//argb8888.channels=4,argb8888.type=24
mConvert2Iv.setImageBitmap(mConvert2Bmp);
Mat gray = new Mat();
Imgproc.cvtColor(mOriginMat, gray, Imgproc.COLOR_BGR2GRAY);
LogUtils.d("mydebug---", "gray.channels="+gray.channels()+",gray.type="+gray.type());//gray.channels=1,gray.type=0
// CV_8UC1 8表示8位,UC表示unsigned char,1表示1个通道, Scalar表示向量长度,要与通道数目一致
Mat cv_8uc3 = new Mat(3, 3, CvType.CV_8UC3, new Scalar(255, 0, 0));//3*3个像素点,CV_8UC3表示像素点为三个通道颜色数据,CV_8UC1表示像素点为单通道,对应的传 Scalar(255)
/* cv_8uc3 =
255,0,0,255,0,0,255,0,0,
255,0,0,255,0,0,255,0,0,
255,0,0,255,0,0,255,0,0,
*/
LogUtils.d("mydebug---", "cv_8uc3="+CV310Utils.traverseMat(cv_8uc3));//打印每个通道颜色数据
Mat zeros = Mat.zeros(2, 2, CvType.CV_8UC1);//初始值0
/* zeros =
0,0,
0,0,
*/
LogUtils.d("mydebug---", "zeros="+CV310Utils.traverseMat(zeros));
Mat eye = Mat.eye(3, 2, CvType.CV_8UC2);//沿着主对角线的像素点(不是通道)的第一个通道的数据设置为1,其他都为0,对于CV_8UC1的方阵可以生成单一矩阵
/* eye =
1,0,0,0,
0,0,1,0,
0,0,0,0,
*/
LogUtils.d("mydebug---", "eye="+CV310Utils.traverseMat(eye));
}
效果图