OpenCV isContinuous()连续存储的问题

来源:互联网 发布:局域网音频传输软件 编辑:程序博客网 时间:2024/06/13 18:27

OpenCV isContinuous()连续存储的问题

尊重原创,转载请注明出处】http://blog.csdn.net/guyuealian/article/details/78614662

一、OpenCV isContinuous()函数

定义:
bool cv::Mat::isContinuous() const

说明:
     报告矩阵是否连续。
     如果矩阵元素在每行末尾连续存储而没有间隙,则方法返回true。 否则,它返回false。 显然,对于1x1或1xN矩阵总是连续的。一般 用Mat :: create创建的矩阵总是连续的。 但是,如果使用Mat :: col,Mat :: diag等提取矩阵的一部分,或者为外部分配的数据构造矩阵头,则此类矩阵可能不再具有此属性。
     连续性标志存储在Mat :: flags字段中,并在构造矩阵标题时自动计算。 因此,连续性检查是一个非常快的操作,虽然理论上可以这样做:
// alternative implementation of Mat::isContinuous()bool myCheckMatContinuity(const Mat& m){    //return (m.flags & Mat::CONTINUOUS_FLAG) != 0;    return m.rows == 1 || m.step == m.cols*m.elemSize();//检测内存存储连续性}
    这个isContinuous方法在很多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());    // here is the idiom: check the arrays for continuity and,    // if this is the case,    // treat the arrays as 1D vectors    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++ )    {        // when the arrays are continuous,        // the outer loop is executed only once        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存储一幅图像时,若图像在内存中是连续存储的(Mat对象的isContinuous == true),则可以将图像的数据看成是一个一维数组,而data(uchar*)成员就是指向图像数据的第一个字节的,因此可以用data指针访问图像的数据,从而加速Mat图像的访问速度。

     一般经过裁剪的Mat图像,都不再连续了,如cv::Mat crop_img = src(rect);crop_img 是不连续的Mat图像,如果想转为连续的,最简单的方法,就是将不连续的crop_img 重新clone()一份给新的Mat就是连续的了,如:

Mat src = imread("D:\\OpencvTest\\B1.jpg");//原始图像是200*200  cv::imshow("src", src);printf("---src.isContinuous=%d", src.isContinuous());printf("\n");//直接imread的Mat是连续的cv::Rect rect(1, 1, 100, 100);cv::Mat crop_img = src(rect);//裁剪后的图像是不连续的cv::imshow("crop_img", crop_img);printf("---crop_img.isContinuous=%d", crop_img.isContinuous());printf("\n");cv::Mat crop_img2;//crop_img2.create(crop_img2.size(), crop_img2.type());crop_img2 = crop_img.clone();//重新clone()后的图像是连续的printf("---crop_img2.isContinuous=%d", crop_img2.isContinuous());printf("\n");
运行结果:显然,裁剪后的Mat图像不再连续,而重新clone()一份后又连续了.