NCNN 源码学习【三】:数据处理
一、Topic:数据处理
这次我们来一段NCNN应用代码中,除了推理外最重要的一部分代码,数据处理:
ncnn::Mat in = ncnn::Mat::from_pixels_resize(bgr.data, ncnn::Mat::PIXEL_BGR, bgr.cols, bgr.rows, 227, 227);const float mean_vals[3] = {104.f, 117.f, 123.f};in.substract_mean_normalize(mean_vals, 0);
这一部分代码由两部分组成:
- from_pixels_resize:将cv::Mat数据转换到ncnn::Mat同时进行resize操作
- substract_mean_normalize:这个就是减均值除方差
二、from_pixels_resize
先看名字,from_pixels_resize由两部分组成:
- from_pixels:从unsigned char* 的数组转换到 ncnn::Mat
- resize:unsigned char* 的数据下进行resize
源码中是先进行resize再进行from_pixels。
A、resize
这个代码支持三种图像类型:单通道的GRAY、三通道的RGB和BGR、四通道的RGBA。源码使用的都是bilinear插值,这里我们挑个简单的单通道GRAY的来看看,函数名字很直观,就叫做resize_bilinear_c1,后面的c1就是chennel 1的意思。具体的代码在mat_pixel.cpp的第1414行,这个我就不细说了,大家可以去看这个文章,这个虽然写的是TNN的,但仔细看下来会发现其实跟NCNN的实现是一样的(变量名也一样)。

这个大体流程就是:
- 先算x、y方向上插值点的位置索引xofs和yofs
- 再算x、y方向上插值点左右的两个插值稀疏iapha和ibeta
- 遍历插值,x方向上的插值用xofs和ialpha得到,y方向上的插值用yofs和ibeta得到
这个计算的细节还是很多的,大家感兴趣的可以去仔细研究一下,这里就不细写了,ncnn的代码为例效率,可能写的不是特别美观。
B、from_pixels
这个就很简单了,就是开辟一块ncnn::Mat的内存,然后遍历数组一个一个填进去就好了,同样的这里支持单通道、三通道、四通道,而且一些颜色转换RGB2BGR、RGB2GRAY这些都是实现支持的,我们挑一个典型的RGB2GRAY的实现来看,源码在mat_pixel.cpp的第539行,函数名就是from_rgb2gray。

static Mat from_rgb2gray(const unsigned char* rgb, int w, int h)
{const unsigned char Y_shift = 8;//14const unsigned char R2Y = 77;const unsigned char G2Y = 150;const unsigned char B2Y = 29;Mat m(w, h, 1);if (m.empty())return m;float* ptr = m;int size = w * h;int remain = size;for (; remain > 0; remain--){*ptr = (rgb[0] * R2Y + rgb[1] * G2Y + rgb[2] * B2Y) >> Y_shift;rgb += 3;ptr++;}return m;
}
这个代码很直观,前面就是定义了转换时R、G、B对应要乘的系数,这里作者用的是整数乘法,所以系数放大了28,后面算结果那里要右移回去。后面就是一个暴力for循环,全部遍历把数据塞进去ncnn::Mat就完了。但这里我还想放一下GRAY2RGB的代码,看下很值得注意的细节。
static Mat from_gray2rgb(const unsigned char* gray, int w, int h)
{Mat m(w, h, 3);if (m.empty())return m;float* ptr0 = m.channel(0);float* ptr1 = m.channel(1);float* ptr2 = m.channel(2);int size = w * h;int remain = size;for (; remain>0; remain--){*ptr0 = *gray;*ptr1 = *gray;*ptr2 = *gray;gray++;ptr0++;ptr1++;ptr2++;}return m;
}
从这个可以看出来,获取ncnn::Mat的三个通道的数据,是要用channel索引出来的,这里就是一个需要留意的点,ncnn::Mat的数据存储,channel间的需要对齐,不一定是连续的,也就是不要理所当然的用channel(0)的指针,自己加加加想去访问其他channel的数据,很容易翻车(我就因为这个翻车过),这个我们后面有时间可以好好写一写ncnn的数据排布。
三、substract_mean_normalize
substract_mean_normalize的源码在mat.cpp的第25行,这个代码是支持只mean不norm,只norm不mean,mean和norm都做得,由于这些都大同小异,我就直接贴都做mean和norm的代码了:
void Mat::substract_mean_normalize(const float* mean_vals, const float* norm_vals)
{int size = w * h;for (int q = 0; q < c; q++){float* ptr = data + cstep * q;const float mean = mean_vals[q];const float norm = norm_vals[q];int remain = size;for (; remain > 0; remain--){*ptr = (*ptr - mean) * norm;ptr++;}}
}
上面比较核心的就一句:
*ptr = (*ptr - mean) * norm;
就是遍历Mat的所有数据,给他减mean乘norm,要注意这里是乘norm,不是一般说的除方差,方差的倒数才是这里的norm。
参考&致谢:
https://zhuanlan.zhihu.com/p/456238585
相关文章:
NCNN 源码学习【三】:数据处理
一、Topic:数据处理 这次我们来一段NCNN应用代码中,除了推理外最重要的一部分代码,数据处理: ncnn::Mat in ncnn::Mat::from_pixels_resize(bgr.data, ncnn::Mat::PIXEL_BGR, bgr.cols, bgr.rows, 227, 227);const float mean_v…...
RabbitMq基本使用
目录 SpringAMQP1.准备Demo工程2.快速入门1.1.消息发送1.2.消息接收1.3.测试 3.WorkQueues模型3.1.消息发送3.2.消息接收3.3.测试3.4.能者多劳3.5.总结 SpringAMQP 将来我们开发业务功能的时候,肯定不会在控制台收发消息,而是应该基于编程的方式。由于R…...
windows wsl2 ubuntu上部署 redroid云手机
Redroid WSL2部署文档 下载wsl内核源码 #文档注明 5.15和5.10 版本内核可以部署成功,这里我当前最新的发布版本 #下载wsl 源码 wget --progressbar:force --output-documentlinux-msft-wsl-5.15.133.1.tar.gz https://codeload.github.com/microsoft/WSL2-Linux-Ker…...
创维电视机 | 用当贝播放器解决创维电视机不能播放MKV视频的问题
小故事在下面,感兴趣可以看看,开头我就直接放解决方案 创维电视虽然是基于Android开发的,可以安装apk软件,但是基本不能用,一定要选择适配电视的视频播放器,或者使用本文中提供的创维版当贝播放器。 原软…...
【STM32】DMA直接存储器存取
1 DMA简介 DMA(Direct Memory Access)直接存储器存取 可以直接访问STM32的存储器的,包括运行SRAM、程序存储器Flash和寄存器等等 DMA可以提供外设寄存器和存储器或者存储器和存储器之间的高速数据传输,无须CPU干预,节…...
Vue3-09-条件渲染-v-show 的基本使用
v-show 的作用 v-show 可以根据条件表达式的值【展示】或【隐藏】html 元素。v-show 的特点 v-show 的实现方式是 控制 dom 元素的 css的 display的属性, 因此,无论该元素是否展示,该元素都会正常渲染在页面上, 当v-show 的 条件…...
ArrayList与LinkLIst
ArrayList 在Java中,ArrayList是java.util包中的一个类,它实现了List接口,是一个动态数组,可以根据需要自动增长或缩小。下面是ArrayList的一些基本特性以及其底层原理的简要讲解: ArrayList基本特性: 动…...
位运算(、|、^、~、>>、<<)
分类 编程技术 1.位运算概述 从现代计算机中所有的数据二进制的形式存储在设备中。即 0、1 两种状态,计算机对二进制数据进行的运算(、-、*、/)都是叫位运算,即将符号位共同参与运算的运算。 口说无凭,举一个简单的例子来看下 CPU 是如何进…...
Centos7部署SVN
文章目录 (1)SVN概述(2)SVN与Samba共享(3)安装SVN(4)SVN搭建实例(5)pc连接svn服务器(6)svn图标所代表含义 (1)…...
Vue中this.$nextTick的执行时机
一、Vue中this.$nextTick的执行时机,整体可分为两种情况: 第一种:下一次 Dom 更新之后执行(即等待DOM更新结束之后,执行nextTick的延迟回调函数); 第二种:页面挂载后 (m…...
Unity中的ShaderToy
文章目录 前言一、ShaderToy网站二、ShaderToy基本框架1、我们可以在ShaderToy网站中,这样看用到的GLSL文档2、void mainImage 是我们的程序入口,类似于片断着色器3、fragColor作为输出变量,为屏幕每一像素的颜色,alpha一般赋值为…...
2 使用postman进行接口测试
上一篇:1 接口测试介绍-CSDN博客 拿到开发提供的接口文档后,结合需求文档开始做接口测试用例设计,下面用最常见也最简单的注册功能介绍整个流程。 说明:以演示接口测试流程为主,不对演示功能做详细的测试,…...
【数据库设计和SQL基础语法】--查询数据--聚合函数
一、聚合函数概述 1.1 定义 聚合函数是一类在数据库中用于对多个行进行计算并返回单个结果的函数。它们能够对数据进行汇总、统计和计算,常用于提取有关数据集的摘要信息。聚合函数在 SQL 查询中广泛应用,包括统计总数、平均值、最大值、最小值等。 1…...
Module ‘app‘: platform ‘android-33‘ not found.
目录 一、报错信息 二、解决方法 一、报错信息 Module app: platform android-33 not found. 检查你的应用程序的build.gradle文件中的targetSdkVersion和compileSdkVersion是否正确设置为已安装的Android SDK版本。 确保你的Android Studio已正确安装并配置了所需的Android …...
MySQL按序批量操作大量数据
MySQL按序批量操作大量数据(Java、springboot、mybatisplus、ElasticSearch) 以同步全量MySQL数据到ElasticSearch为例。 核心代码 业务逻辑: public boolean syncToElasticsearch() {log.info("Starting data synchronization to El…...
strict-origin-when-cross-origin
严格限制同源策略 (1)允许服务器的同源IP地址访问 (2)允许Referer --- 后端服务器要配置...
【置顶】 本博博文汇总
文章目录 前言音视频ijkplayer源码分析FFmpeg、音视频协议Andriod系统音视频框架C、C Android&Java源码分析、绘制、渲染Dalvik、Art虚拟机Java并发 计算机基础操作系统计算机网络设计模式、数据结构、算法 前言 23年底了,想来也工作十年,也一直在c…...
react.js源码二
三、调度Scheduler scheduling(调度)是fiber reconciliation的一个过程,主要决定应该在何时做什么?在stack reconciler中,reconciliation是“一气呵成”,对于函数来说,这没什么问题,因为我们只想要函数的运行结果,但对于UI来说还需要考虑以下问题: 并不是所有的state更…...
如何学习英语
前言 首先写一些自己的感言吧,其实从大学的时候就在不断地听英语,学英语,但是到毕业十几年后,英语一直没起到什么作用,当然最有作用的时候就是几次英语面试吧。 工作之后有一段学习英语的经历,当时花费了…...
robot测试自动化
一. 安装 黑羽robot 首先确保你电脑上安装好了 Python 3.7 或者 3.8 版本的解释器 hyrobot 使用说明1 | 白月黑羽 安装RF 黑羽robot基于Robot Framework ,所以必须先安装RobotFramework 直接执行如下Pip命令即可: pip install robotframework...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...
【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...
windows系统MySQL安装文档
概览:本文讨论了MySQL的安装、使用过程中涉及的解压、配置、初始化、注册服务、启动、修改密码、登录、退出以及卸载等相关内容,为学习者提供全面的操作指导。关键要点包括: 解压 :下载完成后解压压缩包,得到MySQL 8.…...
Java详解LeetCode 热题 100(26):LeetCode 142. 环形链表 II(Linked List Cycle II)详解
文章目录 1. 题目描述1.1 链表节点定义 2. 理解题目2.1 问题可视化2.2 核心挑战 3. 解法一:HashSet 标记访问法3.1 算法思路3.2 Java代码实现3.3 详细执行过程演示3.4 执行结果示例3.5 复杂度分析3.6 优缺点分析 4. 解法二:Floyd 快慢指针法(…...
