如何通过 p5.js 中的噪声扭曲图像

How to distort an image by noise in p5.js

我正在尝试生成一个函数,该函数从源图像开始,生成噪声,然后使用噪声扭曲图像。
我从创建噪声开始,并将其转换为矢量场,然后我重新映射坐标,并在正确的坐标处将像素从图像中拉出。
最后,我将提取的像素重新组合成图像。

目前我的代码如下:

function distort(sourceImage){
  let vectorField = [];
  var amount = 100;
  var scale = 0.01;
  for (x = 0; x < sourceImage.width; x++){
    let row = [];
    for (y = 0; y < sourceImage.height; y++){
      let vector = createVector(amount*(noise(scale*x,scale*y)-0.5), 4*amount*(noise(100+scale*x,scale*y)-0.5))
      row.push(vector);
    }
    vectorField.push(row);
  }

  var result = [];
  sourceImage.loadPixels();
  for (i = 0; i < sourceImage.width; i++){ //sourceImage.width
    for (j = 0; j < sourceImage.height; j += 4){ //sourceImage.height
      var res = vectorField[i][j];
      //console.log(res);

      var ii = constrain(floor(i + res.x), 0, sourceImage.width - 1);
      var jj = constrain(floor(j + res.y), 0, sourceImage.height - 1);
      //console.log(ii, jj);

      result[i * sourceImage.width + j] = color(sourceImage.pixels[ii * sourceImage.width + jj], sourceImage.pixels[ii * sourceImage.width + jj + 1], sourceImage.pixels[ii * sourceImage.width + jj + 2], sourceImage.pixels[ii * sourceImage.width + jj + 3]);
    }
  }
  //console.log(result)
  //console.log(sourceImage.pixels[0 + sourceImage.width * 0])

  for (n=0; n<sourceImage.width; n++) {
    for(m=0; m<sourceImage.height; m++){
      index = (n * sourceImage.width + m) * 4;
      if (index >= 4194300){
        index = 4194300;
      }
      sourceImage.pixels[index] = red(result[index]);
      sourceImage.pixels[index + 1] = green(result[index]);
      sourceImage.pixels[index + 2] = blue(result[index]);
      sourceImage.pixels[index + 3] = alpha(result[index]);
    }
  }


  sourceImage.updatePixels();
  image(sourceImage, 0, 0, size, size);
}

除此之外,我在 canvas 的前 4 个区域收到了 4 个噪声面板。噪音特别包括很多我知道也不在源图像中的像素(即蓝色像素;我试图扭曲的图像是红色和白色)。噪点在某种程度上是可识别的,因为它最初是源图像,但失真并带有上述人工制品。

比较:

你没有完全处理矢量场,你必须从场中读取每个矢量。实际上你只读了向量的第 4 个元素

for (j = 0; j < sourceImage.height; j += 4)

for (j = 0; j < sourceImage.height; j++)

而且源索引的计算是错误的。请注意,行 (jj) 的控制变量必须乘以高度。数组中像素的索引必须乘以4,因为每个像素由4个颜色通道组成:

ii * sourceImage.width + jj

(jj * sourceImage.width + ii) * 4

目标索引的计算也有误:

index = (n * sourceImage.width + m) * 4;

index = (m * sourceImage.width + n) * 4;

注意,result 每个像素包含 1 个元素,而 sourceImage.pixels 每个像素包含 4 个元素。因此从结果中读取的索引和访问目标的索引是不同的:

let result_i = m * sourceImage.width + n;
let target_i = result_i * 4;

例如:

let result = [];
for (let j = 0; j < sourceImage.height; j++) {
    for (let i = 0; i < sourceImage.width; i++) {

      let res = vectorField[i][j];

      let ii = constrain(floor(i + res.x), 0, sourceImage.width - 1);
      let jj = constrain(floor(j + res.y), 0, sourceImage.height - 1);

      let source_i = (jj * sourceImage.width + ii) * 4;
      let col = color(
          sourceImage.pixels[source_i],
          sourceImage.pixels[source_i + 1],
          sourceImage.pixels[source_i + 2],
          sourceImage.pixels[source_i + 3]);

      result.push(col);
    }
}

for(let m = 0; m < sourceImage.height; m++) {
    for (let n = 0; n < sourceImage.width; n++) {

        let result_i = m * sourceImage.width + n;
        let target_i = result_i * 4;

        let col = result[result_i];
        sourceImage.pixels[target_i]     = red(col);
        sourceImage.pixels[target_i + 1] = green(col);
        sourceImage.pixels[target_i + 2] = blue(col);
        sourceImage.pixels[target_i + 3] = alpha(col);
    }
}