目 录
1.初始化矩阵:. 1
2.IplImage 到cvMat的转换. 1
3.cvArr(IplImage或者cvMat)转化为cvMat 1
4.图像直接操作. 2
5.cvMat的直接操作. 3
6.间接访问cvMat 4
7.修改矩阵的形状——cvReshape的操作. 5
8.计算色彩距离. 7
OpenCV学习之CvMat的用法详解及实例
目 录
1.初始化矩阵:. 1
2.IplImage 到cvMat的转换. 1
3.cvArr(IplImage或者cvMat)转化为cvMat 1
4.图像直接操作. 2
5.cvMat的直接操作. 3
6.间接访问cvMat 4
7.修改矩阵的形状——cvReshape的操作. 5
8.计算色彩距离. 7
CvMat是OpenCV比较基础的函数。初学者应该掌握并熟练应用。但是我认为计算机专业学习的方法是,不断的总结并且提炼,同时还要做大量的实践,如编码,才能记忆深刻,体会深刻,从而引导自己想更高层次迈进。
1.初始化矩阵:
方式一、逐点赋值式:
CvMat*mat = cvCreateMat( 2, 2, CV_64FC1 );
cvZero( mat );
cvmSet( mat, 0, 0, 1 );
cvmSet( mat, 0, 1, 2 );
cvmSet( mat, 1, 0, 3 );
cvmSet( mat, 2, 2, 4 );
cvReleaseMat( &mat );
方式二、连接现有数组式:
doublea[] = { 1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12 };
CvMat mat = cvMat( 3, 4, CV_64FC1, a ); // 64FC1 for double
// 不需要cvReleaseMat,因为数据内存分配是由double定义的数组进行的。
方式一、cvGetMat方式:
CvMat mathdr,*mat = cvGetMat( img, &mathdr );
方式二、cvConvert方式:
CvMat *mat =cvCreateMat( img->height, img->width, CV_64FC3 );
cvConvert( img, mat );
// #define cvConvert( src, dst ) cvConvertScale( (src), (dst), 1, 0 )
3.cvArr(IplImage或者cvMat)转化为cvMat
方式一、cvGetMat方式:
int coi = 0;
cvMat *mat = (CvMat*)arr;
if( !CV_IS_MAT(mat) )
{
mat = cvGetMat( mat, &matstub, &coi );
if (coi != 0) reutn; // CV_ERROR_FROM_CODE(CV_BadCOI);
}
写成函数为:
// This is justan example of function
// to support both IplImage and cvMat as an input
CVAPI( void ) cvIamArr( const CvArr* arr )
{
CV_FUNCNAME( "cvIamArr" );
__BEGIN__;
CV_ASSERT( mat == NULL );
CvMat matstub, *mat = (CvMat*)arr;
int coi = 0;
if( !CV_IS_MAT(mat) )
{
CV_CALL( mat = cvGetMat( mat,&matstub, &coi ) );
if (coi != 0)CV_ERROR_FROM_CODE(CV_BadCOI);
}
// Process as cvMat
__END__;
}
4.图像直接操作
方式一:直接数组操作 int col, row, z;
uchar b, g, r;
for( y = 0; row < img->height; y++ )
{
for ( col = 0; col < img->width; col++ )
{
b = img->imageData[img->widthStep * row + col *3]
g = img->imageData[img->widthStep * row + col *3 + 1];
r = img->imageData[img->widthStep * row + col *3 + 2];
}
}
方式二:宏操作:
int row, col;
uchar b, g, r;
for( row = 0; row < img->height; row++ )
{
for ( col = 0; col < img->width; col++ )
{
b = CV_IMAGE_ELEM( img, uchar, row, col * 3 );
g = CV_IMAGE_ELEM( img, uchar, row, col * 3 + 1 );
r = CV_IMAGE_ELEM( img, uchar, row, col * 3 + 2 );
}
}
注:CV_IMAGE_ELEM(img, uchar, row, col * img->nChannels + ch )
5.cvMat的直接操作
数组的直接操作比较郁闷,这是由于其决定于数组的数据类型。
对于CV_32FC1 (1 channel float):
CvMat* M =cvCreateMat( 4, 4, CV_32FC1 );
M->data.fl[ row * M->cols + col ] = (float)3.0;
对于CV_64FC1 (1 channel double):
CvMat* M =cvCreateMat( 4, 4, CV_64FC1 );
M->data.db[ row * M->cols + col ] = 3.0;
一般的,对于1通道的数组:
CvMat* M =cvCreateMat( 4, 4, CV_64FC1 );
CV_MAT_ELEM( *M, double, row, col ) = 3.0;
注意double要根据数组的数据类型来传入,这个宏对多通道无能为力。
对于多通道:
看看这个宏的定义:#defineCV_MAT_ELEM_CN( mat, elemtype, row, col ) \
(*(elemtype*)((mat).data.ptr + (size_t)(mat).step*(row) +sizeof(elemtype)*(col)))
if( CV_MAT_DEPTH(M->type) == CV_32F )
CV_MAT_ELEM_CN( *M, float, row, col * CV_MAT_CN(M->type)+ ch ) = 3.0;
if( CV_MAT_DEPTH(M->type) == CV_64F )
CV_MAT_ELEM_CN( *M, double, row, col * CV_MAT_CN(M->type)+ ch ) = 3.0;
更优化的方法是:
#define CV_8U 0
#define CV_8S 1
#define CV_16U 2
#define CV_16S 3
#define CV_32S 4
#define CV_32F 5
#define CV_64F 6
#define CV_USRTYPE1 7
intelem_size = CV_ELEM_SIZE( mat->type );
for( col = start_col; col < end_col; col++ ) {
for( row = 0; row < mat->rows; row++ ) {
for( elem = 0; elem < elem_size;elem++ ) {
(mat->data.ptr + ((size_t)mat->step * row) + (elem_size * col))[elem] =
(submat->data.ptr + ((size_t)submat->step * row) + (elem_size * (col -start_col)))[elem];
}
}
}
对于多通道的数组,以下操作是推荐的:
for(row=0;row< mat->rows; row++)
{
p = mat->data.fl + row *(mat->step/4);
for(col = 0; col < mat->cols;col++)
{
*p = (float)row+col;
*(p+1) =(float) row+col+1;
*(p+2)=(float) row+col+2;
p+=3;
}
}
对于两通道和四通道而言:
CvMat* vector =cvCreateMat( 1, 3, CV_32SC2 );
CV_MAT_ELEM( *vector, CvPoint, 0, 0 ) = cvPoint(100,100);
CvMat*vector = cvCreateMat( 1, 3, CV_64FC4 );
CV_MAT_ELEM( *vector, CvScalar, 0, 0 ) = cvScalar(0,0,0,0);
6.间接访问cvMat
cvmGet/Set是访问CV_32FC1 和 CV_64FC1型数组的最简便的方式,其访问速度和直接访问几乎相同
cvmSet( mat,row, col, value );
cvmGet( mat, row, col );
举例:打印一个数组
inline voidcvDoubleMatPrint( const CvMat* mat )
{
int i, j;
for( i = 0; i < mat->rows; i++ )
{
for( j = 0; j < mat->cols; j++)
{
printf("%f ",cvmGet( mat, i, j ) );
}
printf( "\n" );
}
}
而对于其他的,比如是多通道的后者是其他数据类型的,cvGet/Set2D是个不错的选择
CvScalar scalar= cvGet2D( mat, row, col );
cvSet2D( mat, row, col, cvScalar( r, g, b ) );
注意:数据不能为int,因为cvGet2D得到的实质是double类型。
举例:打印一个多通道矩阵:
inline voidcv3DoubleMatPrint( const CvMat* mat )
{
int i, j;
for( i = 0; i < mat->rows; i++ )
{
for( j = 0; j < mat->cols; j++)
{
CvScalarscal = cvGet2D( mat, i, j );
printf("(%f,%f,%f) ", scal.val[0], scal.val[1], scal.val[2] );
}
printf( "\n" );
}
}
7.修改矩阵的形状——cvReshape的操作
经实验表明矩阵操作的进行的顺序是:首先满足通道,然后满足列,最后是满足行。
注意:这和Matlab是不同的,Matlab是行、列、通道的顺序。
我们在此举例如下:
对于一通道:
// 1 channel
CvMat *mat, mathdr;
double data[] = { 11, 12, 13, 14,
21, 22, 23, 24,
31, 32, 33, 34 };
CvMat* orig = &cvMat( 3, 4, CV_64FC1, data );
//11 12 13 14
//21 22 23 24
//31 32 33 34
mat = cvReshape( orig, &mathdr, 1, 1 ); // new_ch, new_rows
cvDoubleMatPrint( mat ); // above
// 11 12 13 14 21 22 23 24 31 32 33 34
mat = cvReshape( mat, &mathdr, 1, 3 ); // new_ch, new_rows
cvDoubleMatPrint( mat ); // above
//11 12 13 14
//21 22 23 24
//31 32 33 34
mat = cvReshape( orig, &mathdr, 1, 12 ); // new_ch, new_rows
cvDoubleMatPrint( mat ); // above
// 11
// 12
// 13
// 14
// 21
// 22
// 23
// 24
// 31
// 32
// 33
// 34
mat = cvReshape( mat, &mathdr, 1, 3 ); // new_ch, new_rows
cvDoubleMatPrint( mat ); // above
//11 12 13 14
//21 22 23 24
//31 32 33 34
mat = cvReshape( orig, &mathdr, 1, 2 ); // new_ch, new_rows
cvDoubleMatPrint( mat ); // above
//11 12 13 14 21 22
//23 24 31 32 33 34
mat = cvReshape( mat, &mathdr, 1, 3 ); // new_ch, new_rows
cvDoubleMatPrint( mat ); // above
//11 12 13 14
//21 22 23 24
//31 32 33 34
mat = cvReshape( orig, &mathdr, 1, 6 ); // new_ch, new_rows
cvDoubleMatPrint( mat ); // above
// 11 12
// 13 14
// 21 22
// 23 24
// 31 32
// 33 34
mat = cvReshape( mat, &mathdr, 1, 3 ); // new_ch, new_rows
cvDoubleMatPrint( mat ); // above
//11 12 13 14
//21 22 23 24
//31 32 33 34
// Use cvTranspose and cvReshape( mat, &mathdr, 1, 2 ) to get
// 11 23
// 12 24
// 13 31
// 14 32
// 21 33
// 22 34
// Use cvTranspose again when to recover
对于三通道
// 3 channels
CvMat mathdr, *mat;
double data[] = { 111, 112, 113, 121, 122, 123,
211, 212, 213, 221, 222, 223 };
CvMat* orig = &cvMat( 2, 2, CV_64FC3, data );
//(111,112,113) (121,122,123)
//(211,212,213) (221,222,223)
mat = cvReshape( orig, &mathdr, 3, 1 ); // new_ch, new_rows
cv3DoubleMatPrint( mat ); // above
// (111,112,113) (121,122,123) (211,212,213) (221,222,223)
// concatinate in column first order
mat = cvReshape( orig, &mathdr, 1, 1 );// new_ch, new_rows
cvDoubleMatPrint( mat ); // above
// 111 112 113 121 122 123 211 212 213 221 222 223
// concatinate in channel first, column second, row third
mat = cvReshape( orig, &mathdr, 1, 3); // new_ch, new_rows
cvDoubleMatPrint( mat ); // above
//111 112 113 121
//122 123 211 212
//213 221 222 223
// channel first, column second, row third
mat = cvReshape( orig, &mathdr, 1, 4 ); // new_ch, new_rows
cvDoubleMatPrint( mat ); // above
//111 112 113
//121 122 123
//211 212 213
//221 222 223
// channel first, column second, row third
// memorize this transform because this is useful to
// add (or do something) color channels
CvMat* mat2 = cvCreateMat( mat->cols, mat->rows, mat->type );
cvTranspose( mat, mat2 );
cvDoubleMatPrint( mat2 ); // above
//111 121 211 221
//112 122 212 222
//113 123 213 223
cvReleaseMat( &mat2 );
8.计算色彩距离
我们要计算img1,img2的每个像素的距离,用dist表示,定义如下
IplImage *img1= cvCreateImage( cvSize(w,h), IPL_DEPTH_8U, 3 );
IplImage *img2 = cvCreateImage( cvSize(w,h), IPL_DEPTH_8U, 3 );
CvMat *dist = cvCreateMat( h, w, CV_64FC1 );
比较笨的思路是:cvSplit->cvSub->cvMul->cvAdd
代码如下:
IplImage *img1B= cvCreateImage( cvGetSize(img1), img1->depth, 1 );
IplImage *img1G = cvCreateImage( cvGetSize(img1), img1->depth, 1 );
IplImage *img1R = cvCreateImage( cvGetSize(img1), img1->depth, 1 );
IplImage *img2B = cvCreateImage( cvGetSize(img1), img1->depth, 1 );
IplImage *img2G = cvCreateImage( cvGetSize(img1), img1->depth, 1 );
IplImage *img2R = cvCreateImage( cvGetSize(img1), img1->depth, 1 );
IplImage *diff = cvCreateImage( cvGetSize(img1),IPL_DEPTH_64F, 1 );
cvSplit( img1, img1B, img1G, img1R );
cvSplit( img2, img2B, img2G, img2R );
cvSub( img1B, img2B, diff );
cvMul( diff, diff, dist );
cvSub( img1G, img2G, diff );
cvMul( diff, diff, diff);
cvAdd( diff, dist, dist );
cvSub( img1R, img2R, diff );
cvMul( diff, diff, diff );
cvAdd( diff, dist, dist );
cvReleaseImage( &img1B );
cvReleaseImage( &img1G );
cvReleaseImage( &img1R );
cvReleaseImage( &img2B );
cvReleaseImage( &img2G );
cvReleaseImage( &img2R );
cvReleaseImage( &diff );
比较聪明的思路是
int D =img1->nChannels; // D: Number of colors (dimension)
int N = img1->width * img1->height; // N: number of pixels
CvMat mat1hdr, *mat1 = cvReshape( img1, &mat1hdr, 1, N ); // N x D(colors)
CvMat mat2hdr, *mat2 = cvReshape( img2, &mat2hdr, 1, N ); // N x D(colors)
CvMat diffhdr, *diff = cvCreateMat( N, D, CV_64FC1 ); // N x D, temporal buff
cvSub( mat1, mat2, diff );
cvMul( diff, diff, diff );
dist = cvReshape( dist, &disthdr, 1, N ); // nRow x nCol to N x 1
cvReduce( diff, dist, 1, CV_REDUCE_SUM ); // N x D to N x 1
dist = cvReshape( dist, &disthdr, 1, img1->height ); // Restore N x 1 tonRow x nCol
cvReleaseMat( &diff );
#pragmacomment( lib, "cxcore.lib" )
#include "cv.h"
#include <stdio.h>
int main()
{
CvMat* mat = cvCreateMat(3,3,CV_32FC1);
cvZero(mat);//将矩阵置0
//为矩阵元素赋值
CV_MAT_ELEM(*mat, float, 0, 0 ) = 1.f;
CV_MAT_ELEM( *mat, float, 0, 1 ) = 2.f;
CV_MAT_ELEM( *mat, float, 0, 2 ) = 3.f;
CV_MAT_ELEM( *mat, float, 1, 0 ) = 4.f;
CV_MAT_ELEM( *mat, float, 1, 1 ) = 5.f;
CV_MAT_ELEM( *mat, float, 1, 2 ) = 6.f;
CV_MAT_ELEM( *mat, float, 2, 0 ) = 7.f;
CV_MAT_ELEM( *mat, float, 2, 1 ) = 8.f;
CV_MAT_ELEM( *mat, float, 2, 2 ) = 9.f;
//获得矩阵元素(0,2)的值
float *p =(float*)cvPtr2D(mat, 0, 2);
printf("%f\n",*p);
return 0;
}
分享到:
相关推荐
掌握 `CvMat` 的使用是OpenCV学习的基础,通过不断实践和总结,可以深化对图像处理的理解,进一步探索如特征提取、图像变换、目标检测等高级话题。在实际编程中,还需要了解如何与其他OpenCV结构(如 `Mat`)互换,...
掌握CvMat的用法对于深入理解OpenCV和图像处理至关重要。通过不断的实践和实验,你可以更好地理解和运用这些概念,从而提升你的编程技能。同时,了解如何转换数据格式和操作图像数据是图像处理中的基本技巧,这对于...
OpenCV 中 CvMat 的用法小结 OpenCV 是一个计算机视觉库,它提供了许多实用的函数和数据结构来处理图像和视频。其中,CvMat 是 OpenCV 中的一个基本数据结构,用于存储矩阵数据。在本文中,我们将详细介绍 CvMat 的...
### OpenCV中CvMat的用法详解 #### 1. 初始化矩阵 在OpenCV中,`CvMat`类用于表示多维数值数组。它主要用于处理图像数据和其他需要矩阵运算的情况。 **方式一:逐点赋值式** ```c CvMat* mat = cvCreateMat(2, 2...
今天我们将使用C语言来实现OpenCV提取直线、轮廓及ROI实例详解。 一、Canny检测轮廓检测 Canny检测是一种非监督的边缘检测算法,由John F. Canny在1986年提出。它使用双阈值法来检测图像中的边缘,高阈值用来检测...
关于Opencv的项目实例设计,帮助进阶者继续学习opencv图像处理。
压缩包中的`OpenCV实例.ppt`可能包含了上述各种技术的实际应用案例,例如,使用OpenCV进行实时的人脸检测、图像滤波、边缘检测、图像分割等。通过这些实例,开发者可以更好地掌握OpenCV的用法,并将其应用到自己的...
OpenCV3编程学习笔记+OpenCV实例程序源代码(20个): 20170417_用前置摄像头录制视频.c 20170417_用前置摄像头拍照.c 20170419_用滑条实现亮度调节.c 20170419_用滑条实现线性混合.c 20170419_用鼠标来绘制矩形.c ...
如下所示: import cv2 im = cv2.imread('2.jpg') ... 您可能感兴趣的文章:ubuntu下编译安装opencv的方法Opencv+Python实现图像运动模糊和高斯模糊的示例OpenCV HSV颜色识别及HSV基本颜色分量范围基于Ope
OpenCV Mat实例详解二源码,包含OpenCV Mat构造函数使用方法实例。
这个实例详解将深入探讨如何使用`Mat`类,并通过源代码来解释其成员函数的用法。`Mat`类提供了丰富的功能,包括创建、访问、修改数组元素,以及进行各种图像处理操作。 一、`Mat`类的创建与初始化 1. 基本构造函数...
在这个`OpenCV Mat实例详解一源码`中,我们将深入理解`Mat`类的使用方法和相关概念。 `Mat`类是OpenCV的核心,它支持多种数据类型,包括浮点数、整数、布尔值等,并且可以处理单通道和多通道的数据,如灰度图像、...
自己的一些小程序,希望帮助大家共同学习OpenCV,我的程序是用Qt写的,不过大致思路是相同的
**OpenCV入门教程详解** OpenCV(开源计算机视觉库)是一个强大的图像和视频处理库,广泛应用于人工智能(AI)、深度学习以及图像分析领域。它的功能包括图像读取、图像显示、图像处理、特征检测、物体识别、人脸...
opencv中cvmat创建矩阵并给矩阵赋值并存储成xml文件,适合初学者,可以进一步了解矩阵的存储。
此外,还涉及了如何将Mat对象转换为旧版本OpenCV使用的IplImage和CvMat格式,以及如何将这些旧格式转为Mat对象。 在数据获取与存储章节,介绍了如何使用OpenCV读写图像文件,包括读取和写入图像、视频文件的操作...
1.1.2 OpenCV 组件及架构.. 5 1.1.3 OpenCV 资源.. 9 1.2 VS2012 安装OpenCV2.4.x .. 9 1.3 VS2013 安装OpenCV3.0 14 1.4 Sublime 下配置OpenCV. 16 1.5 小结 19 第2 章图像及视频基本操作. 20 2.1 图像初级操作 21 ...
对于初学者,"学习OpenCV中文版"这本书将引导你逐步理解OpenCV的基本结构,通过实例教学如何使用OpenCV进行图像处理和计算机视觉任务。书中会涵盖OpenCV的基本函数,以及如何在实际项目中应用这些函数。同时,书中的...
这是OpenCV 2.1版本的官方文档,它详细介绍了该版本的API接口、函数用法和实例。通过这份文档,你可以了解到如何在C++或Python中使用OpenCV的基本操作,如图像读取、显示、颜色空间转换、滤波、边缘检测等。此外,...