elemSize和数量地址总结的接头,图片的几何调换

使用opencv-python1段时间了,因为从前未曾大气触及过c++下的opencv,在网上看c++的有的先后想改成python蒙受了不计其数坑,正幸亏此间总结一下。

opencv-python与c++ opencv中的一些分裂和底蕴的文化,

采取opencv-python1段时间了,因为后面未曾大气触及过c++下的opencv,在网上看c++的片段程序想改成python境遇了众多坑,正幸而此间总计一下。

cv::Mat
depth/dims/channels/step/data/elemSize
The class Mat represents an n-dimensional dense numerical single-channel
or multi-channel array. It can be used to store
(Mat类的靶子用于表示贰个多维度的单通道或许多通道稠密数组,它能够用来囤积以下东西)
real or complex-valued vectors or 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 ) (直方图,北周闵帝度的最好存放在SparseMat中)
旧版本的OpenCV中的C结构体有 CvMat 和 CvMatND,近来本人用的是 2.三版,里面的文书档案建议 CvMat 和 CvMatND 弃用了,在C++封装中用 Mat
替代,别的旧版还有1个 IplImage,同样用 Mat 取代(能够参见博文
OpenCV中的结构体、类与Emgu.CV的对应表).
矩阵 (M) 中数据成分的地点总括公式:
addr(Mi0,i1,…im-1) = M.data + M.step[0] * i0 + M.step[1] * i1 + …

转换

1.opencv 中x,y,height, width,rows,cols 的关系(转自

    opencv中图像的x,y 坐标以及 height, width,rows,cols
他们的涉及平日混淆。

    rows 其实正是行,一行1行也等于y 啦。height高度也正是y啦。

    cols  也等于列,一列一列也正是x啦。width宽度相当于x啦。   

1.opencv 中x,y,height, width,rows,cols 的关系(转自

    opencv中图像的x,y 坐标以及 height, width,rows,cols
他们的涉及平日混淆。

    rows 其实正是行,一行壹行也正是y 啦。height高度也正是y啦。

    cols  也正是列,1列1列也正是x啦。width宽度也正是x啦。   

  • M.step[m-1] * im-1 (其中 m = M.dims M的维度)

OpenCV提供了四个转移函数,cv二.warpAffine和cv二.warpPerspective,通过他们你能够开始展览各个调换,cv二.warpAffine收受二x三的转换矩阵二cv二.warpPerspective承受三x三的转换矩阵做为输入。

二.补给(以下均为原创):

  1. opencv python中的rows
    cols分别为img.shape[0](height)和img.shape[1](width)
  2. opencv c++中的图像对象访问像素可使用.at :cv::mat的积极分子函数:
    .at(int y, int
    x),能够用来存取图像中对应坐标为(x,y)的要素坐标。可是在行使它时要留意,在编写翻译期必须求已知图像的多少类型.但在opencv-python中访问像素可直接运用诸如img[x][y]
    的方法举行落到实处

  原因:和opencv不相同,近期opencv-python中的数组均为numpy array方式。

2.填补(以下均为原创):

  原因:和opencv分化,近日opencv-python中的数组均为numpy array格局。

data:Mat对象中的二个指南针,指向内部存款和储蓄器中存放矩阵数据的1块内部存款和储蓄器 (uchar*
data)
dims:Mat所代表的矩阵的维度,如 三 * 肆 的矩阵为 二 维, 三 * 4 * 5
的为3维
channels:通道,矩阵中的每1个矩阵成分具备的值的个数,比如说 3 * 四矩阵中一共 1贰 个成分,若是各个成分有多少个值,那么就说这么些矩阵是 3通道的,即 channels = 三。常见的是一张彩色图片有红、绿、蓝七个通道。
depth:深度,即每二个像素的位数(bits),在opencv的Mat.depth()中取得的是一个0 – 陆 的数字,分别表示不相同的位数:enum { CV_8U=0, CV_8S=1, CV_16U=2,
CV_16S=3, CV_32S=4, CV_32F=5, CV_64F=6 }; 可见 0和1都代表8位,
2和3都代表16位,4和5代表32位,6代表64位;
step:是一个数组,定义了矩阵的布局,具体见上边图片分析,此外注意 step1(step / elemSize一),M.step[m-1] 总是等于
elemSize,M.step一(m-1)总是等于 channels;
elemSize : 矩阵中每3个成分的数据大小,若是Mat中的数据的数据类型是
CV_8U 那么 elemSize = 1,CV_8UC3 那么 elemSize = 3,CV_1陆UC二 那么
elemSize = 4;记住其它有个 elemSize1 象征的是矩阵中数据类型的轻重缓急,即
elemSize / channels 的大大小小
图片分析1:怀念贰维景况(stored row by row)按行存款和储蓄

缩放

OpenCV有3个函数cv二.resize()来干那些,图片的轻重缓急能够人工钦定,或然您可以钦点缩放因子。有例外的差值格局能够使用,推荐的插值方法是压缩时用cv2.INTEBMWX伍_AREA,放大用cv2.INTER_CUBIC(慢)和cv2.INTER_LINEA凯雷德。默许景况下差值使用cv二.INTE翼虎_LINEA汉兰达。你能够接纳下面二种格局来改动图片大小:

import cv2
import numpy as np

img = cv2.imread(‘messi5.jpg’)
res = cv2.resize(img, None, fx=2, fy=2,
interpolation=cv2.INTER_CUBIC)

#OR

height, width = img.shape[:2]
res = cv2.resize(img, (2*elemSize和数量地址总结的接头,图片的几何调换。width, 2*height),
interpolation=cv2.INTER_CUBIC)

3.函数上的应用的分歧处

  在opencv-python中,有为数不少函数的运用措施都与opencv中分歧,下边轻易的剖析一下最不一样的地点

   一)python中应用cv二.方法名或变量名来调用方法/变量

   2)对于有所同样效果的函数的不等调用方法,例如

 

//c++
cvtColor(srcImg, binaryImg, COLOR_BGR2GRAY);

 

#python
binaryImg = cv2.cvtColor(srcImg,cv2.COLOR_BGR2GRAY)

    当然对于每一种具体的函数的现实性用法,能够自动上网找寻

   三)python中对此变量的种类是不须求注明的,所以将c++中代码修改为python时索要专注多数(缩进尽管很方便查看,可是照旧感到到写{}的感到到很爽23三)

   四)python中等高校函授数参数可以为array情势,所以c++
opencv中的繁多项目都是不设有的,切记使用cv二.类型名()去采用,例如

//c++
circle(srcImg, Point(x, y), 3, Scalar(255, 0, 255), 2, 8, 0);

#python
cv2.circle(srcImg, (x, y), 3, (255, 100, 255), 1, 8, 0)

   别的的小坑估算还多数,多谷歌吧。

3.函数上的选择的区别处

  在opencv-python中,有诸多函数的行使措施都与opencv中差别,下边轻巧的解析一下最不相同的地点

   一)python中选用cv2.方法名或变量名来调用方法/变量

   二)对于具备同等效劳的函数的不及调用方法,例如

 

//c++
cvtColor(srcImg, binaryImg, COLOR_BGR2GRAY);

 

#python
binaryImg = cv2.cvtColor(srcImg,cv2.COLOR_BGR2GRAY)

    当然对于各种具体的函数的求实用法,能够活动上网查找

   三)python中对于变量的档次是不需求注脚的,所以将c++中代码修改为python时需求注意诸多(缩进就算很有益查看,不过照旧认为写{}的痛感很爽23三)

   4)python中等学校函授数参数可感觉array方式,所以c++
opencv中的很多品种都是不设有的,切忌选取cv二.类型名()去行使,例如

//c++
circle(srcImg, Point(x, y), 3, Scalar(255, 0, 255), 2, 8, 0);

#python
cv2.circle(srcImg, (x, y), 3, (255, 100, 255), 1, 8, 0)

   其它的小坑测度还广大,多谷歌(Google)吧。

opencv中的一些分别和基本功的学识,
使用opencv-python一段时间了,因为后边未曾大气触及过c++下的opencv,在网上看c++的部分程序…

 

平移

运动是改动物体的职位。如若你知道在(x, y)方向的变迁是(tx,
ty),你可以创设转变矩阵M:

美高梅开户网址 1

您能够把它成为Numpy的数组,类型是np.float3二的,然后把它传给cv二.warpAffine()函数,下边的例子平移(100,
50):

import cv2
import numpy as np

img = cv2.imread(‘messi5.jpg’, 0)
rows, cols = img.shape

M = np.float32([[1,0,100],[0,1,50]])
dst = cv2.warpAffine(img, M, (cols,rows))

cv2.imshow(‘img’, dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

警告:
cv贰.warpAffine()函数的第二个参数是出口图片的分寸,应该是(width,
height)的款型,记住width=列数,height=行数

地方是3个 三 X 肆 的矩阵,倘若其数据类型为 CV_八U,也正是单通道的 uchar
类型

旋转

对三个图纸旋转3个θ角是经过下边那一个情势的调换矩阵达成的:

美高梅开户网址 2

不过OpenCV提供了可选大旨的缩放旋转,所以你能够按任意点旋转。转变矩阵变为:

美高梅开户网址 3

其中:

美高梅开户网址 4

要找到那么些转换矩阵,OpenCV提供了二个函数,cv贰.getRotationMatrix二D。看下边包车型客车事例,把图纸旋转了90度

img = cv2.imread(‘messi5.jpg’, 0)
rows, cols = img.shape

M = cv2.getRotationMatrix2D((cols/2,rows/2), 90, 1)
dst = cv2.warpAffine(img, M, (cols, rows))

结果:

美高梅开户网址 5

仿射转换

在仿射调换里,所有原始图片里的平行线在出口的图片里照样平行,要找到转变矩阵,大家须求输入图片的四个点,和他们在输出图片里的呼应地方,然后cv二.getAffineTransform会创制3个二x3的矩阵,然后把那么些矩阵传给cv贰.warpAffine.

看下边包车型客车例证,注意自个儿选的三个点(群青的点)

img = cv2.imread(‘drawing.png’)
rows, cols, ch = img.shape

pts1 = np.float32([[50,50],[200,50],[50,200]])
pts2 = np.float32([[10,100],[200,50]美高梅开户网址 ,,[100,250]])

M = cv2.getAffineTransform(pts1, pts2)

dst = cv2.warpAffine(img,M,(cols, rows))

plt.subplot(121), plt.imshow(img), plt.title(‘Input’)
plt.subplot(122), plt.imshow(dst), plt.title(‘Output’)
plt.show()

结果:

那是三个二维矩阵,那么维度为 二 (M.dims == 二);
M.rows == 3; M.cols == 4;
sizeof(uchar) = 壹,那么每三个数量成分大小为 一 (M.elemSize() == 一,
M.elemSize一() == 1);
CV_8U 得到 M.depth() == 0, M.channels() == 1;
因为是二维矩阵,那么 step 数组只有三个值, step[0] 和 step[1]
分别代表壹行的数额大小和二个成分的多少大小,则 M.step[0] == 4,
M.step[1] == 1;
M.step1(0) == M.cols = 4; M.step1(1) == 1;
假设上边的矩阵数据类型是 CV_八UC三,也正是三通道

美高梅开户网址 6

M.dims == 2; M.channels() == 3;M.depth() == 0;
M.elemSize() == 三 (每2个要素包罗3个uchar值) M.elemSize一() == 壹(elemSize / channels)
M.step[0] == M.cols * M.elemSize() == 12, M.step[1] == M.channels()
* M.elemSize1() == M.elemSize() == 3;
M.step(0) == M.cols * M.channels() == 12 ; M.step(1) == M.channels() ==
3;
图片分析2:思索三维情形(stored plane by plane)按面存款和储蓄

透视转变

对于透视调换,你须要2个叁x三的转移矩阵。调换后直线照旧维持直线。要得到这么些转变矩阵,你供给输入图片上的五个点,以及出口图片上相应的点。在那多少个点中,一个不可能同线。然后cv2.getPerspectiveTransform函数就能收获更改矩阵了,再用cv二.warpPerspective来收纳这些三x三的更动矩阵。

代码:

img = cv2.imread(‘sudokusmall.png’)
rows, cols, ch = img.shape

pts1 = np.float32([[56,65],[368,52],[28,387],[389,390]])
pts2 = np.float32([[0,0],[300,0],[0,300],[300,300]])

M = cv2.getPerspectiveTransform(pts1,pts2)

dst = cv2.warpPerspective(img, M,(300,300))

plt.subplot(121), plt.imshow(img), plt.title(‘Input’)
plt.subplot(122), plt.imshow(dst), plt.title(‘Output’)
plt.show()

美高梅开户网址 7

END

 

地方是一个 三 X 4 X 六 的矩阵,要是其数据类型为 CV_16SC4,也就是 short
类型

M.dims == 3 ; M.channels() == 4 ; M.elemSize1() == sizeof(short) == 2
;
M.rows == M.cols == –1;
M.elemSize() == M.elemSize1() * M.channels() == M.step[M.dims-1] ==
M.step[2] == 2 * 4 == 8;
M.step[0] == 4 * 6 * M.elemSize() == 192;
M.step[1] == 6 * M.elemSize() == 48;
M.step[2] == M.elemSize() == 8;
M.step1(0) == M.step[0] / M.elemSize() == 48 / 二 == 九陆(第一维度(即面的要素个数) * 通道数);
M.step1(1) == M.step[1] / M.elemSize() == 1二 / 二 ==
二肆(第一维度(即行的元素个数/列宽) * 通道数);
M.step1(2) == M.step[2] / M.elemSize() == M.channels() ==
4(第三个维度度(即成分) * 通道数);
End :

Author : Ggicci

正文讲授Mat 的有的骨干的初阶化

// m为3*伍的矩阵,float型的单通道,把各类点都开端化为一
Mat m(3, 5, CV_32FC1, 1);
或者 Mat m(3, 5, CV_32FC1, Scalar(1));
cout<<m;
输出为:
[1, 1, 1, 1, 1;
  1, 1, 1, 1, 1;
  1, 1, 1, 1, 1]

// m为3*伍的矩阵,float型的2通道,把每一个点都开端化为一 2
 Mat m(3, 5, CV_32FC2, Scalar(1, 2));
cout<<m;
输出为
[1, 2, 1, 2, 1, 2, 1, 2, 1, 2;
  1, 2, 1, 2, 1, 2, 1, 2, 1, 2;
  1, 2, 1, 2, 1, 2, 1, 2, 1, 2]

// m为3*5的矩阵,float型的三坦途,把各类点都初叶化为一 二 三
Mat m(3, 5, CV_32FC3, Scalar(1, 2, 3));
cout << m;
输出为
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3;
  1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3;
  1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]

// 从已有个别数据源初阶化
double *data = new double[15];
for (int i = 0; i < 15; i++)
{
   data[i] = 1.2;
}
Mat m(3, 5, CV_32FC1, data);
cout << m;
输出为:
[1.2, 1.2, 1.2, 1.2, 1.2;
  1.2, 1.2, 1.2, 1.2, 1.2;
  1.2, 1.2, 1.2, 1.2, 1.2]

设若随着
delete [] data;
cout << m;
输出为:
[-1.456815990147463e+144, -1.456815990147463e+144,
-1.456815990147463e+144, -1.456815990147463e+144,
-1.456815990147463e+144;
  -1.456815990147463e+144, -1.456815990147463e+144,
-1.456815990147463e+144, -1.456815990147463e+144,
-1.456815990147463e+144;
  -1.456815990147463e+144, -1.456815990147463e+144,
-1.456815990147463e+144, -1.456815990147463e+144,
-1.456815990147463e+144]
看得出,这里只是实行了浅拷贝,当数据源不在的时候,Mat里的数据也正是乱码了。

// 从图像开端化
 Mat m = imread(“1.jpg”, CV_LOAD_IMAGE_GRAYSCALE);
 cout<< “channels =”<<m.channels()<<endl;
 cout << “cols =”<<m.cols<<endl;
 cout << “rows =”<<m.rows<<endl;
 cout << m;
输出为:
channels =1
cols =13
rows =12
[179, 173, 175, 189, 173, 163, 148, 190, 68, 14, 19, 31, 22;
  172, 172, 172, 180, 172, 177, 162, 190, 64, 13, 19, 30, 17;
  177, 180, 176, 175, 169, 184, 165, 181, 58, 12, 23, 38, 25;
  181, 183, 178, 178, 170, 181, 163, 182, 52, 8, 23, 37, 23;
  176, 173, 173, 184, 175, 178, 164, 195, 60, 14, 24, 35, 16;
  179, 175, 176, 187, 176, 175, 158, 191, 70, 21, 28, 37, 20;
  182, 183, 180, 184, 174, 179, 155, 174, 54, 1, 5, 15, 2;
  173, 182, 178, 176, 173, 191, 165, 169, 157, 101, 100, 107, 93;
  181, 182, 180, 177, 177, 177, 171, 162, 183, 185, 186, 185, 182;
  178, 180, 179, 177, 178, 179, 174, 167, 172, 174, 175, 174, 172;
  175, 178, 179, 178, 180, 182, 179, 173, 172, 174, 175, 175, 174;
  175, 179, 181, 180, 181, 183, 181, 177, 178, 180, 182, 183, 182]

内容来自《OpenCV 贰 Computer Vision Application Programming Cookbook》

OpenCV贰 拜访图像的次第像素有各类办法

大家来用种种艺术来促成减弱图像的水彩数量

color = color/div*div +div/2;

若div为八,则原来CR-VGB每种通道的25三种颜色减少为3贰种。

若div为64,则原来OdysseyGB每一种通道的25陆种颜色减少为四种,此时3通道全数能代表的颜色有4×4×四= 6肆 种

首先,我们来看二个函数

C++: uchar* Mat::ptr(int i=0)
i 是行号,再次回到的是该行数据的指针。
在OpenCV中,一张三坦途图像的一个像素点是按BG卡宴的顺序存储的。
先来看望第一种访问方案
void colorReduce1(cv::Mat& image, cv::Mat& result, int div=64){
    int nrow = image.rows;
    int ncol = image.cols * image.channels();
    for(int i=0; i<nrow; i++){
        uchar* data = image.ptr<uchar>(i);
        uchar* data_out = result.ptr<uchar>(i);
        for(int j=0; j<ncol; j++){
            data_out[j] = data[j]/div*div +div/2;
        }
    }
}

其次种方案:

先来看如下函数:

C++: bool Mat::isContinuous() const

C++: Mat Mat::reshape(int cn, int rows=0) const

因为图像在OpenCV里的囤积机制难题,行与行之间或许有空落落单元。这一个空白单元对图像来讲是从未意思的,只是为着在少数架构上可以更有效能,比如intel
MMX能够更实用的处理那种4或是八倍数的行。鉴于质量方面的设想,在图像每1行的结尾只怕会填充一些像素,那样图像的数据就不是接二连叁的了

**
小编们能够用函数isContinuous()来推断图像的数额是不是接二连三

reshape函数的成效如下:

Changes the shape and/or the number of channels of a 2D matrix without
copying the data.

如此那般,大家就建议了对第2种方法的立异

void colorReduce2(cv::Mat& image, cv::Mat& result, int div){
    if(image.isContinuous()){
        image.reshape(1,image.cols*image.rows);**

    }
    int nrow = image.rows;
    int ncol = image.cols * image.channels();
    for(int i=0; i<nrow; i++){
        uchar* data = image.ptr<uchar>(i);
        uchar* data_out = result.ptr<uchar>(i);
        for(int j=0; j<ncol; j++){
            data_out[j] = data[j]/div*div +div/2;
        }
    }
}

或:

1 void colorReduce(const Mat& image,Mat& outImage,int div)
 2 {
 3     int nr=image.rows;
 4     int nc=image.cols;
 5     outImage.create(image.size(),image.type());
 6     if(image.isContinuous()&&outImage.isContinuous())
 7     {
 8         nr=1;
 9         nc=nc*image.rows*image.channels();
10     }
11     for(int i=0;i<nr;i++)
12     {
13         const uchar* inData=image.ptr<uchar>(i);
14         uchar* outData=outImage.ptr<uchar>(i);
15         for(int j=0;j<nc;j++)
16         {
17             *outData++=*inData++/div*div+div/2;
18         }
19     }
20 }

*
其二种方案:
先来探望上边的函数
C++: template<typename T> T& Mat::at(int i, int j)
其效用是Returns a reference to the specified array element.
void colorReduce3(cv::Mat& image, cv::Mat& result, int div){
    int nrow = image.rows;
    int ncol = image.cols \
image.channels();
    for(int i=0; i<nrow; i++){
        for(int j=0; j<ncol; j++){
            image.at<cv::Vec3b>(j,i)[0]=
image.at<cv::Vec3b>(j,i)[0]/div*div + div/2;
            image.at<cv::Vec3b>(j,i)[1]=
image.at<cv::Vec3b>(j,i)[1]/div*div + div/2;
            image.at<cv::Vec3b>(j,i)[2]=
image.at<cv::Vec3b>(j,i)[2]/div*div + div/2;
        }
    }
}
第各个方案是利用迭代器
会选拔到如下函数:
C++: template<typename _Tp> MatIterator_<_Tp>
Mat::begin()
C++: MatIterator_<_Tp> Mat::end()
void colorReduce4(cv::Mat& image, cv::Mat& result, int div){
    cv::Mat_<cv::Vec3b>::iterator it =
image.begin<cv::Vec3b>();
    cv::Mat_<cv::Vec3b>::iterator itend =
image.end<cv::Vec3b>();
    cv::Mat_<cv::Vec3b>::iterator itout =
result.begin<cv::Vec3b>();
    for(; it!=itend; ++it,++itout){
        (*itout)[0] = (*it)[0]/div*div + div/2;
        (*itout)[1] = (*it)[1]/div*div + div/2;
        (*itout)[2] = (*it)[2]/div*div + div/2;
    }
}
OpenCV中矩阵数据的走访(贰)(Learning OpenCV第三章3) 

2010-0八-14 二1:四五:1玖|  分类: 科学钻探学习 |字号 订阅
上壹篇小说提到了走访矩阵兰月素的前三种方法,上边讲第三种方法:正确的造访矩阵中多少的办法:

毋庸置疑的法门
前方介绍的有个别读取和写入矩阵数据的方法,实际上,你或然很少会动用它们。因为,在大部状态下,你须要使用最有效能的办法来访问矩阵中的数据。假设应用上述的函数分界面来访问数据,效用相比较低,你应该选拔指针方式来一向访问矩阵中多少。越发是,假诺你想遍历矩阵中具备因素时,就更亟待如此做了。
在用指针直接待上访问矩阵成分时,就必要至极留心矩阵结构体中的step成员。该成员是以字节为单位的每行的长度。而矩阵结构体的cols或width就不合乎此时使用,因为为了访问功用,矩阵中的内部存款和储蓄器分配上,是以每多少个字节做为最小单位的。由此要是二个矩阵的肥瘦是八个字节,那么就会在步长上分红八个字节,而那时每行最终一个字节会被忽略掉。所以大家用step则会准确地按行访问数据。
我们得以因而以下例子,看一下rows,cols,height,width,step的多寡,你能够经过改换矩阵的成分类型定义,来查看step的改变:
#pragma comment(lib,”cxcore.lib”)
#include”cv.h”
#include<stdio.h>
void main()
{
    //矩阵元素为③通道伍位浮点数
    CvMat *mat=cvCreateMat(3,3,CV_32FC3 );
    printf(“rows=%d,cols=%d,height=%d,width=%d,step=%d\n”,mat->rows,mat->cols,mat->height,mat->width,mat->step);

}
1旦大家的矩阵存储的是浮点型(或整数类型)数据,此时矩阵中每一种成分占四字节,则只要大家用float类型指针指向下一行时,大家实际上要用float类型指针挪动step/4的尺寸,因为float类型指针每挪动四个单位正是四个字节长度。
假若咱们的矩阵存款和储蓄的是double类型数据,此时矩阵中各样成分占捌字节,则只要大家用double类型指针指向下一行时,我们其实要用double类型指针挪动step/八的长度,因为double类型指针每挪动贰个单位正是7个字节长度。
大家重新看一下CvMat类型的数据结构定义,个中,data就是多少部分,指向data的指针能够是各样数据类型的:
typedef struct CvMat {
    int type;
    int step;
    int* refcount;     // for internal use only
    union {
         uchar* ptr;
         short* s;
         int*    i;
         float* fl;
         double* db;
    } data;//数据部分
    union {
         int rows;
         int height;
    };
    union {
         int cols;
         int width;
    };
} CvMat;

我们能够通过为矩阵赋值,和读取的例子,查看怎么样利用step:
#pragma comment(lib,”cxcore.lib”)
#include”cv.h”
#include<stdio.h>
void main()
{
    //矩阵成分为三通道六人浮点数
    CvMat *mat=cvCreateMat(3,3,CV_32FC3 );
    float *p;
    int row,col;
    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;
        }
    }

    for(row = 0; row < mat->rows; row++)
    {
        p = mat->data.fl + row * (mat->step/4);
        for(col = 0; col < mat->cols; col++)
        {
            printf(“%f,%f,%f\t”,*p,*(p+1),*(p+2));
            p+=3;
        }
        printf(“\n”);
    }
}

假诺大家使用的指针类型为uchar*类型,则事情恐怕会轻易一些,不用思量step/四,step/八等类似景况,大家引入用那种方法。如下例所示:

#pragma comment(lib,”cxcore.lib”)
#include”cv.h”
#include<stdio.h>
void main()
{
    //矩阵成分为3通道8人浮点数
    CvMat *mat=cvCreateMat(3,3,CV_32FC3 );
    float *p;
    int row,col;
    for(row=0; row< mat->rows; row++)
    {
        p = (float*)(mat->data.ptr + row * mat->step);
        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;
        }
    }

    for(row = 0; row < mat->rows; row++)
    {
        p = (float*)(mat->data.ptr + row * mat->step);
        for(col = 0; col < mat->cols; col++)
        {
            printf(“%f,%f,%f\t”,*p,*(p+1),*(p+2));
            p+=3;
        }
        printf(“\n”);
    }
}

谈起底要留意一下,我们在每行都要使用step重新总计一下指南针的任务,那好象不如从首指针从头到尾一贯指下去,如大家上一稿子的事例同样


#pragma comment( lib, “cxcore.lib” )
#include “cv.h”
#include <stdio.h>
void main()
{
    //矩阵成分为3通道浮点数
    CvMat* mat = cvCreateMat(3,3,CV_32FC3);
    cvZero(mat);//将矩阵置0
    //为矩阵成分赋值

    //获得矩阵成分(0,0)的指针
    float *p = (float*)cvPtr2D(mat, 0, 0);
    //为矩阵赋值
    for(int i = 0; i < 9; i++)
    {
        //为每一种通道赋值
        *p = (float)i*10;   
        p++;
        *p = (float)i*10+1;
        p++;
        *p = (float)i*10+2;
        p++;
    }

    //打字与印刷矩阵的值
    p =  (float*)cvPtr2D(mat, 0, 0);

    for(i = 0; i < 9; i++)
    {
        printf(“%2.1f,%2.1f,%2.1f\t”,*p,*(p+1),*(p+2));
        p+=3;
        if((i+1) % 3 == 0)
            printf(“\n”);
    }
}

可是毫无疑问要注意了,那几个例子其实是有有失水准态的!因为我们说过,分配矩阵内部存款和储蓄器空间时,是以四字节为最小单位的,那就很有不小或然有不到几个字节而取成八个字节的处境,所以,假设用矩阵首地址从头到尾指下去访问数据,就很有相当的大可能率拜会到不是数码的字节上去!那或多或少请务必牢记!!
综述,假若要直接待上访问矩阵中多少,请牢记使用step的方案。

另叁个急需知道的情事是,大家须要驾驭三个多维数组(矩阵)和3个一维,不过蕴涵高维数据的数组之间的区分。假如,你有n个点(各样点有x,y,z坐标值)必要保留到CvMat*中,你实际有多种方法得以行使,但那种种办法的贮存格局差异。你大概行使3个贰维矩阵,矩阵大小为n行三列,数据类型为CV3二FC一。你还足以使用八个2维矩阵,矩阵大小为三行n列,数据类型为CV32FC一;第二种恐怕是,你利用一个1维矩阵,n行一列,数据类型为CV32FC三;最后,你还足以选用一行三列,数据类型为CV3二FC三.那两种格局,在内部存款和储蓄器分配上,有个别是1律的,有些是例外的,如下所示:

n个点的集合(n=伍);
(x0 y0 z0) (x1 y1 z1) (x2 y2 z2) (x3 y3 z3) (x4 y4 z4)

n行1列时(数据类型CV3二FC3)内部存款和储蓄器分配境况
x0 y0 z0 x1 y1 z1 x2 y2 z2 x3 y3 z3 x4 y4 z4

1行n列时(数据类型CV3二FC三)内部存款和储蓄器分配境况
x0 y0 z0 x1 y1 z1 x2 y2 z2 x3 y3 z3 x4 y4 z4

n行三列时(数据类型CV3贰FC一)内部存款和储蓄器分配景况
x0 y0 z0 x1 y1 z1 x2 y2 z2 x3 y3 z3 x4 y4 z4

三行n列时(数据类型CV32FC一)内部存款和储蓄器分配情形
x0 x1 x2 x3 x4 y0 y1 y2 y3 y4 z0 z1 z2 z3 z4

我们得以见到,前两种的内部存储器分配意况同样,但最终1种的内部存款和储蓄器分配分裂。更扑朔迷离的是,假设有n维数组,每一个数组的要素是c维(c也许是通道数)时。所以,多维数组(矩阵)和三个一维但含有多维数据的数组1般是差别的。

对此三个Rows行Cols列,通道数为Channels的矩阵,访问个中第row行,第col列,第channel通路的多少,能够采用如下公式:
多少地址偏移量=row*Cols*Channels+col*Channels+channel**

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图