OpenCV图像处理——积分图像计算(C++/Python)

news2024/11/15 13:44:56

概述

积分图像是一种高效的图像处理技术,最初由Crow在1984年提出,目的是为了提高多尺度透视投影的渲染速度。它通过构建一个积分图,使得图像中任意矩形区域的像素和能够在常数时间内快速计算出来,极大地减少了在图像模糊、边缘提取、对象检测等操作中的计算量,提高了计算速度。

积分图像的构建基于一个简单但有效的概念:图像中的每个点都存储了从图像左上角到该点的区域的像素值之和。这意味着,一旦积分图像构建完成,就可以通过简单的查表和有限次运算来快速获取任何区域的像素和,从而加速了多种图像处理算法的执行。

在实际应用中,积分图像被广泛用于多种图像处理算法中。例如,在Viola-Jones的对象检测框架中,积分图像被用来加速Haar特征的计算。此外,SURF特征提取算法也利用积分图像来快速计算图像特征,从而保持了尺度不变性和旋转不变性,同时对光照变化和放射变化具有很强的鲁棒性。

除了在特征提取中的应用,积分图像也用于二值图像分析,如图像的腐蚀和膨胀操作,以及图像相似相关性NCC(归一化互相关)的计算中。这些应用展示了积分图像在图像处理领域的多样性和实用性。

积分图(Integral Image)的定义:取图像左上侧的全部像素计算累加和,并用这个累加和替换图像中的每一个像素,使用这种方式得到的图像称为积分图像。

公式:
在这里插入图片描述

积分图又称总和面积表(summed area table,简称SAT),是一个快速且有效的对一个网格的矩形子区域中计算和的数据结构和算法。

积分图可以只遍历一次图像即可有效的计算出来,其通常被用来加速计算过程。一旦积分图计算完毕,对任意矩形区域的和的计算就可以在常数时间内(一次加法,两次减法)完成。如下图中,阴影矩形区域的值:


其中公式如下:在这里插入图片描述
图像积分图建立与查找,在积分图像(Integral Image - ii)上任意位置(x, y)处的ii(x, y)表示该点左上角所有像素之和, 其中(x,y)是图像像素点坐标。

API

integral(
InputArray src, // 输入图像
OutputArray sum, // 和表
OutputArray sqsum, // 平方和表
OutputArray tilted, // 瓦块和表
int sdepth = -1, // 和表数据深度常见CV_32S
int sqdepth = -1 // 平方和表数据深度 常见 CV_32F
)

C++ 实现

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

void blur_demo(Mat &image, Mat &sum);
void edge_demo(Mat &image, Mat &sum);
int getblockSum(Mat &sum, int x1, int y1, int x2, int y2, int i);

/*
 * 图像积分图算法
 */
int main() {
    Mat src = imread("../images/test.png");
    if (src.empty()) {
        cout << "could not load image.." << endl;
    }
    imshow("input", src);

    // 计算积分图
    Mat sum, sqrsum;
    integral(src, sum, sqrsum);

    /*
     * 积分图应用
    */
    int type = 0;
    // 模糊应用
    blur_demo(src, sum);
    // 边缘检测
    edge_demo(src, sum);

    waitKey(0);
    return 0;
}

void blur_demo(Mat &image, Mat &sum) {
    int w = image.cols;
    int h = image.rows;
    Mat result = Mat::zeros(image.size(), image.type());
    int x2 = 0, y2 = 0;
    int x1 = 0, y1 = 0;
    int ksize = 5;
    int radius = ksize / 2;
    int ch = image.channels();
    int cx = 0, cy = 0;
    for (int row = 0; row < h + radius; row++) {
        y2 = (row + 1)>h ? h : (row + 1);
        y1 = (row - ksize) < 0 ? 0 : (row - ksize);
        for (int col = 0; col < w + radius; col++) {
            x2 = (col + 1)>w ? w : (col + 1);
            x1 = (col - ksize) < 0 ? 0 : (col - ksize);
            cx = (col - radius) < 0 ? 0 : col - radius;
            cy = (row - radius) < 0 ? 0 : row - radius;
            int num = (x2 - x1)*(y2 - y1);
            for (int i = 0; i < ch; i++) {
                // 积分图查找和表,计算卷积
                int s = getblockSum(sum, x1, y1, x2, y2, i);
                result.at<Vec3b>(cy, cx)[i] = saturate_cast<uchar>(s / num);
            }
        }
    }
    imshow("blur_demo", result);
}
/**
* 3x3 sobel 垂直边缘检测演示
*/
void edge_demo(Mat &image, Mat &sum) {
    int w = image.cols;
    int h = image.rows;
    Mat result = Mat::zeros(image.size(), CV_32SC3);
    int x2 = 0, y2 = 0;
    int x1 = 0, y1 = 0;
    int ksize = 3; // 算子大小,可以修改,越大边缘效应越明显
    int radius = ksize / 2;
    int ch = image.channels();
    int cx = 0, cy = 0;
    for (int row = 0; row < h + radius; row++) {
        y2 = (row + 1)>h ? h : (row + 1);
        y1 = (row - ksize) < 0 ? 0 : (row - ksize);
        for (int col = 0; col < w + radius; col++) {
            x2 = (col + 1)>w ? w : (col + 1);
            x1 = (col - ksize) < 0 ? 0 : (col - ksize);
            cx = (col - radius) < 0 ? 0 : col - radius;
            cy = (row - radius) < 0 ? 0 : row - radius;
            int num = (x2 - x1)*(y2 - y1);
            for (int i = 0; i < ch; i++) {
                // 积分图查找和表,计算卷积
                int s1 = getblockSum(sum, x1, y1, cx, y2, i);
                int s2 = getblockSum(sum, cx, y1, x2, y2, i);
                result.at<Vec3i>(cy, cx)[i] = saturate_cast<int>(s2 - s1);
            }
        }
    }
    Mat dst, gray;
    convertScaleAbs(result, dst);
    normalize(dst, dst, 0, 255, NORM_MINMAX);
    cvtColor(dst, gray, COLOR_BGR2GRAY);
    imshow("edge_demo", gray);
}
int getblockSum(Mat &sum, int x1, int y1, int x2, int y2, int i) {
    int tl = sum.at<Vec3i>(y1, x1)[i];
    int tr = sum.at<Vec3i>(y2, x1)[i];
    int bl = sum.at<Vec3i>(y1, x2)[i];
    int br = sum.at<Vec3i>(y2, x2)[i];
    int s = (br - bl - tr + tl);
    return s;
}

Python代码实现

import cv2 as cv
import numpy as np


def get_block_sum(ii, x1, y1, x2, y2, index):
    tl = ii[y1, x1][index]
    tr = ii[y2, x1][index]
    bl = ii[y1, x2][index]
    br = ii[y2, x2][index]
    s = (br - bl - tr + tl)
    return s


def blur_demo(image, ii):
    h, w, dims = image.shape
    result = np.zeros(image.shape, image.dtype)
    ksize = 15
    radius = ksize // 2
    for row in range(0, h + radius, 1):
        y2 = h if (row + 1)> h else (row + 1)
        y1 = 0 if (row - ksize) < 0 else (row - ksize)
        for col in range(0, w + radius, 1):
            x2 = w if (col + 1)>w else (col + 1)
            x1 = 0 if (col - ksize) < 0 else (col - ksize)
            cx = 0 if (col - radius) < 0 else (col - radius)
            cy = 0 if (row - radius) < 0 else (row - radius)
            num = (x2 - x1)*(y2 - y1)
            for i in range(0, 3, 1):
                s = get_block_sum(ii, x1, y1, x2, y2, i)
                result[cy, cx][i] = s // num

    cv.imshow("integral fast blur", result)
    cv.imwrite("D:/result.png", result)


src = cv.imread("D:/images/test1.png")
cv.namedWindow("input", cv.WINDOW_AUTOSIZE)
cv.imshow("input", src)
sum_table = cv.integral(src, sdepth=cv.CV_32S)
blur_demo(src, sum_table)

cv.waitKey(0)
cv.destroyAllWindows()

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

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

相关文章

WARNING: There was an error checking the latest version of pip. 解决方案

WARNING: There was an error checking the latest version of pip. 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xff0c;武汉城市开…

【单片机】51单片机入门教程(二):定时器的模式详解与中断应用实例

文章目录 51单片机定时器教程:模式详解与中断应用实例1. 介绍2. 51单片机定时器/计数器概述3. 定时器控制寄存器与中断入口4. 模式0:13位定时器/计数器5. 模式1:16位定时器/计数器6. 模式2:8位自动重装载定时器/计数器7. 模式3:分割两个独立的8位定时器/计数器8. 总结51单…

Vue.js入门系列(十):深入理解Vue指令及自定义指令的使用

个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[2435024119qq.com] &#x1f4f1…

【技术前沿】MetaGPT入门安装部署——用多个大语言模型解决任务!一键安装,只需填写OpenAI API

项目简介 MetaGPT 是一个多智能体框架&#xff0c;旨在构建全球首家 “AI 软件公司”。该项目通过为 GPT 分配不同的角色&#xff0c;模拟产品经理、架构师、工程师等职业&#xff0c;协同完成复杂的软件开发任务。MetaGPT 将一个简单的需求转化为完整的软件开发流程&#xff…

点接触导致Fluent Meshing网格划分出错的处理

问题概述 在CFD建模中&#xff0c;几何处理有时会出现两个面是单点接触的情形。 举例如下图所示&#xff0c;在球形计算域内部&#xff0c;存在分别用黄色和粉红色标记的内部悬浮面&#xff0c;两者接触区域为一个点&#xff0c;而非一条曲线。 上述几何模型可正确的导入Flue…

从零搭建xxl-job(四):xxljob进行一些性能优化

之前的代码这部分并没有补充完毕&#xff0c;假如调度中心如果判断有定时任务要执行了&#xff0c;该怎么远程通知给执行定时任务的程序呢&#xff1f;当定时任务要把自己的信息发送给调度中心时&#xff0c;是通过一个RegistryParam对象发送的。该对象内部封装了定时任务相关的…

鸿蒙自定义Tab,可居左显示

最近写鸿蒙项目时&#xff0c;需要用到类似Android的TabLayout控件&#xff0c;鸿蒙官方也有提供类似实现的组件Tabs。但是官方Tabs组件&#xff0c;实在有点鸡肋&#xff0c;首先 TabContent和 TabBar是绑定在一起的放在Tabs里面的&#xff0c;如果UI是TabBar的背景是一个整体…

可视化大屏入口界面,炫酷科技又不失简洁时尚。

可视化大屏界面&#xff0c;大家见到很多了&#xff0c;当可视化大屏是多个系统的融合&#xff0c;而且彼此又相互独立&#xff0c;就需要设计一个入口页面&#xff0c;便于分流客户&#xff0c;这次我给大家分享一批。 设计可视化大屏入口界面时&#xff0c;可以结合炫酷科技…

#laravel部署安装报错loadFactoriesFrom是undefined method #

场景: 在git上clone一个项目代码吗laravel版本是5.6 php的版本是7.1 但是运行的时候一直提示错误 Call to undefined method Eachdemo\Rbac\RbacServiceProvider::loadFactoriesFrom() 解决办法: 给RbacServiceProvider&#xff0c;手动添加方…

中国生态地理区划更新和优化

在机器学习或深度学习研究时&#xff0c;建立的模型用于不同地区或时间的数据进行泛化时&#xff0c;其泛化能力往往较差&#xff0c;所以目前在遥感领域用深度学习或机器学习建模时很多文献都是建立分区的模型&#xff0c;即在不同的地理分区内建立模型&#xff0c;泛化时针对…

代码随想录算法训练营第十八天

力扣题部分: 530.二叉搜索树的最小绝对差 题目链接: 题面: 给你一个二叉搜索树的根节点 root &#xff0c;返回 树中任意两不同节点值之间的最小差值 。 差值是一个正数&#xff0c;其数值等于两值之差的绝对值。 思路: 写关于二叉搜索树的问题&#xff0c;一定要先掌握二…

socket回显服务器练习

前言 什么是回显服务器(echo server)呢&#xff1f; 回显服务器接收客户端发送的任何数据&#xff0c;并将这些数据原封不动地发送回客户端。回显服务器在连接成功的基础上只需要知道如何在客户端将收到的信息打印输出到控制台即可。我接下来会使用两种方法来输出&#xff0c;…

“TCP粘包”不是TCP的问题!

前言 写RPC用了Netty。涉及到粘包拆包问题。想复习一下。发现网上博客多是概念模糊不清。没有触及本质或者没有讲清楚。 遂决定自己写一篇 “TCP粘包”是谁的问题&#xff1f; 首先我们要明确TCP是面向字节流的协议。也就是说我们在应用层想使用TCP来传输数据时&#xff0c;…

ARM 处理器异常处理机制详解

目录 异常 异常源 异常处理 异常向量表 安装设置异常向量表及保存现场指令 异常处理的返回 异常源与异常模式对应关系 异常响应优先级 ARM7-11 有7种基本工作模式&#xff0c;而 Cortex-A 系列处理器则额外支持 Monitor 模式&#xff1a; User&#xff1a;非特权模式&…

测试流程自动化实践!

测试流程自动化的最佳实践涉及多个方面&#xff0c;旨在提高测试效率、确保测试质量&#xff0c;并降低测试成本。以下是一些关键的实践方法&#xff1a; 1. 明确测试目标 确定测试范围&#xff1a;在开始自动化测试之前&#xff0c;需要明确哪些功能、模块或场景需要被测试。…

Leetcode JAVA刷刷站(39)组合总和

一、题目概述 二、思路方向 为了解决这个问题&#xff0c;我们可以使用回溯算法来找到所有可能的组合&#xff0c;使得组合中的数字之和等于目标数 target。因为数组中的元素可以无限制地重复选择&#xff0c;所以在回溯过程中&#xff0c;我们不需要跳过已经选择的元素&#x…

python爬虫爬取某图书网页实例

文章目录 导入相应的库正确地设置代码的基础部分设置循环遍历遍历URL保存图片和文档全部代码即详细注释 下面是通过requests库来对ajax页面进行爬取的案例&#xff0c;与正常页面不同&#xff0c;这里我们获取url的方式也会不同&#xff0c;这里我们通过爬取一个简单的ajax小说…

第N6周:中文文本分类-Pytorch实现

本文为365天深度学习训练营 中的学习记录博客原作者&#xff1a;K同学啊 一、准备工作 任务说明 本次将使用PyTorch实现中文文本分类。主要代码与N1周基本一致&#xff0c;不同的是本次任务中使用了本地的中文数据&#xff0c;数据示例如下&#xff1a; 任务&#xff1a; ●1…

Diffusion Model相关论文解析之(二)DENOISING DIFFUSION IMPLICIT MODELS

目录 1、摘要2、创新点3、主要公式4、自己的理解&#xff0c;对错不确定 1、摘要 ‌Denoising Diffusion Implicit Models (DDIM)‌是一种扩散模型的改进版本&#xff0c;旨在加速采样过程并提高采样速度。DDIM通过引入非马尔可夫扩散过程&#xff0c;相对于传统的去噪扩散概率…

H. Ksyusha and the Loaded Set

https://codeforces.com/contest/2000/problem/H div3 H 一开始看就感觉要维护一些比较有趣的量 看了一下数据范围ai<2e6,k<2e6 似乎可以直接开一个线段树来表示是否存在集合当中 我们开4e6维护每个数字是否存在&#xff0c;ai2e6时候k2e6&#xff0c;最大是4e6 存在…