图像转置的Neon优化代码

图像转置的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倍左右性能提升,数据遗失,不补。

<think>好的,我现在要帮用户解决在MATLAB中对图像进行转置处理的问题。用户之前已经问过镜像翻转的代码,现在问的是转置处理的代码。首先,我需要明确转置图像处理中的含义。转置通常指的是矩阵的转置,也就是将行和列交换,对应到图像上就是沿主对角线翻转,即左上到右下的对角线。 接下来,我需要回忆MATLAB中用于转置的操作符。知道在MATLAB中,矩阵的转置可以使用单引号'或者transpose函数。但需要注意的是,单引号在MATLAB中是共轭转置,对于实数矩阵来说没有区别,但对于复数矩阵会有影响。不过图像数据通常是实数,所以这里用单引号应该没问题。不过为了明确,可能应该推荐使用transpose函数,或者更稳妥的方式,因为图像可能是三维矩阵(彩色图像),转置可能需要处理每个颜色通道。 然后,我需要考虑图像的类型。如果是灰度图像,它是一个二维矩阵,直接转置即可。但如果是彩色图像,是三维矩阵(行×列×通道),直接转置会导致维度错误,因为转置默认只处理前两个维度。这时候需要分别对每个颜色通道进行转置,或者使用permute函数调整维度顺序。 用户可能不知道如何处理彩色图像转置,所以需要给出两种情况的代码:灰度图和彩色图的处理方式。可能还需要提醒用户注意图像尺寸的变化,转置后宽高会互换,显示时可能需要调整坐标轴或者图像大小。 另外,需要检查之前的回答是否已经涉及转置,但用户之前的问题是关于镜像翻转,所以转置是新的操作。可能需要比较转置和镜像的区别,避免混淆。例如,转置是沿对角线翻转,而水平镜像是左右翻转,垂直是上下翻转,同时两者则是旋转180度。 然后,我需要考虑代码的正确性。例如,对于彩色图像,使用transpose可能不会正确转置每个通道,因此需要遍历每个通道或者使用permute。例如,permute(img, [2 1 3])会将行和列交换,保持通道不变,这适用于彩色图像。而transpose可能只处理前两个维度,但需要验证。 另外,需要注意图像的数据类型,比如uint8是否需要转换,但MATLAB的图像处理函数通常处理这些类型。不过,在转置时可能需要确保数据类型正确,但通常不会有问题。 最后,需要给出示例代码,展示如何读取图像,进行转置,并显示结果。同时,可能需要提醒用户转置后的图像尺寸变化,以及可能的显示问题,比如使用imshow时图像可能会被拉伸,可以使用axis image保持比例。 总结步骤: 1. 读取图像,区分灰度和彩色。 2. 对灰度图使用transpose或permute([2 1])。 3. 对彩色图使用permute([2 1 3])。 4. 显示结果,比较原图和转置后的图像。 5. 提醒注意事项,比如复数数据、显示调整等。</think>以下是在MATLAB中实现图像转置(沿主对角线翻转,即行与列交换)的代码及详细说明: --- ### **核心代码示例** #### **1. 灰度图像转置** ```matlab % 读取灰度图 gray_img = imread('gray_image.jpg'); % 方法1:使用transpose函数 transposed_gray = transpose(gray_img); % 方法2:使用单引号运算符(等价转置) % transposed_gray = gray_img'; % 显示对比 subplot(1,2,1), imshow(gray_img), title('原图 (灰度)'); subplot(1,2,2), imshow(transposed_gray), title('转置后'); ``` #### **2. 彩色图像转置** ```matlab % 读取彩色图 rgb_img = imread('color_image.jpg'); % 对每个颜色通道分别转置(RGB三通道需保持顺序) transposed_rgb = permute(rgb_img, [2 1 3]); % 交换行和列维度 % 显示对比 figure; subplot(1,2,1), imshow(rgb_img), title('原图 (彩色)'); subplot(1,2,2), imshow(transposed_rgb), title('转置后'); ``` --- ### **关键原理说明** - **数学定义**: 图像转置对应矩阵的转置操作,即像素坐标从$(i,j)$变为$(j,i)$,表现为沿主对角线翻转。 - **维度处理**: - 灰度图:二维矩阵(高度×宽度),直接使用`transpose`或`'`运算符 - 彩色图:三维矩阵(高度×宽度×通道),需通过`permute(img, [2 1 3])`交换前两个维度 - **效果对比**: - 转置 ≠ 镜像翻转(镜像沿垂直/水平轴,转置沿对角线) - 转置图像宽高尺寸互换(原图$H×W$ → 转置后$W×H$) --- ### **进阶应用:仿射变换实现** ```matlab % 构建转置变换矩阵(交换x和y坐标) T = [0 1 0; 1 0 0; 0 0 1]; % 执行变换(需Image Processing Toolbox) transposed_img = imwarp(img, affine2d(T)); ``` --- ### **注意事项** 1. **显示适配**: 转置图像宽高比变化,建议使用`axis image`保持像素比例: ```matlab imshow(transposed_img), axis image; ``` 2. **复数数据警告**: 若图像含复数数据,`'`运算符会进行共轭转置,此时应使用`transpose()`函数。 3. **高效替代方案**: 对于大规模图像,`permute`比逐通道转置更高效: ```matlab % 低效写法(循环转置每个通道) % transposed_rgb(:,:,1) = rgb_img(:,:,1)'; % transposed_rgb(:,:,2) = rgb_img(:,:,2)'; % transposed_rgb(:,:,3) = rgb_img(:,:,3)'; ``` --- ### **效果示意图** 转置操作几何意义可表示为: $$ \text{转置变换}: (x,y) \to (y,x) $$ 其中原图尺寸为$H \times W$,转置后变为$W \times H$。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值