【NCC】之二:积分图加速均值计算

news2024/9/26 5:19:17

文章目录

  • <center> 积分图 integral image
    • 1. 原理:
    • 2. 示例
    • 3. 计算区域均值
    • 4. 计算区域方差
    • 5. 积分图示例
    • 6. 计算积分图的源码
    • 7. 用积分图加速NCC
    • 参考

积分图 integral image

1. 原理:

Summed Area Table是一种数据结构和算法,用于快速有效地生成网格矩形子集中的值总和。在图像处理领域,它也被称为积分图像。

记源图像为 I m × n I_{m \times n} Im×n,积分图为SAT(Summed Area Table)则
S A T ( x , y ) = Σ i ≤ x , j ≤ y I ( i , j ) SAT(x,y) = \underset{i\leq x,j\leq y}{\Sigma }I(i,j) SAT(x,y)=ix,jyΣI(i,j)

S Q A T ( x , y ) = Σ i ≤ x , j ≤ y I ( i , j ) 2 SQAT(x,y) = \underset{i\leq x,j\leq y}{\Sigma }I(i,j)^2 SQAT(x,y)=ix,jyΣI(i,j)2

  • 计算积分图的递推式
    S A T ( x , y ) = S A T ( x − 1 , y ) + S A T ( x , y − 1 ) − S A T ( x − 1 , y − 1 ) + I ( x , y ) SAT(x,y) = SAT(x-1,y) + SAT(x,y-1) - SAT(x-1,y-1) + I(x,y) SAT(x,y)=SAT(x1,y)+SAT(x,y1)SAT(x1,y1)+I(x,y)
    上面的公式中起始项必须从第二行第二列开始,因为递推式中包含-1项,也就是需要单独把第一行和第一列先单独计算出来,后面的所有点都可以用递推式写出来。

  • 一点漂亮的改进
    让积分图比原图多一行一列:上面一行,左边一列,且行列初始值为0!这样的话就可以不需要考虑-1项完全采用递推式得到积分图!opencv就是这么干的

2. 示例

在这里插入图片描述

图片摘自Wikipedia。1为源图,2为积分图每一个像素点的值都是它在源图上对应位置的上面、左边所有像素值的和。

3. 计算区域均值

当要计算源图中的某个矩形区域的像素和时可以用查表的方式快速计算,构建好积分图后求区域和的复杂度将是 O ( 1 ) O(1) O(1)

设在源图中的矩形 R R R左上角坐标为 ( t p x , t p y ) (tpx,tpy) (tpx,tpy),左下角坐标为 ( b t x , b t y ) (btx,bty) (btx,bty),则计算该矩形区域内所有像素值和可以写为下式。

  • 区域像素值之和
    s u m = S A T ( b t x , b t y ) − S A T ( t p x , b t y ) − S A T ( b t x , t p y ) + S A T ( t p x , t p y ) sum = SAT(btx,bty) - SAT(tpx,bty) - SAT(btx,tpy) + SAT(tpx,tpy) sum=SAT(btx,bty)SAT(tpx,bty)SAT(btx,tpy)+SAT(tpx,tpy)
  • 区域均值
    m e a n = s u m ( b t y − t p y + 1 ) ( b t x − t p x + 1 ) mean = \frac{sum}{(bty-tpy+1)(btx-tpx+1)} mean=(btytpy+1)(btxtpx+1)sum

4. 计算区域方差

以【NCC】之一:从Pearson相关系数到模板匹配的NCC方法中的 S x , y S_{x,y} Sx,y的方差计算为例
计算区域方差
σ ( S x , y ) = v a r ( S x , y ) = Σ i = 1 m Σ j = 1 n ( S x , y ( i , j ) − S x , y ˉ ) 2 m n \sigma(S_{x,y})=\sqrt{var(S_{x,y})}=\sqrt{\frac{\Sigma_{i=1}^{m}\Sigma_{j=1}^{n}{(S_{x,y}(i,j)-\bar{S_{x,y}}})^2}{mn}} σ(Sx,y)=var(Sx,y) =mnΣi=1mΣj=1n(Sx,y(i,j)Sx,yˉ)2
let A = Σ i = 1 m Σ j = 1 n ( S x , y ( i , j ) − S x , y ˉ ) 2 A = \Sigma_{i=1}^{m}\Sigma_{j=1}^{n}{(S_{x,y}(i,j)-\bar{S_{x,y}}})^2 A=Σi=1mΣj=1n(Sx,y(i,j)Sx,yˉ)2 则有
A = Σ i = 1 m Σ j = 1 n ( S x , y ( i , j ) 2 − 2 S x , y ˉ S x , y ( i , j ) + S x , y ˉ 2 ) = S Q A T ( m , n ) S x , y − 2 S x , y ˉ × S A T ( m , n ) S x , y + m n × S x , y ˉ 2 = S Q A T ( m , n ) S x , y − 2 S x , y ˉ × S A T ( m , n ) S x , y + S x , y ˉ × S A T ( m , n ) = S Q A T ( m , n ) S x , y − S x , y ˉ × S A T ( m , n ) S x , y \begin{aligned} \begin{aligned} A &=\Sigma_{i=1}^{m}\Sigma_{j=1}^{n}( S_{x,y}(i,j)^2 -2\bar{S_{x,y}}S_{x,y}(i,j) + \bar{S_{x,y}}^2) \\ &= \underset{S_{x,y}}{SQAT(m,n)} -\underset{S_{x,y}}{2\bar{S_{x,y}}\times SAT(m,n)} + mn\times \bar{S_{x,y}}^2 \\ &=\underset{S_{x,y}}{SQAT(m,n)}-\underset{S_{x,y}}{2\bar{S_{x,y}}\times SAT(m,n)} + \bar{S_{x,y}}\times SAT(m,n) \\ &=\underset{S_{x,y}}{SQAT(m,n)}-\underset{S_{x,y}}{\bar{S_{x,y}}\times SAT(m,n)} \end{aligned} \end{aligned} A=Σi=1mΣj=1n(Sx,y(i,j)22Sx,yˉSx,y(i,j)+Sx,yˉ2)=Sx,ySQAT(m,n)Sx,y2Sx,yˉ×SAT(m,n)+mn×Sx,yˉ2=Sx,ySQAT(m,n)Sx,y2Sx,yˉ×SAT(m,n)+Sx,yˉ×SAT(m,n)=Sx,ySQAT(m,n)Sx,ySx,yˉ×SAT(m,n)

5. 积分图示例

  • 原图
    原图

  • 积分图
    在这里插入图片描述

  • 平方积分图
    在这里插入图片描述

6. 计算积分图的源码

/**
 * @brief 计算输入图的积分图,为了提高计算效率,可以让积分图比输入图多一行一列,
 * 具体的就是在原图左边插入一列0,上面插入一行0,设原图为I,积分图为SAT(sum area of table)
 * 则:SAT(i,j) = SAT(i,j-1) + SAT(i-1,j) - SAT(i-1,j-1) + I(i,j)
 * 这样就不用考虑下边界的情况,省掉很多判断条件
 * 
 * @param image  : 输入图CV_8UC1,MxN
 * @param integral_image  : 积分图CV_32FC1,(M+1)x(N+1)
 * @return int 
 */
int integral(const cv::Mat &image,cv::Mat &integral_image)
{
    if(image.empty())
    {
        MYCV_ERROR(kImageEmpty,"image empty");
        return kImageEmpty;
    }

    int h = image.rows;
    int w = image.cols;
    integral_image = cv::Mat::zeros(cv::Size(w+1,h+1),CV_64FC1);

    //SAT(i,j) = SAT(i,j-1) + SAT(i-1,j) - SAT(i-1,j-1) + I(i,j)
    for(int i = 0; i < h ; i++)
    {
        const uchar *ps = image.ptr<uchar>(i);
        double *pd_m1 = integral_image.ptr<double>(i);//integral 的"上一行"
        double *pd = integral_image.ptr<double>(i+1); //integral 的"当前行"
        for(int j = 0; j < w; j++)
        {
            pd[j+1] = pd[j] + pd_m1[j+1] - pd_m1[j] + ps[j];
        }
    }

    return kSuccess;
}


/**
 * @brief 计算输入图的积分图,为了提高计算效率,可以让积分图比输入图多一行一列,
 * 具体的就是在原图左边插入一列0,上面插入一行0,设原图为I,积分图为SAT(summed area table)
 * 则:SAT(i,j) = SAT(i,j-1) + SAT(i-1,j) - SAT(i-1,j-1) + I(i,j)
 * SQAT(i,j) = SQAT(i,j-1) + SQAT(i-1,j) - SQAT(i-1,j-1) + I(i,j) * I(i,j)
 * 这样就不用考虑下边界的情况,省掉很多判断条件
 * 
 * @param image  : 输入图CV_8UC1,MxN
 * @param integral_image  : 积分图CV_32FC1,(M+1)x(N+1)
 * @param integral_sq : 平方的积分图CV_32FC1,(M+1)x(N+1)
 * @return int 
 */
int integral(const cv::Mat &image,cv::Mat &integral_image,cv::Mat &integral_sq)
{
     if(image.empty())
    {
        MYCV_ERROR(kImageEmpty,"image empty");
        return kImageEmpty;
    }

    int h = image.rows;
    int w = image.cols;
    integral_image = cv::Mat::zeros(cv::Size(w+1,h+1),CV_64FC1);
    integral_sq = cv::Mat::zeros(cv::Size(w+1,h+1),CV_64FC1);

    //SAT(i,j) = SAT(i,j-1) + SAT(i-1,j) - SAT(i-1,j-1) + I(i,j)
    //SQAT(i,j) = SQAT(i,j-1) + SQAT(i-1,j) - SQAT(i-1,j-1) + I(i,j) * I(i,j)
    for(int i = 0; i < h ; i++)
    {
        const uchar *ps = image.ptr<uchar>(i);
        double *pd_m1 = integral_image.ptr<double>(i);//integral 的"上一行"
        double *pd = integral_image.ptr<double>(i+1); //integral 的"当前行"
        double *pqd_m1 = integral_sq.ptr<double>(i);
        double *pqd = integral_sq.ptr<double>(i+1);
        for(int j = 0; j < w; j++)
        {
            pd[j+1] = pd[j] + pd_m1[j+1] - pd_m1[j] + (double)ps[j];
            pqd[j+1] = pqd[j] + pqd_m1[j+1] - pqd_m1[j] + (double)ps[j] * (double)ps[j];
        }
    }


    return kSuccess;
}

7. 用积分图加速NCC

采用积分图计算均值和方差

source image size w,h = (1095,680)
target image size w,h = (89,91)
my NCC run 10 times,average use 4741.000000 ms
opencv NCC run 10 times,average use 15.000000 ms

opencv的速度是这一版本的316.06倍,相比上一版882.78倍还是有点进步。

参考

[1] https://en.wikipedia.org/wiki/Summed-area_table
[2] 积分图(一) - 原理及应用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/127218.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【math】大规模对称正定稀疏线性方程组的求解与代数多重网格

大规模对称正定稀疏线性方程组的求解与代数多重网格代数多重网格问题定义迭代法的优畧几何多重网格代数多重网格代数多重网格 你好&#xff01;代数多重网格一个很有意思的话题。 问题定义 很多问题都可以抽象为求解下列优化的问题&#xff1a; 对于图像问题&#xff0c;一…

安全、稳定的工业蜂窝路由器具有怎样的特性?

一、前言 传统路由器通过电缆或光纤线路访问Internet&#xff0c;在很多场景或区域下存在着很大的局限性&#xff0c;例如在行驶的火车上&#xff0c;在固定电话稀缺或没有其他接入方式的地区都是十分受限的。随着科技的发展&#xff0c;很多行业应用都需要具有更强大功能的路…

3 高级面向对象编程实例

高级OOP 1 继承 是一种基于已有类创建新类的机制 class 子类名 extends 父类{类体; }public class Extends_v1 {public static void main(String[] args) {Extendsclass01 ex new Extendsclass01();} } class Baseclass01{public int num;public void setNum(int n){num n…

java之线程死锁和ThreadLocal的使用

线程死锁&#xff1a; 线程死锁是指两个或者两个以上的线程在执行过程中&#xff0c;由于竞争资源或者彼此通信而造成的一种阻塞的现象,若无外力的作用,它们都将无法继续执行下去。 此时应用系统就处于了死锁状态&#xff0c;这些永远在互相等待的线程称为死锁线程。 如下图…

文本中按规则分组区段随机抽样

【问题】 This is a bit complex, and I greatly appreciate any help! I am trying to randomly sample rows from a .csv file. Essentially, I want a resulting file of unique locations (Locations are specified by Easting and Northing columns of the data file, be…

ServletContext和过滤器

✅作者简介&#xff1a;热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏&#xff1a;JAVA开发者…

BM30 二叉搜索树与双向链表

题目 输入一棵二叉搜索树&#xff0c;将该二叉搜索树转换成一个排序的双向链表。如下图所示&#xff1a; 数据范围&#xff1a;输入二叉树的节点数0≤n≤1000&#xff0c;二叉树中每个节点的值0≤val≤1000. 要求&#xff1a;空间复杂度O(1)&#xff08;即在原树上操作&#x…

低代码对比分析,从工程化上看产品的优劣

低代码算是这几年在IT行业内越来越尖锐的讨论了&#xff0c;而且随着这两年大厂的大量裁员&#xff0c;更是亲者痛仇者快的事情&#xff0c;因为很多大厂发现把一些低端的研发岗位干掉了&#xff0c;反而整个体系在工具的辅助运转下&#xff0c;效率更高&#xff0c;执行力更优…

【Python数据分析】Python模拟登录(一) requests.Session应用

最近由于某些原因&#xff0c;需要用到Python模拟登录网站&#xff0c;但是以前对这块并不了解&#xff0c;而且目标网站的登录方法较为复杂&#xff0c; 所以一下卡在这里了&#xff0c;于是我决定从简单的模拟开始&#xff0c;逐渐深入地研究下这块。 注&#xff1a;本文仅为…

Python学习基础笔记五十九——封装和@property

1、私有属性的一个用法&#xff1a; class Room:def __init__(self, name, length, width):self.name nameself.__length lengthself.__width widthdef area(self):return self.__length * self.__widthwei Room(Wei, 2, 1) print(wei.area()) 2、getter和setter&#xf…

Hi3861鸿蒙物联网项目实战:智能照明灯

华清远见FS-Hi3861开发套件&#xff0c;支持HarmonyOS 3.0系统。开发板主控Hi3861芯片内置WiFi功能&#xff0c;开发板板载资源丰富&#xff0c;包括传感器、执行器、NFC、显示屏等&#xff0c;同时还配套丰富的拓展模块。开发板配套丰富的学习资料&#xff0c;包括全套开发教程…

第十篇 1+X考证 Web前端测试题(新)

单选题 1、关于HTML和CSS以下说法错误的是&#xff08; D &#xff09; A、HTML标签中属性的值一定要用双引号或单引号括起来B、HTML空元素要有结束的标签或于开始的标签后加上"/"C、结构与样式完全分离时&#xff0c;结构代码中不涉及任何的样式元素&#xff0c;如f…

Qt之软键盘的实现

文章目录前言一、基于中文汉字数据库1、核心代码2、效果二、基于谷歌拼音输入引擎1、核心代码2、效果前言 Qt5.8版本开始推出了基于QML实现的软键盘功能&#xff0c;在此之前&#xff0c;并没有官方版本的软键盘。本篇主要介绍Qt实现软键盘的两种方案&#xff0c;一种基于中文汉…

[python][GUI]pyside6

------------------------------------------------------------------------------------------------------------------ #非常好资料和教程&#xff1a; 1. Module Index - Qt for Python 2. muziing/PySide6-Code-Tutorial: 可能是最好的PySide6中文教程&#xff01;用代…

Spring boot 日志直接推送到elasticsearch上

Spring boot 日志直接推送到elasticsearch前言核心依赖elasticsearch配置文件1.url格式如下2.index索引前缀 "xxx"3.maxMessageSize参数数据内容最大值&#xff0c;本文未使用&#xff08;默认值-1全部数据接收&#xff09;如下4.BasicAuthentication.java 重写该类用…

详解opencv库函数ellipse()

opencv库函数ellipse()函数可以画扇形&#xff0c;也可以画椭圆。画扇形时只需要将椭圆的长短轴长度设为相同并给定扇形的圆心角即可。 # 参数 1.目标图片 2.椭圆圆心 3.长短轴长度 4.偏转角度 5.圆弧起始角度 6.终止角度 7.颜色 8.是否填充 cv2.ellipse(img_p, (500, 2…

[python] PyMouse、PyKeyboard用python操作鼠标和键盘

1、PyUserInput 简介 PyUserInput是一个使用python的跨平台的操作鼠标和键盘的模块&#xff0c;非常方便使用。支持的平台及依赖如下&#xff1a; Linux - XlibMac - Quartz, AppKitWindows - pywin32, pyHook 支持python版本&#xff1a;我用的是3.6.7 2、安装 直接源码安装…

越南猫年来袭!2023Lazada年货节热销品趋势

距离2023年春节倒计时23天&#xff01;大家是否对春节假期已经满怀期待了&#xff1f;越南人也和我们一样正期盼着新年到来&#xff0c;越南所有的传统节日都是按照农历来算的&#xff0c;其中春节也是越南重大的节日。春节将至&#xff0c;提前置办年货成了越南人和华人必不可…

MySQL 表的增删改查(进阶篇②)· 联合查询 内连接 外连接 · 自连接 · 子查询 exists · 合并查询 union

接进阶篇①&#xff0c;我们继续学习。 一、联合查询1.1 内连接1.2 外连接1.3 内连接和左右外连接的区别二、自连接三、子查询3.1 单行子查询3.2 多行子查询使用 in 范围匹配多行另一种写法 exists两种写法的区别3.3 在 from 子句中使用子查询四、合并查询unionunion all一、联…

随谈_前端与后端

文章目录一、前言二、前后端分别是什么&#xff1f;2.1. 前端&#xff08;front end&#xff09;2.2. 后端&#xff08;back end&#xff09;一、前言 最近在学习Vue&#xff0c;打算边学边用&#xff0c;开发一个网页系统。 Vue的话&#xff0c;网上介绍很多&#xff0c;简单…