Как исказить изображение шумом в p5. js - PullRequest
1 голос
/ 09 мая 2020

Я пытаюсь создать функцию, которая начинается с исходного изображения, генерирует шум, а затем использует шум для искажения изображения.
Я начинаю с создания шума и превращаю его в векторное поле. Затем я переназначить координаты и вытащить пиксели из изображения с правильными координатами.
Наконец, я повторно объединяю извлеченные пиксели в изображение.

Пока мой код выглядит следующим образом:

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);
}

За исключением того, что в результате я получаю 4 панели шума в верхней 4 части холста. В частности, шум включает в себя множество пикселей, которых, как я знаю, также не было в исходном изображении (а именно синие пиксели; изображение, которое я пытаюсь исказить, является красно-белым). Шум можно идентифицировать как начальный как исходное изображение, но с искажениями и с вышеупомянутыми артефактами.

Для сравнения:

original results

1 Ответ

1 голос
/ 09 мая 2020

Вы не обрабатываете векторное поле полностью, вы должны читать каждый вектор из поля. Фактически вы читаете только каждый 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 элемент для каждого пикселя, byut 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);
    }
}
...