Naraina Dewasi
Naraina Dewasi

Reputation: 11

Camera guide within camera frame for click panoramic image for 360 view

I want to create a camera guide for capturing panoramic images for a 360-degree view. When a user clicks a picture, a dot should move to the next position, indicating where the user should click the next picture in sequence. This process should continue seamlessly in any direction the user rotates their mobile device. The guide should provide dots in all directions to help the user capture the images needed for a perfect 360-degree panorama.

I attempted to achieve this using the deviceorientation event. I set an initial alpha angle (rotation on the z-axis), and when the user rotates their mobile device and exceeds the predefined angle, a picture is automatically taken.

The issue I encountered is that the angle of rotation sometimes changes rapidly and other times it does not, leading to inconsistent picture capturing.

here is the code

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>360 Video Capture</title>
    <style>
      body {
        margin: 0;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        height: 100vh;
        background-color: #000;
      }
      #videoElement {
        /* display: none; */
        width: 70%; /* Set a fixed width */
        height: 50%; /* Set a fixed height */
      }
      #startButton {
        margin-bottom: 10px;
      }
      #canvas {
        display: none;
      }
      #overlay {
        position: absolute;
        width: 70%;
        height: 40%;
        bottom: 75px;
        border: 2px solid red;
      }
      #dot {
        position: absolute;
        width: 10px;
        height: 10px;
        background-color: red;
        border-radius: 50%;
        transform: translate(-50%, -50%);
      }
    </style>
  </head>
  <body>
    <button id="startButton">Start Capture</button>
    <p id="initial" style="color: white"></p>
    <p id="current" style="color: white"></p>
    <p id="difference" style="color: white"></p>
    <p id="degrees" style="color: white"></p>
    <p id="right" style="color: white"></p>
    <p id="count" style="color: white"></p>
    <p id="left" style="color: white"></p>

    <canvas id="canvas"></canvas>
    <video id="videoElement" autoplay playsinline></video>
    <div id="overlay">
      <div id="dot"></div>
    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <script>
      new Promise((resolve, reject) => {
        document.addEventListener("DOMContentLoaded", resolve);
      }).then(() => {
        const videoElement = document.getElementById("videoElement");
        const startButton = document.getElementById("startButton");
        const canvas = document.getElementById("canvas");
        const overlayDiv = document.getElementById("overlay");
        const dotDiv = document.getElementById("dot");
        const radius = 50; // Radius in degrees for initial calculation
        const radiusInPixels = 100; // Example radius in pixels for movement
        let initialOrientation = null; // Store initial orientation for comparison
        let captureEnabled = true; // Flag to control image capture
        let capture = 0;
        let currentLength = 0;
        let moveX = overlayDiv.clientWidth / 2;
        let moveY = overlayDiv.clientHeight / 2;

        dotDiv.style.left = `${moveX}px`;
        dotDiv.style.top = `${moveY}px`;
        console.log(
          "dotDiv background ",
          Number(dotDiv.style.left.replace("px", ""))
        );
        if (
          Number(dotDiv.style.left.replace("px", "")) >= 120 &&
          Number(dotDiv.style.left.replace("px", "")) <= 135
        ) {
          dotDiv.style.background = "green";
        } else {
          dotDiv.style.background = "red";
        }
        console.log("dotDiv background ", dotDiv.style.background);

        // alert(`orintation ${DeviceOrientationEvent.requestPermission}`)

        let stream; // Store the stream object

        // Function to request permission for device orientation

        async function startCapture() {
          try {
            let constraints = {
              video: {
                facingMode: "environment", // Use rear camera if available
              },
            };

            stream = await navigator.mediaDevices.getUserMedia(constraints);
            videoElement.srcObject = stream;
            await new Promise(
              (resolve) => (videoElement.onloadedmetadata = resolve)
            );

            // Set canvas size to match the video element
            canvas.width = videoElement.videoWidth;
            canvas.height = videoElement.videoHeight;

            // Capture variables
            let lastCaptureAngle = 0;
            const captureInterval = 45; // degrees to capture next image

            // Function to capture the current view
            function captureImage() {
              // renderer.render(scene, camera);
              canvas.width = videoElement.videoWidth;
              canvas.height = videoElement.videoHeight;
              canvas
                .getContext("2d")
                .drawImage(videoElement, 0, 0, canvas.width, canvas.height);
              const imageData = canvas.toDataURL("image/png");
              saveImage(imageData);
            }

            // Function to save the captured image (placeholder for actual saving mechanism)
            function saveImage(dataUrl) {
              const link = document.createElement("a");
              link.href = dataUrl;
              link.download = `capture_${Date.now()}.png`;
              link.click();
            }

            let count = 0;
            // alert("value ", count)

            // Function to handle device orientation changes
            function handleOrientation(event) {
              // alert(event.alpha)
              console.log("hello", initialOrientation);
              // document.getElementById("count").innerText = count++;
              captureEnabled = true;

              // Check if initialOrientation is not set, save initial orientation
              if (initialOrientation == null) {
                initialOrientation = event.alpha;
                console.log("hello", initialOrientation);
              } else {
                // Check if rotated 90 degrees left or right from initial orientation
                const currentOrientation = event.alpha;
                document.getElementById("degrees").innerText = Math.round(
                  event.alpha
                );
                const rotatedLeft =
                  currentOrientation - initialOrientation <= -50;
                const rotatedRight =
                  currentOrientation - initialOrientation >= 50;
                document.getElementById(
                  "left"
                ).innerText = `left ${rotatedLeft}`;
                document.getElementById(
                  "right"
                ).innerText = `right ${rotatedRight}`;
                document.getElementById(
                  "initial"
                ).innerText = `initial ${Math.round(initialOrientation)}`;
                document.getElementById(
                  "current"
                ).innerText = `current ${Math.round(currentOrientation)}`;
                document.getElementById(
                  "difference"
                ).innerText = `difference ${Math.round(
                  currentOrientation - initialOrientation
                )}`;

                if (currentLength != 0) {
                  decreaseDotPosition(
                    currentOrientation - initialOrientation,
                    currentLength
                  );
                }

                if ((rotatedLeft || rotatedRight) && captureEnabled) {
                  captureEnabled = false; // Disable further captures
                  // if(capture <6){
                  captureImage();
                  // capture++
                  // alert(`captured ${currentOrientation} - ${initialOrientation} = ${currentOrientation- initialOrientation}`)
                  const xAxis = updateDotPosition(
                    initialOrientation,
                    currentOrientation
                  );
                  console.log("xAxis ", xAxis);
                  // alert(`xaxis ${currentOrientation-initialOrientation}`)

                  // }else{
                  //   alert('the end')
                  // }

                  initialOrientation = currentOrientation;
                  // alert("image captured on ");
                }
              }
            }

            function updateDotPosition(initialOrientation, currentOrientation) {
              console.log("updatePosiiton");
              const angleDifferenceDegrees =
                currentOrientation - initialOrientation;
              const angleDifferenceRadians =
                angleDifferenceDegrees < 0 ? -50 : 50 * (Math.PI / 180); // Convert degrees to radians
              const movement = radiusInPixels * angleDifferenceRadians;
              // alert(`movemnet ${movement}`)

              // Calculate new position
              const centerX = overlayDiv.clientWidth / 2;
              const newX = centerX - movement;

              const centerY = overlayDiv.clientHeight / 2;

              // Update dot position
              console.log("old left ", dotDiv.style.left);
              dotDiv.style.left = `${newX}px`;
              dotDiv.style.top = `${centerY}px`;
              console.log("new left ", newX);
              currentLength = newX;
              console.log('background ', dotDiv.style.background)
              console.log('background ', Number(dotDiv.style.left.replace("px", "")))
              if (
                Number(dotDiv.style.left.replace("px", "")) >= 120 &&
                Number(dotDiv.style.left.replace("px", "")) <= 135
              ) {
                dotDiv.style.background = "green";
              } else {
                dotDiv.style.background = "red";
              }
              console.log('background ', dotDiv.style.background)
            }
            function decreaseDotPosition(difference, xAxis) {
              console.log("decreaseDotPosition ", xAxis);
              // const angleDifferenceDegrees = currentOrientation - initialOrientation;
              const angleDifferenceRadians = difference * (Math.PI / 180); // Convert degrees to radians
              const movement = radiusInPixels * angleDifferenceRadians;

              // Calculate new position
              const newX = xAxis + movement;
              // const centerY = overlayDiv.clientHeight / 2;

              // Update dot position
              dotDiv.style.left = `${newX}px`;
              console.log("new length ", newX);
              if (
                Number(dotDiv.style.left.replace("px", "")) >= 120 &&
                Number(dotDiv.style.left.replace("px", "")) <= 135
              ) {
                dotDiv.style.background = "green";
              } else {
                dotDiv.style.background = "red";
              }
              // dotDiv.style.top = `${centerY}px`;
            }

            // Start listening to device orientation events
            window.addEventListener("deviceorientation", handleOrientation);
            // requestOrientationPermission()

            function animate() {
              requestAnimationFrame(animate);

              // renderer.render(scene, camera);
            }

            animate();
          } catch (err) {
            console.error(
              "Error accessing the camera or creating WebGL context:",
              err
            );
          }
        }

        startButton.addEventListener("click", () => {
          startCapture();
          startButton.disabled = true;
        });

        window.addEventListener("beforeunload", () => {
          if (stream) {
            stream.getTracks().forEach((track) => track.stop());
          }
        });
      });
    </script>
  </body>
</html>

Upvotes: 0

Views: 88

Answers (0)

Related Questions