【问题标题】:How to optimize the computing speed of this for loop?如何优化这个for循环的计算速度?
【发布时间】:2015-06-02 03:43:03
【问题描述】:

我有点被一个难题困住了(至少对我来说)。在分析我的代码时,我注意到我几乎所有的(单核)计算时间都被下面的单个嵌套循环(图像上的双积分)消耗掉了。您认为加速其计算的最佳方式是什么?

我尝试将其映射到嵌套流,但我不明白如何映射多个 if 块...尝试使用 OpenCL 在 GPU 上执行此操作是否更适合该问题?

ip 是一个 ImageJ ImageProcessor,它的方法 .getPixelValue(x,y) 也非常消耗资源。但由于它属于已建立的库,因此我想尽可能避免对其进行修改。

变量声明:

private ImageProcessor ip = null; //This type comes from ImageJ
private double area;
private double a11, a22;
private double u1, u2;
private double v1, v2;
private double y1, y2;
private static final double HALF_SQRT2 = sqrt(2.0) / 2.0;
private static final double SQRT_TINY =
    sqrt((double)Float.intBitsToFloat((int)0x33FFFFFF));

功能:

private double contrast (
) {
    if (area < 1.0) {
        return(1.0 / SQRT_TINY);
    }
    double c = 0.0;
    final int xmin = max((int)floor(u1), 0);
    final int xmax = min((int)ceil(v1), width - 1);
    final int ymin = max((int)floor(u2), 0);
    final int ymax = min((int)ceil(v2), height - 1);
    if ((u1 < xmin) || (xmax < v1) || (u2 < ymin) || (ymax < v2)){
        return(1.0 / SQRT_TINY);
    }
    if ((xmax <= xmin) || (ymax <= ymin)) {
        return(1.0 / SQRT_TINY);
    }
    for (int y = ymin; (y <= ymax); y++) {
        final double dy = y2 - (double)y;
        final double dy2 = dy * dy;
        for (int x = xmin; (x <= xmax); x++) {
            final double dx = y1 - (double)x;
            final double dx2 = dx * dx;
            final double d = sqrt(dx2 + dy2);
            double z = a11 * dx2 + a12 * dx * dy + a22 * dy2;
            if (z < SQRT_TINY) {
                c -= ip.getPixelValue(x, y);
                continue;
            }
            z = a3 / sqrt(z);
            double d0 = (1.0 - z / SQRT2) * d;
            if (d0 < -HALF_SQRT2) {
                c -= ip.getPixelValue(x, y);
                continue;
            }
            if (d0 < HALF_SQRT2) {
                c += SQRT2 * d0 * ip.getPixelValue(x, y);
                continue;
            }
            d0 = (1.0 - z) * d;
            if (d0 < -1.0) {
                c += ip.getPixelValue(x, y);
                continue;
            }
            if (d0 < 1.0) {
                c += (1.0 - d0) * ip.getPixelValue(x, y) / 2.0;
                continue;
            }
        }
    }
    return(c / area);

【问题讨论】:

  • 不知道如何帮助您加快代码速度,但您的代码可能会减少一些额外的括号。不需要额外的括号,请参阅运算符优先级docs.oracle.com/javase/tutorial/java/nutsandbolts/…if (u1 &lt; xmin || xmax &lt; v1 || u2 &lt; ymin || ymax &lt; v2)。请参阅 Java 编码约定(第 7.3 节),您应该坚持在 return c / area; 中不加括号,祝您好运!:)

标签: java algorithm optimization parallel-processing scientific-computing


【解决方案1】:

您没有提供太多关于循环中发生的事情的信息,例如,变量“ip”是什么。但总的来说,我建议在 for 循环范围之外实例化变量,因为使用局部变量会增加内存使用率

【讨论】:

  • 是的,你是对的。我在我的问题中添加了变量声明。
【解决方案2】:

您可以尝试分而治之的方法。

将图像分成 n 个部分,并行处理。 但是您必须处理边界(两部分相交处)发生的边缘情况。

或者您可以开始寻找计算(离散)积分并为并行性而设计的数值算法。

更新

由于您的方法称为contrast,我假设您正在更改图像的对比度。

可以通过带有特定kernel(图像过滤器)的卷积(如果在二维图像上执行,本质上是一个离散的双积分)对图像执行操作。这些操作可以在 GPU 上计算并产生数量级的加速。您可以使用 OpenCl 编写在多个 GPU 上执行的程序。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-07
    • 2019-09-27
    • 2021-02-26
    • 1970-01-01
    • 1970-01-01
    • 2020-01-19
    • 1970-01-01
    相关资源
    最近更新 更多