penCV isContinuous()连续存储的问题

转置:(221条消息) OpenCV isContinuous()连续存储的问题_pan_jinquan的博客-CSDN博客

 

 

OpenCV isContinuous()连续存储的问题

pan_jinquan

于 2017-11-23 20:15:19 发布

10126
收藏 18
分类专栏: OpenCV 文章标签: isContinuous Mat图像连续存储 OpenCV isContinuous
版权

OpenCV
专栏收录该内容
33 篇文章28 订阅
订阅专栏
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()一份后又连续了.

————————————————
版权声明:本文为CSDN博主「pan_jinquan」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/guyuealian/article/details/78614662

posted @ 2022-02-28 19:48  梅长苏枫笑  阅读(108)  评论(0编辑  收藏  举报