首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >优化javascript策略

优化javascript策略
EN

Stack Overflow用户
提问于 2018-03-06 08:28:49
回答 1查看 62关注 0票数 0

我编写了一个javascript程序,它使用遗传算法仅使用三角形重新创建图像。以下是策略:

  • 生成一个随机的模型池,每个模型都有一个三角形数组(3个点和一个颜色)。
  • 评估每个模型的适应度。为此,我将原始图像的像素数组与模型的像素数组进行比较。
  • 保留最好的模型,并将它们配对以创建新的模型。
  • 随机变异一些模型
  • 评估新的池并继续

您可以在这里看到,经过一些迭代之后,它运行得相当好:

我的问题是,它非常慢,大部分时间用于获取模型的像素(将三角形列表(颜色+点)转换为像素数组)。我现在是这样做的:

我的像素数组是一个一维数组,我需要能够将x,y坐标转换为索引:

代码语言:javascript
运行
复制
static getIndex(x, y, width) {
  return 4 * (width * y + x);
}

然后我就能得出一个观点:

代码语言:javascript
运行
复制
static plot(x, y, color, img) {
  let idx = this.getIndex(x, y, img.width);

  let added = [color.r, color.g, color.b, map(color.a, 0, 255, 0, 1)];
  let base = [img.pixels[idx], img.pixels[idx + 1], img.pixels[idx + 2], map(img.pixels[idx + 3], 0, 255, 0, 1)];
  let a01 = 1 - (1 - added[3]) * (1 - base[3]);

  img.pixels[idx + 0] = Math.round((added[0] * added[3] / a01) + (base[0] * base[3] * (1 - added[3]) / a01)); // red
  img.pixels[idx + 1] = Math.round((added[1] * added[3] / a01) + (base[1] * base[3] * (1 - added[3]) / a01)); // green
  img.pixels[idx + 2] = Math.round((added[2] * added[3] / a01) + (base[2] * base[3] * (1 - added[3]) / a01)); // blue
  img.pixels[idx + 3] = Math.round(map(a01, 0, 1, 0, 255));
}

然后是一行:

代码语言:javascript
运行
复制
 static line(x0, y0, x1, y1, img, color) {
  x0 = Math.round(x0);
  y0 = Math.round(y0);
  x1 = Math.round(x1);
  y1 = Math.round(y1);
  let dx = Math.abs(x1 - x0);
  let dy = Math.abs(y1 - y0);
  let sx = x0 < x1 ? 1 : -1;
  let sy = y0 < y1 ? 1 : -1;
  let err = dx - dy;

  do {
    this.plot(x0, y0, color, img);
    let e2 = 2 * err;
    if (e2 > -dy) {
      err -= dy;
      x0 += sx;
    }
    if (e2 < dx) {
      err += dx;
      y0 += sy;
    }
  } while (x0 != x1 || y0 != y1);
}

最后,一个三角形:

代码语言:javascript
运行
复制
static drawTriangle(triangle, img) {
  for (let i = 0; i < triangle.points.length; i++) {
    let point = triangle.points[i];
    let p1 =
      i === triangle.points.length - 1
        ? triangle.points[0]
        : triangle.points[i + 1];
    this.line(point.x, point.y, p1.x, p1.y, img, triangle.color);
  }
  this.fillTriangle(triangle, img);
}

static fillTriangle(triangle, img) {
  let vertices = Array.from(triangle.points);
  vertices.sort((a, b) => a.y > b.y);
  if (vertices[1].y == vertices[2].y) {
    this.fillBottomFlatTriangle(vertices[0], vertices[1], vertices[2], img, triangle.color);
  } else if (vertices[0].y == vertices[1].y) {
    this.fillTopFlatTriangle(vertices[0], vertices[1], vertices[2], img, triangle.color);
  } else {
    let v4 = {
      x: vertices[0].x + float(vertices[1].y - vertices[0].y) / float(vertices[2].y - vertices[0].y) * (vertices[2].x - vertices[0].x),
    y: vertices[1].y
    };
    this.fillBottomFlatTriangle(vertices[0], vertices[1], v4, img, triangle.color);
    this.fillTopFlatTriangle(vertices[1], v4, vertices[2], img, triangle.color);
  }
}

static fillBottomFlatTriangle(v1, v2, v3, img, color) {
  let invslope1 = (v2.x - v1.x) / (v2.y - v1.y);
  let invslope2 = (v3.x - v1.x) / (v3.y - v1.y);

  let curx1 = v1.x;
  let curx2 = v1.x;

  for (let scanlineY = v1.y; scanlineY <= v2.y; scanlineY++) {
    this.line(curx1, scanlineY, curx2, scanlineY, img, color);
    curx1 += invslope1;
    curx2 += invslope2;
  }
}

static fillTopFlatTriangle(v1, v2, v3, img, color) {
  let invslope1 = (v3.x - v1.x) / (v3.y - v1.y);
  let invslope2 = (v3.x - v2.x) / (v3.y - v2.y);

  let curx1 = v3.x;
  let curx2 = v3.x;

  for (let scanlineY = v3.y; scanlineY > v1.y; scanlineY--) {
    this.line(curx1, scanlineY, curx2, scanlineY, img, color);
    curx1 -= invslope1;
    curx2 -= invslope2;
  }
}

您可以在操作中看到完整的代码这里

所以,我想知道:

  • 有可能优化这段代码吗?
  • 如果是的话,最好的办法是什么?也许有一个图书馆比我做得更好?还是利用工人?

谢谢!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-03-06 15:44:35

我已经测试了你的建议,结果如下:

  • 使用均方根而不是余弦相似度:如果相似性度量更好,我不确定,但它肯定不是更糟。它似乎也跑得更快了。
  • 使用UInt8Array:它肯定会产生影响,但不会运行得更快。但不是慢点。
  • 绘制到不可见的画布:绝对更快和更容易!我可以删除我的所有绘图函数,用几行代码替换它,它运行得更快!

下面是绘制到不可见画布上的代码:

代码语言:javascript
运行
复制
var canvas = document.createElement('canvas');
canvas.id = "CursorLayer";
canvas.width = this.width;
canvas.height = this.height;
canvas.display = "none";
var body = document.getElementsByTagName("body")[0];
body.appendChild(canvas);

var ctx = canvas.getContext("2d");
ctx.fillStyle = "rgba(0, 0, 0, 1)";
ctx.fillRect(0, 0, this.width, this.height);

for (let i = 0; i < this.items.length; i++) {
  let item = this.items[i];
  ctx.fillStyle = "rgba(" +item.color.r + ','+item.color.g+','+item.color.b+','+map(item.color.a, 0, 255, 0, 1)+")";
  ctx.beginPath();
  ctx.moveTo(item.points[0].x, item.points[0].y);
  ctx.lineTo(item.points[1].x, item.points[1].y);
  ctx.lineTo(item.points[2].x, item.points[2].y);
  ctx.fill();
}
let pixels = ctx.getImageData(0, 0, this.width, this.height).data;
//delete canvas
body.removeChild(canvas);
return pixels;

在这些更改之前,我的代码以每秒1.68次迭代的速度运行。现在它以每秒16.45次的迭代速度运行!

参见完整代码这里

再次感谢!

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49126341

复制
相关文章

相似问题

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