copyTo方法引发的对Mat的理解

原创 2018年04月16日 16:07:20
最近用OpenCV开发中,需要一个功能:将一张小图片贴到一张大一点的背景图片上。

用的是copyTo方法。

例如这样:
Mat background = imread("back.jpg");
Mat a = imread("a.jpg");
Mat imageROI = background(Rect(20,20,a.cols,a.rows));//(20,20)指要贴到什么位置
a.copyTo(imageROI);
以上就完成了将a贴到background上。

麻烦出现在:当a不是从硬盘读取,而是截屏而来时。

由于截图一般返回的是位图句柄,即HBITMAP类型,需要先将HBITMAP转为Mat,我是这样转换的:

bool hBitMapToMat(HBITMAP& _hBmp,Mat& _mat)
{
	BITMAP bmp;    
	GetObject( _hBmp, sizeof(BITMAP), &bmp );    
	int nChannels = bmp.bmBitsPixel == 1 ? 1 : bmp.bmBitsPixel/8 ;   
	int depth = bmp.bmBitsPixel == 1 ? IPL_DEPTH_1U : IPL_DEPTH_8U;    
	Mat v_mat;
	v_mat.create( cvSize( bmp.bmWidth,bmp.bmHeight), CV_MAKETYPE(CV_8U, nChannels) );
	GetBitmapBits( _hBmp, bmp.bmHeight*bmp.bmWidth*nChannels, v_mat.data );  
	_mat = v_mat;
	return TRUE;   
}

例如:
Mat test_Mat;
hBitMapToMat(bitmap, test_Mat);
test_Mat.copyTo(imageROI);//这个执行失败了
调试良久,发现是Mat通道数不一致的问题。经hBitMapToMat转换后,得到的test_Mat的通道数为4。
而background的通道数为3,这时copyTo方法不能生效。


解决办法是将4通道转化为3通道:

Mat xx;
cvtColor(image, xx, CV_RGBA2RGB);//image是截取的图片


《Learning OpenCV 中文版》中说:4通道是RGB+alpha,其中每个通道可以包含任意的整数或浮点数,因此,该类型比常见的、易于理解的3通道8位RGB图像更通用。


OpenCV2中,数据结构Mat是保存图像像素信息的矩阵,它主要包含两部分:矩阵头和一个指向像素数据的矩阵指针。矩阵头主要包含,矩阵尺寸、存储方法、存储地址和引用次数等。

矩阵头的大小是一个常数,不会随着图像的大小而改变,但是保存图像像素数据的矩阵则会随着图像的大小而改变,通常数据量会很大,比矩阵头大几个数量级。这样,在图像复制和传递过程中,主要的开销是由存放图像像素的矩阵而引起的。因此,OpenCV使用了引用次数,当进行图像复制和传递时,不再复制整个Mat数据,而只是复制矩阵头和指向像素矩阵的指针。例如:
cv::Mat a ;//创建矩阵头
a = cv::imread("f:\\psb.jpg");//读入图像
cv::Mat b = a ;//复制  


The class Mat represents an n-dimensional dense numerical single-channel or multi-channel array. It can be used to store real or complex-valued vectors and matrices, grayscale or color images, voxel volumes, vector fields, point clouds, tensors, histograms (though, very high-dimensional histograms may be better stored in a SparseMat ).

上面的一段话引用自官方的文档,Mat类用于表示一个多维的单通道或者多通道的稠密数组。能够用来保存实数或复数的向量、矩阵,灰度或彩色图像,立体元素,点云,张量以及直方图(高维的直方图使用SparseMat保存比较好)。简而言之,Mat就是用来保存多维的矩阵的。


Mat的常见属性

data  uchar型的指针。Mat类分为了两个部分:矩阵头和指向矩阵数据部分的指针,data就是指向矩阵数据的指针。
dims 矩阵的维度,例如5*6矩阵是二维矩阵,则dims=2,三维矩阵dims=3.
rows  矩阵的行数
cols   矩阵的列数
size 矩阵的大小,size(cols,rows),如果矩阵的维数大于2,则是size(-1,-1)
channels 矩阵元素拥有的通道数,例如常见的彩色图像,每一个像素由RGB三部分组成,则channels = 3







使用目录内容建立菜单

目的:根据目录内容,建立一个菜单。菜单项为目录中的文件和子目录(以弹出方式显示)。解决方案:遍历子目录,建立一个文件路径数组。菜单项的ID是数组的索引。当用户单击某个菜单项时,从数组中读取文件路径并执...
  • jiangsheng
  • jiangsheng
  • 2001-08-02 22:58:00
  • 2068

【拜小白opencv】12-Mat类常用的几种创建方法及clone(),copyTo()的使用

Mat类常用的几种创建方法。及clone(),copyTo()的使用
  • sinat_36264666
  • sinat_36264666
  • 2017-08-16 16:49:11
  • 309

OpenCV中Mat操作clone() 与copyto()的区别

// Mat is basically a class with two data parts: the matrix header and //a pointer to the matrix con...
  • CorCplusplusorjava
  • CorCplusplusorjava
  • 2014-04-28 14:40:21
  • 18041

opencv之图像mat复制copyTo,clone=

函数原型 Mat clone() const; void copyTo( OutputArray m ) const; void copyTo( OutputArray m, InputArray m...
  • qq_20823641
  • qq_20823641
  • 2016-05-21 10:15:36
  • 24689

用mask掩码处理图片,Mat::copyTo函数第一个用于输出的传入参数不能是原图片

例如src.copyTo(src,mask)是绝对不能成功的。原本只想把理由粗略说一下,但是后来想一想看一看源代码还是有好处的,于是去源代码里面看了看,怎么知道由于本人的过于才疏学浅,就这么一看就看了...
  • jdpshq
  • jdpshq
  • 2013-06-02 18:13:37
  • 10971

OpenCV中操作Mat的copy()和clone()的区别

OpenCV中使用Mat,经常会碰到这样一种场景,会想拷贝一份Mat,并对新的Mat进行操作。但是OpenCV中的clone()和直接赋值都会导致共享数据区,也就是相当于&。 而使用copy,才会获...
  • patkritLee
  • patkritLee
  • 2016-10-10 21:42:02
  • 4299

opencv矩阵赋值函数copyTo、clone、重载元算赋=的比较

opencv矩阵赋值函数copyTo、clone、重载元算赋‘=’之间实现的功能相似均是给不同的矩阵赋值功能。copyTo和clone函数基本相同,被赋值的矩阵和赋值矩阵之间空间独立,不共享同一空间。...
  • kxuehen
  • kxuehen
  • 2015-01-29 10:14:43
  • 4168

cvSetImageROI 和 cv::Mat.copyTo 和 addWeighted

功能: 基于给定的矩形设置图像的ROI(感兴趣区域,region of interesting) 格式: void cvSetImageROI(IplImage* image,CvR...
  • chinabinlang
  • chinabinlang
  • 2014-09-30 10:21:28
  • 3427

clone()和copyTo()的区别

clone()和copyTo()的区别
  • neverfadingMay
  • neverfadingMay
  • 2017-02-15 15:23:34
  • 1051

刚发现copyTo还能加掩码

//---------------------------------【头文件、命名空间包含部分】---------------------------- // 描述:包含程序所使用的头文件和命名空...
  • lcj1105
  • lcj1105
  • 2016-01-29 14:59:19
  • 485
收藏助手
不良信息举报
您举报文章:copyTo方法引发的对Mat的理解
举报原因:
原因补充:

(最多只允许输入30个字)