如何优化这个for循环的计算速度?
How to optimize the computing speed of this for loop?
我遇到了一个难题(至少对我而言)。在分析我的代码时,我注意到几乎所有(单核)计算时间都被下面的单个嵌套循环(图像上的双积分)耗尽了。您认为加速其计算的最佳方式是什么?
我试图将它映射到嵌套流,但我不明白如何映射多个 if
块...尝试在 GPU 上使用 OpenCL 进行映射是否更适合该问题?
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);
你没有给出太多关于循环中发生了什么的信息,例如,变量是什么 'ip'。但总的来说,我建议在 for 循环范围之外实例化变量,因为使用局部变量会增加内存使用量
您可以尝试分而治之方法。
将图像分成 n 个部分,并行处理。
但是你必须处理边界上发生的边缘情况(两部分相遇的地方)。
或者您可以开始寻找计算(离散)积分并专为并行设计的数值算法。
更新
由于您的方法被称为 contrast
,我假设您正在更改图像的对比度。
图像操作可以通过卷积(如果在二维图像上执行,本质上是离散二重积分)与特定的kernel (image filter). These operations can be computed on the GPU and yield speed-ups by orders of magnitude. You can use OpenCl来编写可在多个 GPU 上执行的程序。
我遇到了一个难题(至少对我而言)。在分析我的代码时,我注意到几乎所有(单核)计算时间都被下面的单个嵌套循环(图像上的双积分)耗尽了。您认为加速其计算的最佳方式是什么?
我试图将它映射到嵌套流,但我不明白如何映射多个 if
块...尝试在 GPU 上使用 OpenCL 进行映射是否更适合该问题?
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);
你没有给出太多关于循环中发生了什么的信息,例如,变量是什么 'ip'。但总的来说,我建议在 for 循环范围之外实例化变量,因为使用局部变量会增加内存使用量
您可以尝试分而治之方法。
将图像分成 n 个部分,并行处理。 但是你必须处理边界上发生的边缘情况(两部分相遇的地方)。
或者您可以开始寻找计算(离散)积分并专为并行设计的数值算法。
更新
由于您的方法被称为 contrast
,我假设您正在更改图像的对比度。
图像操作可以通过卷积(如果在二维图像上执行,本质上是离散二重积分)与特定的kernel (image filter). These operations can be computed on the GPU and yield speed-ups by orders of magnitude. You can use OpenCl来编写可在多个 GPU 上执行的程序。