• OpenCV点滴3


    这段时间想稍微系统地学下:

    转自:http://blog.csdn.net/giantchen547792075/article/details/9107877

    1、Mat-基本图像容器:

    • OpenCV函数中输出图像的内存分配是自动完成的(如果不特别指定的话)。
    • 使用OpenCV的C++接口时不需要考虑内存释放问题。
    • 赋值运算符(=)和拷贝构造函数( Mat A,Mat B(A) )只拷贝信息头。
    • 使用函数 clone() 或者 copyTo() 来拷贝一副图像的矩阵。

      Mat M(2,2, CV_8UC3, Scalar(0,0,255));

      行数,列数,8位,3通道,指定的值初始化;

    Mat::eye

    返回一个恒等指定大小和类型矩阵。

    C++: static MatExpr Mat::eye(int rows, int cols, inttype)

    C++: static MatExpr Mat::eye(Size size, int type)

    参数

    rows –的行数。

    cols– 的列数。

    size –替代矩阵大小规格Size(cols, rows)的方法。

    type – 创建的矩阵的类型。

    该方法返回 Matlab 式恒等矩阵初始值设定项,类似 Mat::zeros()和 Mat::ones(),你可以用缩放操作高效地创建缩放的恒等矩阵:

    / / 创建4 x 4 的对角矩阵并在对角线上以0.1的比率缩小。

    Mat A = Mat::eye(4, 4, CV_32F)*0.1;

    Mat::create

    分配新的阵列数据 (如果需要)。

    C++: void Mat::create(int rows, int cols, int type)

    C++: void Mat::create(Size size, int type)

    C++: void Mat::create(int ndims, const int* sizes, inttype)

    参数

    ndims – 新数组的维数。

    rows –新的行数。

    cols – 新的列数。

    size – 替代新矩阵大小规格:Size(cols, rows)。

    sizes – 指定一个新的阵列形状的整数数组。

    type – 新矩阵的类型。

    这是关键的Mat方法之一。大多数新样式 OpenCV 函数和产生阵列的方法每个输出数组都调用这个方法。此方法使用如下算法

    1.如果当前数组形状和类型匹配新的请立即返回。否则,通过调用 Mat::release()取消引用以前的数据。

    2.初始化新矩阵头。

    3.分配新的 total()*elemSize() 个字节的数据空间。

    4.分配新的关联数据的引用计数并将其设置为 1。

    这项计划使内存管理强大高效同时还为用户减少了额外输入。这意味着通常不需要显式分配输出数组。也就是说,可以不写成:

    Mat color;

    ...

    Mat gray(color.rows, color.cols,color.depth());

    cvtColor(color, gray, CV_BGR2GRAY);

    而写成:

    Mat color;

    ...

    Mat gray;

    cvtColor(color, gray, CV_BGR2GRAY);

    因为 cvtColor,与大多数 OpenCV 函数相同,在输出数组时内部调用Mat::create()。

    Mat::addref

    计数器参考。

    C++: void Mat::addref()

    该方法递增与矩阵数据关联的引用计数。如果矩阵头指向外部的数据集(见 Mat::Mat()),则引用计数为 NULL,并且该方法在这种情况下不起作用。通常情况下,为避免内存泄漏,不应显式调用该方法。它是由该矩阵赋值运算符隐式调用。在支持的它平台上,引用计数器递增是一个原子操作。因此,对相同的矩阵,在不同的线程异步操作是安全的。

    Mat::release

    在必要的情况下,递减引用计数并释放该矩阵。

    C++: void Mat::release()

    该方法递减与矩阵的数据关联的引用计数。当引用计数减为0时,矩阵的数据将被释放,数据和引用计数器指针设置为 NULL。如果矩阵头指向外部数据集 (见 Mat::Mat()), 引用计数为 NULL,并且该方法在这种情况下无效。

    可以手动调用此方法强制矩阵数据释放。但由于这种方法在析构函数中是自动调用的,或以更改数据指针的其他方法,因此通常不需要调用这个函数。在支持它的平台上,引用计数器递减并检查是否为0 是一个原子操作。因此,在不同的线程异步调用相同的矩阵是安全的操作。

    Mat::resize

    更改矩阵的行数。

    C++: void Mat::resize(size_t sz)

    C++: void Mat::resize(size_t sz, const Scalar& s)

    参数

    sz –新的行数。

    s –分配给新添加的元素的值。

    该方法更改矩阵的行数。如果矩阵重新分配,第一最少(Mat::rows,sz) 行数要保留下来。该方法模拟相应的 STL 向量类的方法。

    Mat::reserve

    保留一定数量的行的空间。

    C++: void Mat::reserve(size_t sz)

    参数

    sz –的行数。

    该方法sz行存储空间。如果矩阵已经有足够的空间来存储sz行,没有任何异常发生。如果矩阵重新分配,保留前(Mat::rows) 行。该方法模拟了相应的STL 向量类的方法。

    Mat::push_back

    将元素添加到矩阵的底部。

    C++: template<typename T> voidMat::push_back(const T& elem)

    C++: void Mat::push_back(const Mat& elem)

    参数

    elem –增加的一个或多个元素。

    该方法将一个或多个元素添加到矩阵的底部。他们是模拟相应的 STL 向量类的方法。元素为Mat时,其类型和列的数目必须和矩阵容器是相同的。

    Mat::pop_back

    从底部的列表中删除元素。

    C++: template<typename T> voidMat::pop_back(size_t nelems=1)

    参数

    nelems –删除的行的数目。如果它大于总的行数,则会引发异常。

    该方法从底部的列表中删除一行或多行。

    Mat::locateROI

    父矩阵内定位矩阵头。

    C++: void Mat::locateROI(Size& wholeSize,Point& ofs) const

    参数

    wholeSize–输出参数,其中包含的整个矩阵包含大小 * 这是其中一部分。

    ofs –输出参数包含*this在整个的矩阵里面的偏移量。你使用Mat::row()、 Mat::col()、 Mat::rowRange()、Mat::colRange()以及其他的方法从矩阵中提取子阵后该结果子阵只指向原始大矩阵的一部分。然而,每个子阵包含有助于重建的最初矩阵大小和提取子阵在原始矩阵中的位置信息(由 datastart 和 dataend fields表示)。locateROI方法正是这样做的。

    Mat::adjustROI

    调整子阵大小及其在父矩阵中的位置。

    C++: Mat& Mat::adjustROI(int dtop, int dbottom,int dleft, int dright)

    参数

    dtop –顶部子阵边界向上的平移量。

    dbottom –底部子阵边界向下的平移量。

    dleft –左子阵边界向左的平移量。

    dright –右子阵边界向右的平移量。

    该方法是 Mat::locateROI() 的互补性方法。这些函数的典型应用是确定父矩阵中子阵的位置,然后以某种方式改变位置。尤其典型的是,当滤镜操作中要考虑ROI外的像素时就需要它。当方法的所有参数都是正的时候,ROI需要以指定量全方位增长,例如:

    A.adjustROI(2, 2, 2,2);

    在此示例中,每个方向 4 元素增加矩阵大小。矩阵向左侧和上侧分别平移2 个元素,这会产生5 x 5 内核的滤镜所需的所有像素。你的责任是确保 adjustROI 不超出父矩阵边界。如果超出,该函数发出错误提示。OpenCV的滤镜函数在内部调用该函数,像filter2D(),形态学的操作,等等。

    另请参阅:

    copyMakeBorder()

    Mat::operator()

    提取矩形子阵。

    C++: Mat Mat::operator()(Range rowRange, RangecolRange) const

    C++: Mat Mat::operator()(const Rect& roi) const

    C++: Mat Mat::operator()(const Ranges* ranges) const

    参数:

    rowRange –提取的子阵的开始和结束的行。不包括的上限。若要选择的所有行,请使用 Range::all()。

    colRange –提取的子阵的开始和结束的列。不包括的上限。若要选择的所有列,请使用 Range::all()。

    roi – 抽出子阵 specified 作为一个矩形。

    ranges – 选定范围沿每个数组维度的数组。

    该运算符为*this的子数组创建新的头。他们是Mat::row()、 Mat::col()、 Mat::rowRange(),和Mat::colRange()最普遍的形式。例如,A(Range(0, 10),Range::all()) 是相当于A.rowRange(0, 10)。与上述所有操作相同,该操作运算符是复杂度为O(1)的操作,就是没有矩阵数据将被复制。

    Mat::operator CvMat

    创建矩阵 CvMat 头。

    C++: Mat::operator CvMat() const

    该运算符创建矩阵 CvMat 的头,而不复制的基础数据。引用计数未被考虑到此操作中。因此,您应该确保CvMat 头在使用的时候不释放原始矩阵。该运算符对于新旧OpenCV API混用是有用的,例如:

    Mat img(Size(320, 240), CV_8UC3);

    ...

    CvMat cvimg = img;

    mycvOldFunc( &cvimg, ...);

    其中 mycvOldFunc 是用于OpenCV 1.x 数据结构的函数。

    Mat::operator IplImage

    创建IplImage矩阵头。

    C++: Mat::operator IplImage() const

    运算符创建矩阵 IplImage 头,而不复制的基础数据。您应该确保使用IplImage头时不释放原矩阵。与Mat::operatorCvMat类似,该运算符在OpenCV新旧API混用中很有用。

    Mat::total

    返回数组元素的总数。

    C++: size_t Mat::total() const

    该方法返回数组元素(如果该数组表示图像的像素数)的数目。

    Mat::isContinuous

    返回矩阵是否连续。

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

    如果在每一行的结尾无间隙连续存储矩阵的元素,该方法返回 true。否则,它将返回 false。很明显,1 x 1 或 1xN 矩阵始终是连续的。使用 Mat::create() 创建矩阵是始终是连续的。但是,如果您提取的矩阵,使用 Mat::col()、 Mat::diag(),等等,或外部已分配的数据构造的矩阵头的一部分,那么这种矩阵可能不再具有此属性。连续性标记在Mat::flags域内用一个位存储,构造矩阵头时可以自动计算出来。因此,连续性检查是非常快速的操作,虽然理论上可以做,如下所示:

    / / 等价的Mat::isContinuous() 的执行情况

    boolmyCheckMatContinuity(const Mat& m)

    {

    //返回 (m.flags & Mat::CONTINUOUS_FLAG) != 0;

    return m.rows ==1 || m.step == m.cols*m.elemSize();

    }

    很多的OpenCV 函数中使用该方法。关键在于按元素操作(如算术和逻辑运算、 数学函数、 alpha 融合、颜色空间转换,以及其他) 不依赖于图像的几何形状。因此,如果所有的输入和输出的阵列是连续的,该函数可以它们作为很长的单行的向量处理。下面的示例阐释了如何实现 alpha 融合功能。

    template<typename T>

    void alphaBlendRGBA(const Mat& src1,const Mat& src2, Mat& dst)

    {

    const float alpha_scale =(float)std::numeric_limits<T>::max(),

    inv_scale = 1.f/alpha_scale;

    CV_Assert( src1.type() == src2.type()&&

    src1.type() ==CV_MAKETYPE(DataType<T>::depth, 4) &&

    src1.size() == src2.size());

    Size size = src1.size();

    dst.create(size, src1.type());

    // 规定如下: 检查阵列的连续性

    //如果的确如此,阵列连续

    // 把阵列看做一维的向量。

    if( src1.isContinuous() &&src2.isContinuous() && dst.isContinuous() )

    {

    size.width *= size. height;

    size.height = 1;

    }

    size.width *= 4;

    for( int i = 0; i < size.height; i++ )

    {// 当阵列连续,

    // 外循环只执行一次

    const T* ptr1 = src1.ptr<T>(i);

    const T* ptr2 = src2.ptr<T>(i);

    T* dptr = dst.ptr<T>(i);

    for( int j = 0; j < size.width; j += 4 )

    {

    float alpha = ptr1[j+3]*inv_scale, beta =ptr2[j+3]*inv_scale;

    dptr[j] =saturate_cast<T>(ptr1[j]*alpha + ptr2[j]*beta);

    dptr[j+1] =saturate_cast<T>(ptr1[j+1]*alpha + ptr2[j+1]*beta);

    dptr[j+2] =saturate_cast<T>(ptr1[j+2]*alpha + ptr2[j+2]*beta);

    dptr[j+3] = saturate_cast<T>((1 -(1-alpha)*(1-beta))*alpha_scale);

    }

    }

    }

    这种方法,不仅很简单,而且在简单的元素的操作中可以提高10-20%性能,尤其在图像很小且操作非常简单的时候。

    在此函数中另一个 OpenCV 语法,目标数组中Mat::create() 的调用会对没有适当大小和类型的目标数组分配空间。虽然新分配的数组始终是连续的,但您仍需要检查目标数组,因为 Mat::create()不是总会分配一个新的矩阵。

    Mat::elemSize

    返回矩阵元素大小 (以字节为单位)。

    C++: size_t Mat::elemSize() const

    该方法返回以字节为单位的矩阵元素大小。例如,如果矩阵类型是 CV_16SC3,该方法返回3*sizeof(short)或 6。

    Mat::elemSize1

    以字节为单位返回每个矩阵元素通道的大小。

    C++: size_t Mat::elemSize1() const

    该方法返回以字节为单位的矩阵元素通道大小,也就是忽略通道的数量。例如,

    如果矩阵类型是 CV_16SC3,该方法返回 sizeof(short) 或 2。

    Mat::type

    返回一个矩阵元素的类型。

    C++: int Mat::type() const

    该方法返回一个矩阵的元素类型。这是兼容CvMat 类型系统,像 CV_16SC3标识符

    或 16 位有符号的3 通道阵列,等等。

    Mat::depth

    返回一个矩阵元素的深度。

    C++: int Mat::depth() const

    该方法返回矩阵元素深度(每个单独的通道类型)的标识符。例如,对于16位有符号的3通道数组,该方法返回CV_16S。矩阵类型的完整列表包含以下内容值:

    • CV_8U-8 位无符号整数 (0…..255)

    • CV_8S-8 位符号整数 (-128…..127)

    • CV_16U-16 位无符号整数 (0……65535)

    • CV_16S-16 位符号整数 (-32768…..32767)

    • CV_32S-32 位符号整数 (-2147483648……2147483647)

    • CV_32F-32 位浮点数 (-FLT_MAX ………FLT_MAX,INF,NAN)

    • CV_64F-64 位浮点数(-DBL_MAX ……….DBL_MAX,INF,NAN)

    Mat::channels

    返回矩阵通道的数目。

    C++: int Mat::channels() const

    该方法返回矩阵通道的数目。

    Mat::step1

    返回矩阵归一化迈出的一步。

    C + +: size_t const Mat::step1()

    该方法返回以矩阵的step除以Mat::elemSize1()。它对快速访问任意矩阵元素很有用。

    Mat::size

    返回一个矩阵大小。

    C++: Size Mat::size() const

    该方法返回一个矩阵大小:Size(cols, rows)。矩阵超过 2 维时返回大小为(-1,-1)。

    Mat::empty

    如果数组有没有 elemens,则返回 true。

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

    如果 Mat::total() 是 0 或 Mat::data 为 NULL,则方法返回 true。因为pop_back() 和 resize()方法M.total()= = 0,并不意味着M.data = =NULL。

    Mat::ptr

    返回指定矩阵行的指针。

    C++: uchar* Mat::ptr(int i=0)

    C++: const uchar* Mat::ptr(int i=0) const

    C++: template<typename _Tp> _Tp* Mat::ptr(inti=0)

    C++: template<typename _Tp> const _Tp*Mat::ptr(int i=0) const

    参数:

    i –一个基于0的行索引。

    该方法返回uchar*,或指向由输入指定矩阵行的指针。参看Mat::isContinuous()的中示例了解如何使用这些方法。

    Mat::at

    返回对指定数组元素的引用。

    C++: template<typename T> T& Mat::at(int i)const

    C++: template<typename T> const T&Mat::at(int i) const

    C++: template<typename T> T& Mat::at(int i,int j)

    C++: template<typename T> const T&Mat::at(int i, int j) const

    C++: template<typename T> T& Mat::at(Pointpt)

    C++: template<typename T> const T&Mat::at(Point pt) const

    C++: template<typename T> T& Mat::at(int i,int j, int k)

    C++: template<typename T> const T&Mat::at(int i, int j, int k) const

    C++: template<typename T> T& Mat::at(constint* idx)

    C++: template<typename T> const T&Mat::at(const int* idx) const

    参数

    i –索引 0 维度

    j – 1 维度的索引

    k – 沿 2 维度的索引

    pt – Point(j,i) 作为指定元素的位置。

    idx – Mat::dims 数组的索引。

    该模板方法返回指定数组元素的引用。为了具有更高的性能,索引范围检查只在调试配置下执行。请注意使用具有单个索引 (i) 的变量可以访问的单行或单列的2 维的数组元素。也就是比方说,如果A是1 x N 浮点矩阵和B是M x 1的整数矩阵,您只需编写A.at<float>(k+4) 和 B.at<int>(2*i+1) 分别代替A.at<float>(0,k+4)和

    B.at<int>(2*i+1,0)。

    下面的示例将初始化希尔伯特矩阵:

    Mat H(100, 100, CV_64F);

    for(inti=0; i<H.rows; i++)

    for(intj=0; j<H.cols; j++)

    H.at<double>(i,j)=1./(i+j+1);

    Mat::begin

    返回矩阵迭代器,并将其设置为第一矩阵元。

    C++: template<typename _Tp>MatIterator_<_Tp> Mat::begin()

    C++: template<typename _Tp>MatConstIterator_<_Tp> Mat::begin() const

    该方法返回矩阵的只读或读写的迭代器。矩阵迭代器的使用和双向 STL 迭代器的使用是非常相似的。在下面的示例中,alpha融合函数是使用矩阵迭代器重写:

    template<typename T>

    void alphaBlendRGBA(const Mat& src1,const Mat& src2, Mat& dst)

    {

    typedef Vec<T, 4> VT;

    const float alpha_scale =(float)std::numeric_limits<T>::max(),

    inv_scale = 1.f/alpha_scale;

    CV_Assert( src1.type() == src2.type()&&

    src1.type() == DataType<VT>::type&&

    src1.size() == src2.size());

    Size size = src1.size();

    dst.create(size, src1.type());

    MatConstIterator_<VT> it1 =src1.begin<VT>(), it1_end = src1.end<VT>();

    MatConstIterator_<VT> it2 =src2.begin<VT>();

    MatIterator_<VT> dst_it =dst.begin<VT>();

    for( ; it1 != it1_end; ++it1, ++it2,++dst_it )

    {

    VT pix1 = *it1, pix2 = *it2;

    float alpha = pix1[3]*inv_scale, beta =pix2[3]*inv_scale;

    *dst_it =VT(saturate_cast<T>(pix1[0]*alpha + pix2[0]*beta),

    saturate_cast<T>(pix1[1]*alpha + pix2[1]*beta),

    saturate_cast<T>(pix1[2]*alpha +pix2[2]*beta),

    saturate_cast<T>((1 -(1-alpha)*(1-beta))*alpha_scale));

    }

    }

    Mat::end

    返回矩阵迭代器,并将其设置为 最后元素之后(after-last)的矩阵元。

    C++: template<typename _Tp>MatIterator_<_Tp> Mat::end()

    C++: template<typename _Tp>MatConstIterator_<_Tp> Mat::end() const

    该方法返回矩阵只读或读写的迭代器,设置为紧随最后一个矩阵元素的点。



    Point2f P(5,1) -->[5,1]

    2、image有400行,有400*600个像素。得到第3行第42个像素的指针:uchar * data = image.ptr<uchar>(3)[42];

    3、 cv::Mat image = cv::Mat(400, 600, CV_8UC3); //宽400,长600,3通道彩色图片

  • 相关阅读:
    Fedora 14 安装完后的设置 添加源 更新软件
    visual studio NuGet 常用包管理命令
    ubuntu通过cifs-utils访问Windows共享目录
    C# 数据库写入Sql Bulk索引损坏异常问题System.InvalidOperationException: DataTable internal index is corrupted: '4'
    C# IEnumerable to List 的转换
    python 端口扫描
    ubuntu 关闭 phpmyadmin
    zendframework 初始化配置
    zend-form笔记
    DirectX 图形流水线
  • 原文地址:https://www.cnblogs.com/wuxiaotianC/p/6359623.html
Copyright © 2020-2023  润新知