IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> Opencv meanStdDev mean函数详解 -> 正文阅读

[人工智能]Opencv meanStdDev mean函数详解

阅读了一下Opencv求均值和标准差的源码,总结下来,愿渡有缘人。

meanStdDev 函数在mean.dispatch.cpp中实现,计算均值和方差的公式如下:

?

meanStdDev这个函数的输入是src和mask,mask矩阵里为0位置的元素不被求和if( mask[i] ){才求和};

这个函数的输出也是两个矩阵,这个输出矩阵的维数应该是channels * 1,每个通道存储相应的和(sum)或平方和(sqsum),如果空间太大,后面的空间会被设置为0.

?下面先说一下要理解这个函数的一些先决条件:

(1)NAryMatIterator类:这是一个N元矩阵迭代器,这个迭代器可同步处理多个矩阵,常用在处理src和mask的情况。每个NAryMatIterator::pannels是一个连续的地址空间,pannels是整体矩阵的切片。不连续的地址空间出现在如Mat(src, Rect(1, 1, 3, 3))的情况。就是用Rect截取了src矩阵的一部分,这个部分矩阵的地址空间不连续。

也有很多人写了关于这个类的详解,但是最终还是看源码上的注释才懂了的。

(2)这个函数调用了一个求和、求平方和的函数

static int sqsum8u(const uchar* src, const uchar* mask, int* sum, int* sqsum, int len, int cn)

是通过getSumSqrFunc()获取一个函数数组得到的。

这个函数的输入是src,mask

输出是:没有被mask的元素的和(保存在sum所指的变量内)、元素的平方和(保存在sqsum)

返回值:处理元素的长度len

如果src是多个通道,sum[0],sum[1]分别存储相应通道的和

(3)AutoBuffer:这个类简单,就相当于new

(4)这个函数里OCL/OVX/IPP:和图形加速、GPU相关,Opencv编译的时候应该没有使能这些选项,我也没有细究这些,高人可以补充一下。

(5)CV_INSTRUMENT_REGION():这个宏Opencv里随处可见,我也没有细究,应该是标识下面的代码在链接过程应该放在哪个段内。(放在.code的指令区段内)

正题,解释一下这个函数内使用的变量的含义和难懂的语句:

(1)total:每个pannels的尺寸大小,这个是Pannels的总大小。

(2)blockSize:每次处理的元素个数,被初始化为total

(3)_buf(cn*4):如果有3个通道,则对于通道一,使用_buf[0,3,6,9],通道二使用_buf[1,4,7,10]

其中_buf[0]保存最终的sum,_buf[3]保存最终的sqsum。_buf[6]和_buf[9]保存临时的sum和sqsum。

(4)intSumBlockSize:求和的时候,处理的元素个数超过intSumBlockSize的大小,就将求和的结果加到_buf[0],intSumBlockSize被初始化为1<<15。这个值不能太大,否则求得的sum会超过int类型表示的范围。

(5)?bool?blockSum = depth <= CV_16S:

? ? ? ? ??bool?blockSqSum = depth <= CV_8S:

这两条语句主要是因为求均值,那么元素大小不能超过2个字节,否则图像加起来会超过double(8字节)所能表示的范围;要计算方差,元素不能超过1字节,否则不计算方差。

正常情况这两个变量的值都应该为true

(6)?int nz = func( ptrs[0], ptrs[1], (uchar*)sbuf, (uchar*)sqbuf, bsz, cn );

sbuf存储cn个通道的sum,sqbuf存储cn个通道的sqsum,返回处理元素的个数: nz = bsz

(7)if( blockSum && (count + blockSize >= intSumBlockSize || (i+1 >= it.nplanes && j+bsz >= total)) ){}

count为已经处理了的元素个数:已经处理的元素个数不能超过intSumBlockSize,因为sqsum8u返回的和是int类型的。(func就是static int sqsum8u( const uchar* src, const uchar* mask, int* sum, int* sqsum, int len, int cn ))

这里count + blockSize的意思是,如果马上要满了,下次循环处理的元素个数就超了intSumBlockSize,就把求得的和保存一下,保存到_buf[0]里面,这个变量是double类型的,所以足够存储一副图像的sum。

(8)nz0:count的值在处理的元素个数马上超过intSumBlockSize的时候就会清零,而nz0不会,nz0保存所有的处理过的元素个数。

(9)ptrs[0] += bsz*esz;
? ? ? ? ? ? if( ptrs[1] )
? ? ? ? ? ? ? ? ptrs[1] += bsz;

最初ptrs[0]指向第一个Pannels数据的首地址,ptrs[0] += bsz*esz就是指针在本Pannel内向后移动bsz*esz个字节。(因为ptrs[0]的类型是char *型)

ptrs[1] += bsz;不乘esz是因为如果要计算方差,元素必须是占1个字节

(10)后面的代码就简单了,就是先求均值和方差,然后通过一个2遍的for循环将计算值保存到输出参数内,for循环第一遍保存均值;第二遍保存标准差。

附上源码:


void meanStdDev(InputArray _src, OutputArray _mean, OutputArray _sdv, InputArray _mask)
{
    CV_INSTRUMENT_REGION();

    CV_Assert(!_src.empty());
    CV_Assert( _mask.empty() || _mask.type() == CV_8UC1 );

    CV_OCL_RUN(OCL_PERFORMANCE_CHECK(_src.isUMat()) && _src.dims() <= 2,
               ocl_meanStdDev(_src, _mean, _sdv, _mask))

    Mat src = _src.getMat(), mask = _mask.getMat();

    CV_OVX_RUN(!ovx::skipSmallImages<VX_KERNEL_MEAN_STDDEV>(src.cols, src.rows),
               openvx_meanStdDev(src, _mean, _sdv, mask))

    CV_IPP_RUN(IPP_VERSION_X100 >= 700, ipp_meanStdDev(src, _mean, _sdv, mask));

    int k, cn = src.channels(), depth = src.depth();

    SumSqrFunc func = getSumSqrFunc(depth);

    CV_Assert( func != 0 );

    const Mat* arrays[] = {&src, &mask, 0};
    uchar* ptrs[2] = {};
    NAryMatIterator it(arrays, ptrs);
    int total = (int)it.size, blockSize = total, intSumBlockSize = 0;
    int j, count = 0, nz0 = 0;
    AutoBuffer<double> _buf(cn*4);
    double *s = (double*)_buf.data(), *sq = s + cn;
    int *sbuf = (int*)s, *sqbuf = (int*)sq;
    bool blockSum = depth <= CV_16S, blockSqSum = depth <= CV_8S;
    size_t esz = 0;

	for( k = 0; k < cn; k++ )
	    s[k] = sq[k] = 0;

    if( blockSum )
    {
        intSumBlockSize = 1 << 15;
        blockSize = std::min(blockSize, intSumBlockSize);
        sbuf = (int*)(sq + cn);
        if( blockSqSum )
            sqbuf = sbuf + cn;
        for( k = 0; k < cn; k++ )
            sbuf[k] = sqbuf[k] = 0;
        esz = src.elemSize();
    }

    for( size_t i = 0; i < it.nplanes; i++, ++it )
    {
        for( j = 0; j < total; j += blockSize )
        {
            int bsz = std::min(total - j, blockSize);
            int nz = func( ptrs[0], ptrs[1], (uchar*)sbuf, (uchar*)sqbuf, bsz, cn );
            count += nz;
            nz0 += nz;
            if( blockSum && (count + blockSize >= intSumBlockSize || (i+1 >= it.nplanes && j+bsz >= total)) )
            {
                for( k = 0; k < cn; k++ )
                {
                    s[k] += sbuf[k];
                    sbuf[k] = 0;
                }
                if( blockSqSum )
                {
                    for( k = 0; k < cn; k++ )
                    {
                        sq[k] += sqbuf[k];
                        sqbuf[k] = 0;
                    }
                }
                count = 0;
            }
            ptrs[0] += bsz*esz;
            if( ptrs[1] )
                ptrs[1] += bsz;
        }
    }

    double scale = nz0 ? 1./nz0 : 0.;
    for( k = 0; k < cn; k++ )
    {
        s[k] *= scale;
        sq[k] = std::sqrt(std::max(sq[k]*scale - s[k]*s[k], 0.));
    }

    for( j = 0; j < 2; j++ )
    {
        const double* sptr = j == 0 ? s : sq;
        _OutputArray _dst = j == 0 ? _mean : _sdv;
        if( !_dst.needed() )
            continue;

        if( !_dst.fixedSize() )
            _dst.create(cn, 1, CV_64F, -1, true);
        Mat dst = _dst.getMat();
        int dcn = (int)dst.total();
        CV_Assert( dst.type() == CV_64F && dst.isContinuous() &&
                   (dst.cols == 1 || dst.rows == 1) && dcn >= cn );
        double* dptr = dst.ptr<double>();
        for( k = 0; k < cn; k++ )
            dptr[k] = sptr[k];
        for( ; k < dcn; k++ )
            dptr[k] = 0;
    }
}

  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2021-08-19 12:04:06  更:2021-08-19 12:05:23 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 19:51:32-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码