首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >调整存储为“跨栏”数组的图像大小:我能使这种双线性插值更快吗?

调整存储为“跨栏”数组的图像大小:我能使这种双线性插值更快吗?
EN

Stack Overflow用户
提问于 2018-04-26 17:13:38
回答 1查看 186关注 0票数 1

我有一个C代码,它是公共存储库(暗网)的一部分,它应该使用双线性插值来调整图像的大小。由于其他代码处理图像的方式,图像存储为一维数组,其中从原始的3通道图像中读取像素值是大步的。因此,与像素(x, y, k) (x: column,y: row,k: channel)相对应的值存储在一维数组中的位置x + w.h + w.h.c中。

实际上是Darknet一部分的调整大小函数在预处理阶段花费了相当长的时间,这可能是因为它嵌套的for循环迭代行和列,并试图访问相应的值,以及类型转换:因此,我试图创建一个更优化的版本。调整大小的原始代码如下所示。im是原始图像,因此im.wim.h是原始的宽度和高度。wh是目标的宽度和高度。

代码语言:javascript
复制
image resize_image(image im, int w, int h)
{
    image resized = make_image(w, h, im.c);   
    image part = make_image(w, im.h, im.c);
    int r, c, k;
    float w_scale = (float)(im.w - 1) / (w - 1);
    float h_scale = (float)(im.h - 1) / (h - 1);
    for(k = 0; k < im.c; ++k){
        for(r = 0; r < im.h; ++r){
            for(c = 0; c < w; ++c){
                float val = 0;
                if(c == w-1 || im.w == 1){
                    val = get_pixel(im, im.w-1, r, k);
                } else {
                    float sx = c*w_scale;
                    int ix = (int) sx;
                    float dx = sx - ix;
                    val = (1 - dx) * get_pixel(im, ix, r, k) + dx * get_pixel(im, ix+1, r, k);
                }
                set_pixel(part, c, r, k, val);
            }
        }
    }
    for(k = 0; k < im.c; ++k){
        for(r = 0; r < h; ++r){
            float sy = r*h_scale;
            int iy = (int) sy;
            float dy = sy - iy;
            for(c = 0; c < w; ++c){
                float val = (1-dy) * get_pixel(part, c, iy, k);
                set_pixel(resized, c, r, k, val);
            }
            if(r == h-1 || im.h == 1) continue;
            for(c = 0; c < w; ++c){
                float val = dy * get_pixel(part, c, iy+1, k);
                add_pixel(resized, c, r, k, val);
            }
        }
    }
    free_image(part);
    return resized;
}

有没有办法使这个函数更快:例如,通过创建一种更优化的方法来访问像素,而不是这种跨越式读取?此外,我在此指出,就我而言:

  1. 源图像和调整大小图像的尺寸将是固定的,因此我的“自定义”调整大小函数不必与大小无关。我要从640x360到尺寸626x352。
  2. 目标平台是一个带有ARM CPU的NVIDIA,所以像AVX2这样的指令不适用于我的情况。但我确实有机会进入数据自动化系统。

我必须在这里指出,由于我的项目的需求,这个调整大小的函数实际上是从Python调用的库(.so)的一部分。所以我不能保存任何“在内存中”本身,如CUDA纹理对象等,因此一次又一次地创建它们实际上可能会在CUDA方面产生更多的开销。

任何改进这一惯例的建议都会很有帮助。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-04-27 01:26:23

正如Stargateur提到的,get_pixel et.艾尔很浪费。大多数像素访问都可以用指针处理。在处理需要速度的图像时,这是一件非常标准的事情。

大多数访问沿着x维度移动,因此我们只需增加指针。

get_pixel中,创建以下函数:

代码语言:javascript
复制
static float *loc_pixel(image m, int x, int y, int c)
{
    return &m.data[(c * m.h * m.w) + (y * m.w) + x];
}

通过一些重组,if in resize_image可以从第一个内部for循环中移出。

在所有for循环中,我们可以通过使用loc_pixel和指针从内部循环中删除所有*_pixel函数。

下面是一个重构版本,它只使用应该更快的指针。请注意,我已经编写了这个代码,但既没有测试也没有编译它。我想已经很近了,但你应该再检查一遍。

您可以补充一点,我没有做的一件事是让loc_pixel接受一个指向图像的指针(即image *m),而不是传递整个结构。

此外,您还可以尝试用src[c]代替src[c],用dst[c]代替*dst。这将消除一些++src++dst,而且可能会更快。它还可能允许编译器更好地理解循环,因此它可以使用任何arm矢量指令,并可能使它更易于使用CUDA。YMMV

代码语言:javascript
复制
image
resize_image(image im, int w, int h)
{
    image resized = make_image(w, h, im.c);
    image part = make_image(w, im.h, im.c);
    int r,
     c,
     k;
    float w_scale = (float) (im.w - 1) / (w - 1);
    float h_scale = (float) (im.h - 1) / (h - 1);
    int wm1 = w - 1;
    float val;
    float marg;
    float *src;
    float *dst;

    for (k = 0; k < im.c; ++k) {
        for (r = 0; r < im.h; ++r) {
            src = loc_pixel(im, 0, r, k);
            dst = loc_pixel(part, 0, r, k);
            marg = get_pixel(im, im.w - 1, r, k);

            if (im.w == 1) {
                for (c = 0; c < w; ++c, ++dst)
                    *dst = marg;
                continue;
            }

            for (c = 0; c < wm1; ++c, ++src, ++dst) {
                float sx = c * w_scale;
                int ix = (int) sx;
                float dx = sx - ix;
                val = (1 - dx) * src[0] + dx * src[1];
                *dst = val;
            }

            // handle c == w - 1 case
            *dst = marg;
        }
    }

    for (k = 0; k < im.c; ++k) {
        for (r = 0; r < h; ++r) {
            float sy = r * h_scale;
            int iy = (int) sy;
            float dy = sy - iy;

            src = loc_pixel(part, 0, iy, k);
            dst = loc_pixel(resized, 0, r, k);
            for (c = 0; c < w; ++c, ++src, ++dst) {
                val = (1 - dy) * src[0];
                *dst = val;
            }

            if (r == h - 1 || im.h == 1)
                continue;

            src = loc_pixel(part, 0, iy + 1, k);
            dst = loc_pixel(resized, 0, r, k, val);
            for (c = 0; c < w; ++c, ++src, ++dst) {
                val = dy * src[0];
                *dst += val;
            }
        }
    }

    free_image(part);
    return resized;
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50048626

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档