Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate canvas returns black screen [Question] #352

Open
olsommer opened this issue Sep 25, 2022 · 1 comment
Open

Separate canvas returns black screen [Question] #352

olsommer opened this issue Sep 25, 2022 · 1 comment

Comments

@olsommer
Copy link

Hello community, @mozmorris ,
I got stuck and I really don't know how to solve it. Now I'm writing my question here because I am a little bit desperate. Sorry for that..

I am trying to use react-webcam as media input only and a separate canvas element as output. That's because I need to draw some things later on top.

But the only thing I see is a black screen.. although my console gives me some "positive" output, means that it logs readyState=4 and a video element).

I don't get it, it only renders a black screen.. Hope someone can give me a hint.

My question is a bit like #167

import { render } from "react-dom";
import Webcam from "react-webcam";

const VIDEO_CONSTRAINTS = {
  width: 640,
  height: 480,
  facingMode: "user",
  deviceId: "",
  frameRate: { max: 1, ideal: 1 },
};

const Stream = () => {
  const webcamRef = useRef() as React.MutableRefObject<Webcam>;
  const canvasRef = useRef() as React.MutableRefObject<HTMLCanvasElement>;
  const [mediaStreamReady, setMediaStreamReady] = useState(false);

  const draw = (ctx: CanvasRenderingContext2D, video: HTMLVideoElement) => {
    ctx.fillRect(0, 0, VIDEO_CONSTRAINTS.width, VIDEO_CONSTRAINTS.height);
    ctx.translate(VIDEO_CONSTRAINTS.width, 0);
    ctx.scale(-1, 1);
    ctx.clip();
    console.log(video);
    ctx.drawImage(
      video,
      0,
      0,
      VIDEO_CONSTRAINTS.width,
      VIDEO_CONSTRAINTS.height,
    );
  };

  const onUserMediaError = () => {
    console.log("ERROR in Camera!");
  };

  const onUserMedia = () => {
    console.log("onUserMedia: Camera loaded!");
    setMediaStreamReady(true);
  };

  useEffect(() => {
    const canvas = canvasRef.current;
    const ctx = canvas.getContext("2d");
    canvas.width = VIDEO_CONSTRAINTS.width;
    canvas.height = VIDEO_CONSTRAINTS.height;
    if (!ctx) return;
    if (!mediaStreamReady) return;
    const render = () => {
      const video = webcamRef.current.video;
      if (!video) return;
      console.log("render..");
      draw(ctx, video);
      requestAnimationFrame(render);
    };
    render();
  });

  return (
    <>
      <Webcam
        audio={false}
        ref={webcamRef}
        videoConstraints={VIDEO_CONSTRAINTS}
        onUserMediaError={onUserMediaError}
        onUserMedia={onUserMedia}
        style={{ opacity: 1 }}
        width={"200px"} // only to get safe that I receive a stream
        height={"100px"} // only to get safe that I receive a stream
      />
      <canvas ref={canvasRef} />
    </>
  );
};

export default Stream;```
@olsommer olsommer changed the title Separate canvas returns black screen Separate canvas returns black screen [Question] Sep 25, 2022
@rvdende
Copy link

rvdende commented Apr 13, 2024

For anyone coming across this. You might be loading opencv differently, but it should be very similar no matter how you load it.

image

import { Button } from "~/components/Button";
import Webcam from "react-webcam";
import { cv, setupOpenCv } from "~/lib/opencv";
import { useRef, useState, useCallback } from "react";

let interval: NodeJS.Timeout;
export default function WebcamPage() {
  const webcamRef = useRef<Webcam>(null);

  const [capturing, setCapturing] = useState(false);
  const [cvready, setCvReady] = useState(false);

  const handleCanvas = useCallback(
    (canvas: HTMLElement) => {
      // console.log(canvas);

      if (cvready) {
        const src = cv.imread(canvas);
        const dst = new cv.Mat();
        // You can try more different parameters
        cv.threshold(src, dst, 177, 200, cv.THRESH_BINARY);
        cv.imshow("canvasOutput", dst);
        src.delete();
        dst.delete();
      }
    },
    [cvready],
  );

  const capture = useCallback(() => {
    interval = setInterval(() => {
      const canv = webcamRef?.current?.getCanvas();
      if (!canv) return;
      handleCanvas(canv);
    }, 50);
    setCapturing(true);
  }, [webcamRef, setCapturing, handleCanvas]);

  const stop = useCallback(() => {
    clearInterval(interval);
    setCapturing(false);
  }, [setCapturing]);

  return (
    <>
      <Button
        onClick={async () => {
          await setupOpenCv();
          setCvReady(true);
        }}
      >
        init
      </Button>
      {cvready ? "cv ready" : "cv not ready"}
      <Webcam audio={false} ref={webcamRef} />
      {capturing ? (
        <button onClick={stop}>Stop Capture</button>
      ) : (
        <button onClick={capture}>Start Capture</button>
      )}
      <canvas id="canvasOutput" />
    </>
  );
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants