图像转置的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) 默认应用设置(电话、短信、浏览器、主屏幕应用)
1285 0
|
Android开发
Android Studio解决导入别人源码报红问题
当我们下载别人的源码导入到自己的Android Studio中时可能出现各种红色警告,不管是Clean Project还是Rebuild Project都不管用,但是尴尬的是源码还能正常运行,那我们该如何解决呢? 解决方法 :点击左上角File——>Invalidate Caches/Restarts.
2126 0
|
Python
Python中解包使用星号(*)进行灵活解包
【6月更文挑战第21天】
358 2
|
Kubernetes API 调度
在K8S中,创建pod过程?
在K8S中,创建pod过程?
|
11月前
|
缓存 监控 网络协议
Linux操作系统的内核优化与实践####
本文旨在探讨Linux操作系统内核的优化策略与实际应用案例,深入分析内核参数调优、编译选项配置及实时性能监控的方法。通过具体实例讲解如何根据不同应用场景调整内核设置,以提升系统性能和稳定性,为系统管理员和技术爱好者提供实用的优化指南。 ####
|
JSON 监控 Java
Elasticsearch 入门:搭建高性能搜索集群
【9月更文第2天】Elasticsearch 是一个分布式的、RESTful 风格的搜索和分析引擎,基于 Apache Lucene 构建。它能够处理大量的数据,提供快速的搜索响应。本教程将指导你如何从零开始搭建一个基本的 Elasticsearch 集群,并演示如何进行简单的索引和查询操作。
620 3
|
持续交付 开发工具 git
如何保留原提交记录迁移Git项目,你还不知道吗?
如何保留原提交记录迁移Git项目,你还不知道吗?
如何保留原提交记录迁移Git项目,你还不知道吗?
|
负载均衡 Java Apache
SpringCloud极简入门-使用RestTemplate实现服务通信
目前除了Eureka Server以外我们的微服务有订单服务springcloud-order-server-1030,和用户服务springcloud-user-server-1020 , 我们就用这两个服务来演示微服务的通信,他们的调用关系应该是:浏览器 -> 订单服务 -> 用户服务,
267 0
|
人工智能 缓存 移动开发
通用矩阵乘算法从入门到实践
通用矩阵乘算法从入门到实践
479 0
|
传感器 前端开发 Java
Android流媒体开发之路一:Camera2采集摄像头原始数据并手动预览
Android流媒体开发之路一:Camera2采集摄像头原始数据并手动预览
1008 0