OpenCV中积分图介绍与应用
时间:2022-05-07
本文章向大家介绍OpenCV中积分图介绍与应用,主要内容包括OpenCV中积分图函数与应用、二:OpenCV中积分图函数、三:使用积分图函数、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。
OpenCV中积分图函数与应用
一:图像积分图概念
积分图像是Crow在1984年首次提出,是为了在多尺度透视投影中提高渲染速度。随后这种技术被应用到基于NCC的快速匹配、对象检测和SURF变换中、基于统计学的快速滤波器等方面。积分图像是一种在图像中快速计算矩形区域和的方法,这种算法主要优点是一旦积分图像首先被计算出来我们可以计算图像中任意大小矩形区域的和而且是在常量时间内。这样在图像模糊、边缘提取、对象检测的时候极大降低计算量、提高计算速度。第一个应用积分图像技术的应用是在Viola-Jones的对象检测框架中出现。
上图左侧四个点的矩形区域像素求和,只要根据每个点左上方所有像素和表值,进行两次减法与一次加法即可=》46 – 22 – 20 + 10 = 14
二:OpenCV中积分图函数
OpenCV中通过integral()函数可以很容易的计算图像的积分图,该函数支持和表积分图、平方和表积分图、瓦块和表积分图计算。integral函数与参数解释如下:
void cv::integral(
InputArray src, // 输入图像
OutputArray sum, // 和表
OutputArray sqsum, // 平方和表
OutputArray tilted, // 瓦块和表
int sdepth = -1, // 和表数据深度常见CV_32S
int sqdepth = -1 // 平方和表数据深度 常见 CV_32F
)
三:使用积分图函数
通过代码演示计算积分图实现任意窗口大小的盒子模糊与垂直边缘提取,完整的代码实现如下:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
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(int argc, char** argv) {
Mat src = imread("D:/vcprojects/images/yuan_test.png");
if (src.empty()) {
printf("could not load image...n");
return -1;
}
namedWindow("input", CV_WINDOW_AUTOSIZE);
imshow("input", src);
namedWindow("output", CV_WINDOW_AUTOSIZE);
// 计算积分图
Mat sum, sqrsum;
integral(src, sum, sqrsum, CV_32S, CV_32F);
// 积分图应用
int type = 0;
while (true) {
char c = waitKey(100);
if (c > 0) {
type = (int)c;
printf("c : %dn", type);
}
if (c == 27) {
break; // ESC
}
if (type == 49) { // 数字键 1
blur_demo(src, sum);
}
else if (type == 50) { // 数字键 2
edge_demo(src, sum);
}
else {
blur_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("output", result);
imwrite("D:/result.png", 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("output", gray);
imwrite("D:/edge_result.png", 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;
}
这里最重要的是要注意到上面的图示,积分图对象的Mat(1,1)对应实际图像Mat(0,0),如果不加处理的话会导致结果有明显的中心迁移。edge_demo实现了积分图查找提取图像边缘、blur_demo函数实现积分图查找图像均值模糊,getblockSum函数实现和表查找功能,运行显示:
原图:
模糊效果
边缘效果
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 打卡群刷题总结1008——加油站
- 打卡群刷题总结1005——跳跃游戏
- 真是活久见,在 Minecraft 的虚拟游戏里竟然还能管理 Kubernetes!
- 打卡群2刷题总结1007——反转链表
- 打卡群2刷题总结1001——两数之和 II - 输入有序数组
- 复杂一点的SQL语句
- PL/SQL Developer连接本地Oracle 11g 64位数据库
- 打卡群刷题总结1007——买卖股票的最佳时机 II
- 事务Transaction
- 打卡群2刷题总结1006—— 删除链表的倒数第N个节点
- 打卡群刷题总结1006——跳跃游戏 II
- 面试官常问的Spring依赖注入和Bean的装配问题,今天给大家讲清楚!
- 打卡群刷题总结1003——分割等和子集
- 打卡群2刷题总结1005——有效的括号
- 腾讯云服务器操作系统TencentOS安装与体验