人工智能识别组件

219 天前
 ScriptEcho

本文由ScriptEcho平台提供技术支持

项目地址:传送门

基于 Transformers.js 的图片景深 3D 图生成

应用场景

本代码可以将一张普通的图片转换为具有景深效果的 3D 图,可用于创建逼真的 3D 场景或增强图片的视觉吸引力。

代码基本功能

该代码使用 Transformers.js 中的深度估计模型,分析图片中物体的深度信息,并生成一张位移贴图。然后将位移贴图应用于 3D 模型,使其产生景深效果。用户可以通过滑动条控制景深程度,呈现出更具立体感和真实感的图像。

功能实现步骤及关键代码分析

1. 导入依赖项

import { ref, onMounted } from 'vue';
import * as THREE from 'three';
import { OrbitControls } from '/sfc/threejs/jsm/controls/OrbitControls.js';
import { pipeline, env, RawImage } from '@xenova/transformers';

2. 初始化状态和引用

onMounted(async () => {
console.log(`Transformers.js version: ${env.version}`);

// Since we will download the model from the Hugging Face Hub, we can skip the local model check
env.allowLocalModels = false;

// Proxy the WASM backend to prevent the UI from freezing
env.backends.onnx.wasm.proxy = true;

// Constants
const EXAMPLE_URL = 'https://huggingface.co/datasets/Xenova/transformers.js-docs/resolve/main/bread_small.png';
const DEFAULT_SCALE = 0.75;

// Reference the elements that we will need
const status = document.getElementById('status');
const fileUpload = document.getElementById('upload');
const imageContainer = document.getElementById('container');
const example = document.getElementById('example');
console.log(`status: `, status)

// Create a new depth-estimation pipeline
status.textContent = '正在加载模型...';
const depth_estimator = await pipeline('depth-estimation', 'Xenova/depth-anything-small-hf');
status.textContent = '已完成';

3. 设置事件监听器

example.addEventListener('click', (e) => {
e.preventDefault();
predict(EXAMPLE_URL);
});

fileUpload.addEventListener('change', function (e) {
const file = e.target.files[0];
if (!file) {
return;
}

const reader = new FileReader();

// Set up a callback when the file is loaded
reader.onload = e2 => predict(e2.target.result);

reader.readAsDataURL(file);
});

4. 预测深度图

async function predict(url) {
imageContainer.innerHTML = '';
const image = await RawImage.fromURL(url);

// Set up scene and slider controls
const { canvas, setDisplacementMap } = setupScene(url, image.width, image.height);

imageContainer.append(canvas);

status.textContent = '正在分析...';
const { depth } = await depth_estimator(image);

setDisplacementMap(depth.toCanvas());
status.textContent = '';

// Add slider control
const slider = document.createElement('input');
slider.type = 'range';
slider.min = 0;
slider.max = 1;
slider.step = 0.01;
slider.addEventListener('input', (e) => {
onSliderChange(parseFloat(e.target.value));
});
slider.defaultValue = DEFAULT_SCALE;
imageContainer.append(slider);
}

5. 设置场景

function setupScene(url, w, h) {

// Create new scene
const canvas = document.createElement('canvas');
const width = canvas.width = imageContainer.offsetWidth;
const height = canvas.height = imageContainer.offsetHeight;

const scene = new THREE.Scene();

// Create camera and add it to the scene
const camera = new THREE.PerspectiveCamera(30, width / height, 0.01, 10);
camera.position.z = 2;
scene.add(camera);

const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
renderer.setSize(width, height);
renderer.setPixelRatio(window.devicePixelRatio);

// Add ambient light
const light = new THREE.AmbientLight(0xffffff, 2);
scene.add(light);

// Load depth texture
const image = new THREE.TextureLoader().load(url);
image.colorSpace = THREE.SRGBColorSpace;
const material = new THREE.MeshStandardMaterial({
map: image,
side: THREE.DoubleSide,
});
material.displacementScale = DEFAULT_SCALE;

const setDisplacementMap = (canvas) => {
material.displacementMap = new THREE.CanvasTexture(canvas);
material.needsUpdate = true;
}

const setDisplacementScale = (scale) => {
material.displacementScale = scale;
material.needsUpdate = true;
}
onSliderChange = setDisplacementScale;

// Create plane and rescale it so that max(w, h) = 1
const [pw, ph] = w > h ? [1, h / w] : [w / h, 1];
const geometry = new THREE.PlaneGeometry(pw, ph, w, h);
const plane = new THREE.Mesh(geometry, material);
scene.add(plane);

// Add orbit controls
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;

renderer.setAnimationLoop(() => {
renderer.render(scene, camera);
controls.update();
});

window.addEventListener('resize', () => {
const width = imageContainer.offsetWidth;
const height = imageContainer.offsetHeight;

camera.aspect = width / height;
camera.updateProjectionMatrix();

renderer.setSize(width, height);
}, false);

return {
canvas: renderer.domElement,
setDisplacementMap,
};
}

总结与展望

这段代码成功实现了图片景深 3D 图的生成功能,展示了 Transformers.js 和 Three.js 的强大功能。

开发经验与收获:

未来拓展与优化:

更多组件:

获取更多 Echos

本文由ScriptEcho平台提供技术支持

项目地址:传送门

扫码加入 AI 生成前端微信讨论群:

573 次点击
所在节点    前端开发
0 条回复

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1043054

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX