图像转置的Neon优化代码

简介: 图像转置的Neon优化代码原理图像转置图像转置和矩阵转置是一样的,其公式为:dst.getPixels(y, x) = src.getPixels(x, y)dst.w = src.hdst.h = src.w效果如下: 原图: 结果图: 先做图像转置后,再实现90度/270度的旋转相对容易, 如图像旋转90度,就只需要再水平翻

图像转置的Neon优化代码

原理

图像转置

图像转置和矩阵转置是一样的,其公式为:

dst.getPixels(y, x) = src.getPixels(x, y)
dst.w = src.h
dst.h = src.w

效果如下:
原图:
原图

结果图:
结果图

先做图像转置后,再实现90度/270度的旋转相对容易,
如图像旋转90度,就只需要再水平翻转一下:
旋转结果图:
旋转结果图

分而治之

图像转置的优化思路是:
1、将图像分割成一系列小矩阵。
分成的小矩阵当然是越大越好,但在矩阵变大时,汇编代码的复杂度变高,且寄存器如果使用完了也非常难处理,这里选的是4X4的矩阵。
2、每个小矩阵的宏观位置转置。
3、实现每个小矩阵的内部转置。
必须把矩阵图和寄存器向量的关系图画清,然后推演一番。
Neon指令vtrn是解决转置问题的核心。
vtrn

4、边角处理
写惯了基于一行的Neon优化,到这步很容易犯错,一定要记得这里是二维的Neon优化,边角料是两条边。
边角料

代码

该代码仅适用于32位(RGBA)图像的转置。

static void _transpose(unsigned char* dest_s, unsigned char* source_s, int dstw, int srcw, int dw, int dh)
{
    int ista=0,jsta=0;
    const int bpp = 4;//RGBA
#ifdef HAS_NEON
/*矩阵转置示意图
    d1       d2
 x00 x01  x02 x03
    d3       d4
 x10 x11  x12 x13
    d5       d6
 x20 x21  x22 x23
    d7       d8
 x30 x31  x32 x33

       _||_
       \  /
        \/

    d1       d2
 x00 x10  x20 x30
    d3       d4
 x01 x11  x21 x31
    d5       d6
 x02 x12  x22 x32
    d7       d8
 x03 x13  x23 x33
 */

    const int unit = 4;//必须是4
    //GPCLOCK;
    int nw = dw/unit;
    int nh = dh/unit;
    int srcstride = srcw*bpp;
    int dststride = dstw*bpp;
    if (nw > 1 && nh > 1)
    {
        asm (
                     "mov r5, #4\t\n"
                     "mul r8, %[srcstride], r5\t\n"
                     "mul r9, %[dststride], r5\t\n"
                     "mul r10, r5, r5\t\n"//In fact, it's 4*r5
                     "movs r5, %[nh]\t\n"//i
                     "sub r5, r5, #1\t\n"
                     "1:\t\n"
                     "sub r4, %[nw], #1\t\n"//j
                     "2:\t\n"
                     "mla r6, r4, r8, %[source_s]\t\n"
                     "mla r6, r5, r10, r6\t\n"
                     "vld1.32 {d1, d2}, [r6]\t\n"
                     "add r6, r6, %[srcstride]\t\n"
                     "vld1.32 {d3, d4}, [r6]\t\n"
                     "add r6, r6, %[srcstride]\t\n"
                     "vld1.32 {d5, d6}, [r6]\t\n"
                     "add r6, r6, %[srcstride]\t\n"
                     "vld1.32 {d7, d8}, [r6]\t\n"

                     /*Transpose internal*/
                     "vtrn.32 d1, d3\t\n"
                     "vtrn.32 d2, d4\t\n"
                     "vtrn.32 d5, d7\t\n"
                     "vtrn.32 d6, d8\t\n"
                     "vswp d2, d5\t\n"
                     "vswp d4, d7\t\n"

                     "mla r7, r5, r9, %[dest_s]\t\n"
                     "mla r7, r4, r10, r7\t\n"
                     "vst1.32 {d1, d2}, [r7]\t\n"
                     "add r7, r7, %[dststride]\t\n"
                     "vst1.32 {d3, d4}, [r7]\t\n"
                     "add r7, r7, %[dststride]\t\n"
                     "vst1.32 {d5, d6}, [r7]\t\n"
                     "add r7, r7, %[dststride]\t\n"
                     "vst1.32 {d7, d8}, [r7]\t\n"

                     "subs r4, r4, #1\t\n"
                     "bne 2b\t\n"//Loop1

                     "mla r6, r4, r8, %[source_s]\t\n"
                     "mla r6, r5, r10, r6\t\n"
                     "vld1.32 {d1, d2}, [r6]\t\n"
                     "add r6, r6, %[srcstride]\t\n"
                     "vld1.32 {d3, d4}, [r6]\t\n"
                     "add r6, r6, %[srcstride]\t\n"
                     "vld1.32 {d5, d6}, [r6]\t\n"
                     "add r6, r6, %[srcstride]\t\n"
                     "vld1.32 {d7, d8}, [r6]\t\n"

                     /*Transpose internal*/
                     "vtrn.32 d1, d3\t\n"
                     "vtrn.32 d2, d4\t\n"
                     "vtrn.32 d5, d7\t\n"
                     "vtrn.32 d6, d8\t\n"
                     "vswp d2, d5\t\n"
                     "vswp d4, d7\t\n"

                     "mla r7, r5, r9, %[dest_s]\t\n"
                     "mla r7, r4, r10, r7\t\n"
                     "vst1.32 {d1, d2}, [r7]\t\n"
                     "add r7, r7, %[dststride]\t\n"
                     "vst1.32 {d3, d4}, [r7]\t\n"
                     "add r7, r7, %[dststride]\t\n"
                     "vst1.32 {d5, d6}, [r7]\t\n"
                     "add r7, r7, %[dststride]\t\n"
                     "vst1.32 {d7, d8}, [r7]\t\n"

                     "subs r5, r5, #1\t\n"
                     "bne 1b\t\n"//Loop2

                     /*Last line*/
                     "sub r4, %[nw], #1\t\n"//j
                     "4:\t\n"
                     "mla r6, r4, r8, %[source_s]\t\n"
                     "mla r6, r5, r10, r6\t\n"
                     "vld1.32 {d1, d2}, [r6]\t\n"
                     "add r6, r6, %[srcstride]\t\n"
                     "vld1.32 {d3, d4}, [r6]\t\n"
                     "add r6, r6, %[srcstride]\t\n"
                     "vld1.32 {d5, d6}, [r6]\t\n"
                     "add r6, r6, %[srcstride]\t\n"
                     "vld1.32 {d7, d8}, [r6]\t\n"

                     /*Transpose internal*/
                     "vtrn.32 d1, d3\t\n"
                     "vtrn.32 d2, d4\t\n"
                     "vtrn.32 d5, d7\t\n"
                     "vtrn.32 d6, d8\t\n"
                     "vswp d2, d5\t\n"
                     "vswp d4, d7\t\n"

                     "mla r7, r5, r9, %[dest_s]\t\n"
                     "mla r7, r4, r10, r7\t\n"
                     "vst1.32 {d1, d2}, [r7]\t\n"
                     "add r7, r7, %[dststride]\t\n"
                     "vst1.32 {d3, d4}, [r7]\t\n"
                     "add r7, r7, %[dststride]\t\n"
                     "vst1.32 {d5, d6}, [r7]\t\n"
                     "add r7, r7, %[dststride]\t\n"
                     "vst1.32 {d7, d8}, [r7]\t\n"

                     "subs r4, r4, #1\t\n"
                     "bne 4b\t\n"//Loop1
                     "mla r6, r4, r8, %[source_s]\t\n"
                     "mla r6, r5, r10, r6\t\n"
                     "vld1.32 {d1, d2}, [r6]\t\n"
                     "add r6, r6, %[srcstride]\t\n"
                     "vld1.32 {d3, d4}, [r6]\t\n"
                     "add r6, r6, %[srcstride]\t\n"
                     "vld1.32 {d5, d6}, [r6]\t\n"
                     "add r6, r6, %[srcstride]\t\n"
                     "vld1.32 {d7, d8}, [r6]\t\n"

                     /*Transpose internal*/
                     "vtrn.32 d1, d3\t\n"
                     "vtrn.32 d2, d4\t\n"
                     "vtrn.32 d5, d7\t\n"
                     "vtrn.32 d6, d8\t\n"
                     "vswp d2, d5\t\n"
                     "vswp d4, d7\t\n"

                     "mla r7, r5, r9, %[dest_s]\t\n"
                     "mla r7, r4, r10, r7\t\n"
                     "vst1.32 {d1, d2}, [r7]\t\n"
                     "add r7, r7, %[dststride]\t\n"
                     "vst1.32 {d3, d4}, [r7]\t\n"
                     "add r7, r7, %[dststride]\t\n"
                     "vst1.32 {d5, d6}, [r7]\t\n"
                     "add r7, r7, %[dststride]\t\n"
                     "vst1.32 {d7, d8}, [r7]\t\n"

                     "5:\t\n"
                     : [srcstride] "+r" (srcstride), [dststride] "+r" (dststride), [source_s] "+r" (source_s), [dest_s] "+r" (dest_s), [nw] "+r" (nw), [nh] "+r" (nh)
                     :
                     : "r4", "r5", "r6", "r7", "r8", "r9","r10", "cc","memory", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8"
                     );
    }
    ista = nh*unit;
    jsta = nw*unit;
#endif
//边角处理,先处理图像下边缘,再处理图像右边缘
    for (int i=ista; i<dh; ++i)
    {
        for (int j=0; j<dw; ++j)
        {
            unsigned char* dest = dest_s + (i*dstw+j)*bpp;
            unsigned char* source = source_s + (j*srcw+i)*bpp;
            ::memcpy(dest, source, bpp*sizeof(unsigned char));
        }
    }
    for (int i=0; i<ista; ++i)
    {
        for (int j=jsta; j<dw; ++j)
        {
            unsigned char* dest = dest_s + (i*dstw+j)*bpp;
            unsigned char* source = source_s + (j*srcw+i)*bpp;
            ::memcpy(dest, source, bpp*sizeof(unsigned char));
        }
    }
}

加速比率

大约10倍左右性能提升,数据遗失,不补。

目录
相关文章
|
Shell Android开发
Android10.0(Q) 默认应用设置(电话、短信、浏览器、主屏幕应用)
Android10.0(Q) 默认应用设置(电话、短信、浏览器、主屏幕应用)
1333 0
|
Android开发
Android Studio解决导入别人源码报红问题
当我们下载别人的源码导入到自己的Android Studio中时可能出现各种红色警告,不管是Clean Project还是Rebuild Project都不管用,但是尴尬的是源码还能正常运行,那我们该如何解决呢? 解决方法 :点击左上角File——>Invalidate Caches/Restarts.
2155 0
|
机器学习/深度学习
小尺度信道建模 | 带你读《大规模天线波束赋形技术原理与设计 》之二十六
小尺度衰落是指无线电信号在短时间或短距离(若干波长)传播后其幅度、 相位或多径时延的快速变化。这种衰落是由于同一传输信号沿不同的路径传播, 由不同时刻(或相位)到达接收机的信号互相叠加所引起的,这些不同路径到 达的信号称为多径信号,接收机的信号强度取决于多径信号的强度、相对到达 时延以及传输信号的带宽。
10007 1
 小尺度信道建模  | 带你读《大规模天线波束赋形技术原理与设计 》之二十六
|
Kubernetes API 调度
在K8S中,创建pod过程?
在K8S中,创建pod过程?
|
11月前
|
缓存 监控 网络协议
Linux操作系统的内核优化与实践####
本文旨在探讨Linux操作系统内核的优化策略与实际应用案例,深入分析内核参数调优、编译选项配置及实时性能监控的方法。通过具体实例讲解如何根据不同应用场景调整内核设置,以提升系统性能和稳定性,为系统管理员和技术爱好者提供实用的优化指南。 ####
|
JSON 监控 Java
Elasticsearch 入门:搭建高性能搜索集群
【9月更文第2天】Elasticsearch 是一个分布式的、RESTful 风格的搜索和分析引擎,基于 Apache Lucene 构建。它能够处理大量的数据,提供快速的搜索响应。本教程将指导你如何从零开始搭建一个基本的 Elasticsearch 集群,并演示如何进行简单的索引和查询操作。
636 3
|
安全 大数据 网络安全
网络安全与信息安全:守护数字世界的坚盾在数字化浪潮席卷全球的今天,网络安全已成为维系社会稳定、促进经济发展的重要基石。本文旨在深入探讨网络安全漏洞、加密技术及安全意识等核心议题,通过分享前沿知识与实用策略,助力构建更加安全可靠的网络环境。
【10月更文挑战第8天】 本文聚焦网络安全领域的关键要素,包括安全漏洞的识别与防御、加密技术的演进与应用,以及安全意识的培养与提升。通过对最新研究成果和实际案例的分析,文章揭示了网络安全威胁的多样性和复杂性,强调了综合防护策略的重要性。同时,倡导社会各界共同参与,形成全民网络安全意识,共筑数字空间的安全防线。
312 0
|
持续交付 开发工具 git
如何保留原提交记录迁移Git项目,你还不知道吗?
如何保留原提交记录迁移Git项目,你还不知道吗?
如何保留原提交记录迁移Git项目,你还不知道吗?
|
传感器 机器学习/深度学习 编解码
2022最新综述!一文详解自动驾驶中的多模态融合感知算法(数据级/特征级/目标级)
多模态传感器融合意味着信息互补、稳定和安全,长期以来都是自动驾驶感知的重要一环。然而信息利用的不充分、原始数据的噪声及各个传感器间的错位(如时间戳不同步),这些因素都导致融合性能一直受限。本文全面调研了现有多模态自动驾驶感知算法,传感器包括LiDAR和相机,聚焦于目标检测和语义分割,分析超过50篇文献。同传统融合算法分类方法不同,本文从融合阶段的不同将该领域分类两大类、四小类。此外,本文分析了当前领域存在的问题,对未来的研究方向提供参考。
2022最新综述!一文详解自动驾驶中的多模态融合感知算法(数据级/特征级/目标级)
|
数据安全/隐私保护
【数字IC手撕代码】Verilog伪随机数生成器|线性反馈移位寄存器|题目|原理|设计|仿真
【数字IC手撕代码】Verilog伪随机数生成器|线性反馈移位寄存器|题目|原理|设计|仿真
【数字IC手撕代码】Verilog伪随机数生成器|线性反馈移位寄存器|题目|原理|设计|仿真