Введение

В конечном итоге я пытаюсь визуализировать взаимодействие человека с самим пространством и объектами в космосе. В качестве первого прототипа я буду использовать пиксели выходного видеосигнала для захвата и сохранения движения в пространстве.
Мой процесс задокументирован в три этапа:

  1. Отслеживание движения
    Сравнение предыдущего кадра с входящим по значениям RGB и определение перемещенных* пикселей (пикселей с большой разницей по сравнению с предыдущим кадром) выше определенный порог.
  2. Подсчет и сохранение перемещенных пикселей
    После определения того, что пиксель переместился, он обновляется в поле (с использованием массива), где каждый пиксель содержит значение, равное его количеству переехал.
  3. Сопоставление перемещенныхпикселей с максимальным значением или временем
    Наконец важно сопоставить значение цвета от нуля до самого высокого значения RGB, 255, чтобы иметь точное среднее значение того, где было наибольшее движение.

*Очевидно, что этот прототип не передает все движения. Например, когда движение в реальной жизни имеет тот же свет или цвет, что и камера, оно не воспринимается как «движение». Сопровождается обилием ошибок измерения.

Трекер движения

На основе скетча обнаружения движения от bestesaylar по адресу:



«Веб-редактор p5.js
Веб-редактор для p5.js, библиотеки JavaScript с целью сделать программирование доступным для художников, дизайнеров…editor.p5js .или"



Сначала давайте настроим холст HTML, импортировав библиотеку p5js и связав наш sketch.js с index.html.

index.html:

<!DOCTYPE html>
<html>
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/addons/p5.dom.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/addons/p5.sound.min.js"></script>
    <link rel="stylesheet" type="text/css" href="style.css" />
    <meta charset="utf-8" />
  </head>
  <body>
    <script src="src/sketch.js"></script>
  </body>
</html>

sketch.js:

var video;
var scaler = 10;
var preFrame;

function setup() {
  createCanvas(640, 480);
  pixelDensity(1);
  video = createCapture(VIDEO);
  video.size(width / scaler, height / scaler);
  video.hide();
  preFrame = createImage(video.width, video.height);
  frameRate(10);
}

function draw() {
  video.loadPixels();
  preFrame.loadPixels();

  fill(255, 50);
  rect(0, 0, innerWidth, innerWidth);

  if (frameCount >= 10) {
    for (let y = 0; y < video.height; y++) {
      for (let x = 0; x < video.width; x++) {
        let index = (x + y * video.width) * 4;
        let pr = preFrame.pixels[index + 0];
        let pg = preFrame.pixels[index + 1];
        let pb = preFrame.pixels[index + 2];
        let pbright = (pr + pg + pb) / 3;

        let r = video.pixels[index + 0];
        let g = video.pixels[index + 1];
        let b = video.pixels[index + 2];
        let bright = (r + g + b) / 3;

        var diff = distSq(r, g, b, pr, pg, pb);
        if (diff * diff < 10000) {
          // fill(r, g, b);
        } else {
          fill(255, 0, 0, 50);
          drawHeatmap(x, y);
        }
        noStroke();
      }
    }
  }

  preFrame.copy(
    video,
    0,
    0,
    video.width,
    video.height,
    0,
    0,
    video.width,
    video.height
  );
}

const distSq = (x1, y1, z1, x2, y2, z2) => {
  let d = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) + (z2 - z1) * (z2 - z1);
  return d;
};

const drawHeatmap = (x, y) => {
  rect(x * scaler, y * scaler, scaler, scaler);
};

Результат с использованием плагина Live Server в коде Visual Studio (открытие HTML-файла в браузере также сделает эту работу):

Скриншоты:

Подсчет и сохранение перемещенных пикселей

var video;
var scaler = 10;
var preFrame;
let motionCaptureArray = [];

function setup() {
  createCanvas(640, 480);
  pixelDensity(1);
  video = createCapture(VIDEO);
  video.size(width / scaler, height / scaler);
  video.hide();
  preFrame = createImage(video.width, video.height);
  frameRate(10);
}

function draw() {
  video.loadPixels();
  preFrame.loadPixels();

  if (motionCaptureArray.length === 0) {
    motionCaptureArray = preFrame.pixels;
  }

  // fill(255, 50);
  // rect(0, 0, innerWidth, innerWidth);

  if (frameCount >= 10) {
    for (let y = 0; y < video.height; y++) {
      for (let x = 0; x < video.width; x++) {
        let index = (x + y * video.width) * 4;
        let pr = preFrame.pixels[index + 0];
        let pg = preFrame.pixels[index + 1];
        let pb = preFrame.pixels[index + 2];
        let pbright = (pr + pg + pb) / 3;

        let r = video.pixels[index + 0];
        let g = video.pixels[index + 1];
        let b = video.pixels[index + 2];
        let bright = (r + g + b) / 3;

        var diff = distSq(r, g, b, pr, pg, pb);
        if (diff * diff < 10000) {
          // fill(r, g, b);
        } else {
          drawHeatmap(x, y);
        }
        noStroke();
      }
    }
  }

  preFrame.copy(
    video,
    0,
    0,
    video.width,
    video.height,
    0,
    0,
    video.width,
    video.height
  );
}

const distSq = (x1, y1, z1, x2, y2, z2) => {
  let d = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) + (z2 - z1) * (z2 - z1);
  return d;
};

const drawHeatmap = (x, y) => {
  let index = (x + y * video.width) * 4;
  motionCaptureArray[index] = motionCaptureArray[index] + 1;
  // console.log(motionCaptureArray[index]);
  //textSize(10);
  text(motionCaptureArray[index], x * scaler, y * scaler);
  fill(
    motionCaptureArray[index],
    motionCaptureArray[index + 1],
    motionCaptureArray[index + 2]
  );
  rect(x * scaler, y * scaler, scaler, scaler);
};

Скриншоты:

Сопоставление перемещенныхпикселей с максимальным значением или временем

var video;
const devices = [];
var scaler = 7;
var preFrame;
let motionCaptureArray = [];
let mapNumber = 1;

function setup() {

  video = createCapture(VIDEO);
  createCanvas(840, 680);
  pixelDensity(1);
  video.size(width / scaler, height / scaler);
  video.hide();
  preFrame = createImage(video.width, video.height);
  frameRate(10);
}

function draw() {
  image(video, 840, 0, width, height);
  video.loadPixels();
  preFrame.loadPixels();

  if (motionCaptureArray.length === 0) {
    motionCaptureArray = Array.prototype.slice.call(preFrame.pixels);
  }
  //mapNumber = frameCount;
  if (frameCount % 10 == 0) {
    mapNumber = Math.max(...motionCaptureArray);
  }

  if (frameCount >= 10) {
    for (let y = 0; y < video.height; y++) {
      for (let x = 0; x < video.width; x++) {
        let index = (x + y * video.width) * 4;
        let pr = preFrame.pixels[index + 0];
        let pg = preFrame.pixels[index + 1];
        let pb = preFrame.pixels[index + 2];

        let r = video.pixels[index + 0];
        let g = video.pixels[index + 1];
        let b = video.pixels[index + 2];

        var diff = distSq(r, g, b, pr, pg, pb);
        if (diff * diff < 50000) {
          //fill(r, g, b);
        } else {
          motionCaptureArray[index] = motionCaptureArray[index] + 1;
        }
        noStroke();
        colorMode(HSB);

        fill(
          map(motionCaptureArray[index], 0, mapNumber, 0, 360),
          map(motionCaptureArray[index], 0, mapNumber, 0, 100),
          map(motionCaptureArray[index], 0, mapNumber, 0, 100)
        );
        // text(motionCaptureArray[index], x * scaler, y * scaler);
        rect(x * scaler, y * scaler, scaler, scaler);

        colorMode(RGB);
        fill((r + g + b) / 3, 90);
        rect(x * scaler, y * scaler, scaler, scaler);
      }
    }
  }

  preFrame.copy(
    video,
    0,
    0,
    video.width,
    video.height,
    0,
    0,
    video.width,
    video.height
  );
}

const distSq = (x1, y1, z1, x2, y2, z2) => {
  let d = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) + (z2 - z1) * (z2 - z1);
  return d;
};

Скриншоты:

Заключение и следующие шаги

Это работает с постоянным источником света и неподвижной камерой.
Следующий шаг — использовать настоящий тепловой датчик или сделать то же самое с датчиками расстояния.

Следующим проектом также может быть генератор тепловых карт из импортированного видеофайла в качестве отдельного сервиса.

Репозиторий на гитхабе:

https://github.com/julesdocx/motion_heatmap