我有一个C代码,它是公共存储库(暗网)的一部分,它应该使用双线性插值来调整图像的大小。由于其他代码处理图像的方式,图像存储为一维数组,其中从原始的3通道图像中读取像素值是大步的。因此,与像素(x, y, k) (x: column,y: row,k: channel)相对应的值存储在一维数组中的位置x + w.h + w.h.c中。
实际上是Darknet一部分的调整大小函数在预处理阶段花费了相当长的时间,这可能是因为它嵌套的for循环迭代行和列,并试图访问相应的值,以及类型转换:因此,我试图创建一个更优化的版本。调整大小的原始代码如下所示。im是原始图像,因此im.w和im.h是原始的宽度和高度。w和h是目标的宽度和高度。
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;
}有没有办法使这个函数更快:例如,通过创建一种更优化的方法来访问像素,而不是这种跨越式读取?此外,我在此指出,就我而言:
我必须在这里指出,由于我的项目的需求,这个调整大小的函数实际上是从Python调用的库(.so)的一部分。所以我不能保存任何“在内存中”本身,如CUDA纹理对象等,因此一次又一次地创建它们实际上可能会在CUDA方面产生更多的开销。
任何改进这一惯例的建议都会很有帮助。
发布于 2018-04-27 01:26:23
正如Stargateur提到的,get_pixel et.艾尔很浪费。大多数像素访问都可以用指针处理。在处理需要速度的图像时,这是一件非常标准的事情。
大多数访问沿着x维度移动,因此我们只需增加指针。
在get_pixel中,创建以下函数:
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
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;
}https://stackoverflow.com/questions/50048626
复制相似问题