Kawd
Kawd

Reputation: 4440

p5.js | Quality of image captured from camera feed, lower than actual camera feed?

With the code below, the quality of the video coming from my Mac's camera and shown inside <video> is great.

However the quality of the frame I capture and show in p5's canvas is pretty low, dark and grainy. Why is that and can I fix it ?

function setup() {
  let canvas = createCanvas(canvasSize, canvasSize)
  canvas.elt.width = canvasSize
  canvas.elt.height = canvasSize
  video = createCapture(VIDEO)
}

let PAUSE = false

async function draw() {

  if (video && video.loadedmetadata) {

    if (!PAUSE) {
      // the quality of this image is much lower than what is shown inside p5's <video>
      image(video.get(), 0, 0, canvasSize, canvasSize, x, y, canvasSize, canvasSize)

      PAUSE = true

    }

  }

}

Upvotes: 1

Views: 593

Answers (2)

Kawd
Kawd

Reputation: 4440

I found what the problem was.

It was not due to me setting the canvas.elt.width and canvas.elt.height, even though setting them is indeed redundant.

It's because in the code shown in the OP I was capturing the very first frame and this is too soon so the very first frame is still dark and blurry. Apparently the first few frames coming from the camera are like that.

If I give my code a delay of e.g. 5 seconds the frame it captures is then the exact same quality as the one coming from the video feed.

let video
let canvasWidth = 400

// set this to 10 on https://editor.p5js.org/ and you'll see the problem
const DELAY = 5000

function setup() {
  let canvas = createCanvas(canvasWidth, canvasWidth)
  canvas.elt.width = canvasWidth // redundant
  canvas.elt.height = canvasWidth // redundant
  video = createCapture(VIDEO)
}

let PAUSE = false
let start = Date.now()

async function draw() {
  let delay = Date.now() - start

  if (video && video.loadedmetadata) {

    if (delay > DELAY && !PAUSE) {
      PAUSE = true
      
      let x = Math.round((video.width / 2) - (canvasWidth / 2))
      let y = Math.round((video.height / 2) - (canvasWidth / 2))

      // the quality of this image is now perfect
      image(video.get(), 0, 0, canvasWidth, canvasWidth, x, y, canvasWidth, canvasWidth)
    }

  }

}

Upvotes: 1

Paul Wheeler
Paul Wheeler

Reputation: 20180

You should not be setting width/height this way. That will mess up the sizing on high DPI displays and cause your image to appear stretched and blurry.

const canvasSize = 500;

function setup() {
  let canvas = createCanvas(canvasSize, canvasSize)
  // Don't do this, it will mess up the sizing on high DPI displays:
  // canvas.elt.width = canvasSize
  // canvas.elt.height = canvasSize
  video = createCapture(VIDEO)
}

let PAUSE = false;

function draw() {
  if (video && video.loadedmetadata) {
    if (!PAUSE) {
      // the quality of this image is much lower than what is shown inside p5's <video>
      image(video.get(), 0, 0, canvasSize, canvasSize, 0, 0, canvasSize, canvasSize)
    }
  }
}

function keyPressed() {
  if (key === 'p') {
    PAUSE = !PAUSE;
  }
}

With this code I paused the video that was being rendered to p5.js and then took a screenshot. The version of the video displayed on the p5.js canvas wash indistinguishable from the live video.

Upvotes: 0

Related Questions