将视频加载到三维场景中的方法

一、实现 将图片映射到三维场景

1、新写一个html展示一张图片实现获取它的x,y地址(需要替换成像素点坐标,还需要图片高度imageHeight、图片宽度imageWidth)

 <img src="your-image.jpg" alt="Your Image" usemap="#image-map">

下面是实现方法

document.getElementById('your-image').addEventListener('click', function(event) {
 var x = event.clientX - this.offsetLeft;
 var y = event.clientY - this.offsetTop;
});

获取图片像素点坐标之后,在test.html中实现以下步骤

2、引入opencv库

<script async src="https://docs.opencv.org/master/opencv.js" onload="onOpenCvReady();" type="text/javascript"></script>

3、添加像素点坐标

var pixelCoordinates = [
    { x: 100, y: 100 },
    { x: 200, y: 200 },
];

4、遍历像素点坐标将像素点坐标转换为纹理坐标

var textureCoordinates = pixelCoordinates.map(function(pixelCoord) {
    var textureX = pixelCoord.x / imageWidth; // imageWidth 是图片宽度
    var textureY = 1.0 - pixelCoord.y / imageHeight; // imageHeight 是图片高度
    return new Cesium.Cartesian2(textureX, textureY);
});

5、用插值计算进行映射

var worldCoordinates = textureCoordinates.map(function(textureCoord) {
    var position = new Cesium.Cartographic();
    var cartographic = Cesium.Cartographic.fromCartesian(your3DPoint); // 替换为三维场景中的点
    var longitude = cartographic.longitude + textureCoord.x * yourLongitudeRange;
    var latitude = cartographic.latitude + textureCoord.y * yourLatitudeRange;
    var height = cartographic.height;
    return new Cesium.Cartesian3.fromDegrees(longitude, latitude, height);
});

6、创建存放图片的几何体(忽略此步骤,放到10、11、12步骤执行)

var geometry = new Cesium.PolygonGeometry({
    polygonHierarchy: {
        positions: worldCoordinates
    }
});

7、将几何体存放到三维场景中(忽略此步骤,放到10、11、12步骤执行)

viewer.scene.primitives.add(new Cesium.Primitive({
    geometryInstances: new Cesium.GeometryInstance({
        geometry: geometry,
        attributes: {
            color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.RED)
        }
    })
}));

8、创建图片材质

var imageMaterial = new Cesium.ImageMaterialProperty({
    image: 'path_to_your_image.png' // 替换为本地图片路径
});

9、创建外观(Appearance),将图片材质应用到外观上

var appearance = new Cesium.MaterialAppearance({
    material: imageMaterial
});

10、创建几何体

var geometry = new Cesium.PolygonGeometry({
    polygonHierarchy: {
        positions: worldCoordinates
    }
});

11、创建包含几何体和外观的 Primitive

var primitive = new Cesium.Primitive({
    geometryInstances: new Cesium.GeometryInstance({
        geometry: geometry,
        attributes: {
            color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.RED)
        }
    }),
    appearance: appearance
});

12、将 Primitive 添加到场景中

viewer.scene.primitives.add(primitive);

二、实现 将视频转化为图片帧

以下两个方法选一种执行完毕即可

import org.bytedeco.javacpp.avutil;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.OpenCVFrameConverter;
import org.bytedeco.opencv.opencv_core.IplImage;

public class VideoToImages {
    public static void main(String[] args) {
        String inputVideoFile = "input.mp4"; // 替换视频文件路径
        String outputImageFolder = "output_images/"; // 替换图片帧输出文件夹

        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputVideoFile);
        OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
        long frameRate = (long) Math.round(1.0 / 0.5); // 0.5秒一帧,可更改

        try {
            grabber.start();
            Frame frame;
            int frameNumber = 1;
            while (true) {
                frame = grabber.grabImage();
                if (frame == null) {
                    break;
                }
                if (frameNumber % frameRate == 0) {
                    IplImage image = converter.convertToIplImage(frame);
                    saveImage(image, outputImageFolder, frameNumber / frameRate);
                }
                frameNumber++;
            }
            grabber.stop();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void saveImage(IplImage image, String outputFolder, int frameNumber) {
        try {
            String filename = String.format("%s/frame%04d.jpg", outputFolder, frameNumber);
            avutil.av_log_set_level(avutil.AV_LOG_QUIET); // 静默输出
            org.bytedeco.opencv.global.opencv_imgcodecs.cvSaveImage(filename, image);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
import cv2
import os

# 视频文件路径(更改)
video_file = 'input.mp4'

# 图像帧输出文件夹(更改)
output_folder = 'output_images'

# 每帧之间的时间间隔(以毫秒为单位,这里是0.5秒)
frame_interval = 500

# 创建输出文件夹(如果不存在)
if not os.path.exists(output_folder):
    os.makedirs(output_folder)

# 打开视频文件
cap = cv2.VideoCapture(video_file)

frame_count = 0

while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        break

    # 计算帧时间
    frame_time = frame_count * frame_interval

    # 每隔0.5秒保存一帧
    if frame_time % 500 == 0:
        # 构建输出文件名
        output_file = os.path.join(output_folder, f'frame_{frame_count:04d}.jpg')
        # 保存图像帧
        cv2.imwrite(output_file, frame)
    frame_count += 1

# 释放视频捕获对象
cap.release()

# 关闭所有窗口
cv2.destroyAllWindows()

三、设置时间不断替换视频帧图片

// 初始化图片地址列表(做个读取对应文件夹中的图片)
var imageUrls = ['path_to_image1.png', 'path_to_image2.png', 'path_to_image3.png'];
var currentIndex = 0; // 当前图片索引
// 创建图片材质
var imageMaterial = new Cesium.ImageMaterialProperty({
    image: imageUrls[currentIndex]
});
// 创建外观(Appearance),将图片材质应用到外观上
var appearance = new Cesium.MaterialAppearance({
    material: imageMaterial
});
// 创建几何体,这里使用一个简单的矩形
var geometry = new Cesium.RectangleGeometry({
    rectangle: Cesium.Rectangle.fromDegrees(-75.0, 28.0, -74.0, 29.0),
    vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
});
// 创建包含几何体和外观的 Primitive
var primitive = new Cesium.Primitive({
    geometryInstances: new Cesium.GeometryInstance({
        geometry: geometry,
        attributes: {
            color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.RED)
        }
    }),
    appearance: appearance
});
// 将 Primitive 添加到场景中
viewer.scene.primitives.add(primitive);
// 定时更改图片地址并重新加载图片材质
setInterval(function() {
    currentIndex = (currentIndex + 1) % imageUrls.length;
    imageMaterial.image = imageUrls[currentIndex];
}, 500); // 500 毫秒(0.5秒)为间隔时间
const fs = require('fs');
const path = require('path');
const folderPath = 'E:/01_data/videoframe/X1';  // 本地图片文件夹路径
let imageUrls = [];
let detailUrl = '';
// 读取文件夹中的文件
fs.readdir(folderPath, (err, files) => {
  if (err) {
    console.error('Error reading folder:', err);
    return;
  }
  // 遍历文件夹中的文件
  files.forEach((file) => {
    const filePath = path.join(folderPath, file);
    // 检查是否是文件
    if (fs.statSync(filePath).isFile()) {
      imageUrls.push(file);  // 存储文件名
      detailUrl = filePath;  // 存储完整的本地文件路径
    }
  });
});

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
</head>

<body>
    <div id="container">
        <img id="your-image" src="frame0.jpg" alt="Image" usemap="#image-map">
    </div>

    <script>
        document.getElementById('your-image').addEventListener('click', function (event) {
            var x = event.clientX - this.offsetLeft;
            var y = event.clientY - this.offsetTop;
            console.log('Clicked at (' + x + ', ' + y + ')');
        });
    </script>
</body>
</html>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值