创建react项目
安装脚手架
npm i create-react-app -g
在合适的目录创建react项目my-app
npx create-react-app my-app
启动项目
cd my-app
// 进入my-app目录
code .
// 使用vscode打开,若未配置code命令,可以手动打开
npm i
// 安装依赖
npm run start
// 启动项目
初始化项目 src目录下保留index.js和app.js,其余文件全部删除即可
修改app.js文件名为app.jsx,内容修改如下:
import React from "react";
function App() {
return (
<div>
test
</div>
);
}
export default App;
删减index.js文件如下:
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
此时项目页面为:
此时先使用transformers.js中的remove-background-client中的代码测试一下:
1.安装@xenova/transformers:
npm i @xenova/transformers
2.在src下新建components目录,components目录下新建transformers目录,用于存放我们在官网复制的案例
3.在transformers目录下新建index.jsx代码
import React, { useRef } from "react";
import { useAsyncEffect } from "ahooks";
import { AutoModel, AutoProcessor, env, RawImage } from '@xenova/transformers';
import './index.css'
// 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://images.pexels.com/photos/5965592/pexels-photo-5965592.jpeg?auto=compress&cs=tinysrgb&w=1024';
const Transform = () => {
const status = useRef();
const fileUpload = useRef();
const imageContainer = useRef();
const example = useRef();
useAsyncEffect(async () => {
status.current.textContent = 'Loading model...';
const model = await AutoModel.from_pretrained('briaai/RMBG-1.4', {
// Do not require config.json to be present in the repository
config: { model_type: 'custom' },
});
const processor = await AutoProcessor.from_pretrained('briaai/RMBG-1.4', {
// Do not require config.json to be present in the repository
config: {
do_normalize: true,
do_pad: false,
do_rescale: true,
do_resize: true,
image_mean: [0.5, 0.5, 0.5],
feature_extractor_type: "ImageFeatureExtractor",
image_std: [1, 1, 1],
resample: 2,
rescale_factor: 0.00392156862745098,
size: { width: 1024, height: 1024 },
}
});
status.current.textContent = 'Ready';
example.current.addEventListener('click', (e) => {
e.preventDefault();
predict(EXAMPLE_URL);
});
fileUpload.current.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);
});
// Predict foreground of the given image
async function predict(url) {
// Read image
const image = await RawImage.fromURL(url);
// Update UI
imageContainer.current.innerHTML = '';
imageContainer.current.style.backgroundImage = `url(${url})`;
// Set container width and height depending on the image aspect ratio
const ar = image.width / image.height;
const [cw, ch] = (ar > 720 / 480) ? [720, 720 / ar] : [480 * ar, 480];
imageContainer.current.style.width = `${cw}px`;
imageContainer.current.style.height = `${ch}px`;
status.current.textContent = 'Analysing...';
// Preprocess image
const { pixel_values } = await processor(image);
// Predict alpha matte
const { output } = await model({ input: pixel_values });
// Resize mask back to original size
const mask = await RawImage.fromTensor(output[0].mul(255).to('uint8')).resize(image.width, image.height);
// Create new canvas
const canvas = document.createElement('canvas');
canvas.width = image.width;
canvas.height = image.height;
const ctx = canvas.getContext('2d');
// Draw original image output to canvas
ctx.drawImage(image.toCanvas(), 0, 0);
// Update alpha channel
const pixelData = ctx.getImageData(0, 0, image.width, image.height);
for (let i = 0; i < mask.data.length; ++i) {
pixelData.data[4 * i + 3] = mask.data[i];
}
ctx.putImageData(pixelData, 0, 0);
// Update UI
imageContainer.current.append(canvas);
imageContainer.current.style.removeProperty('background-image');
imageContainer.current.style.background = `url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAGUExURb+/v5nD/3QAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAUSURBVBjTYwABQSCglEENMxgYGAAynwRB8BEAgQAAAABJRU5ErkJggg==")`;
status.current.textContent = 'Done!';
}
}, [])
return <div className="transform">
<div id="container" ref={imageContainer}>
<label id="upload-button" htmlFor="upload">
Click to upload image
<label id="example" ref={example}>(or try example)</label>
</label>
</div>
<label id="status" ref={status}></label>
<input id="upload" ref={fileUpload} type="file" accept="image/*" />
</div>
}
export default Transform;
4.在transformers目录下新建index.css代码
* {
box-sizing: border-box;
padding: 0;
margin: 0;
font-family: sans-serif;
}
html,
body {
height: 100%;
}
body {
padding: 16px 32px;
}
body,
#container,
#upload-button {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
h1,
h4 {
text-align: center;
}
h4 {
margin-top: 0.5rem;
}
#container {
position: relative;
width: 720px;
height: 480px;
max-width: 100%;
max-height: 100%;
border: 2px dashed #D1D5DB;
border-radius: 0.75rem;
overflow: hidden;
margin-top: 1rem;
background-size: 100% 100%;
background-position: center;
background-repeat: no-repeat;
}
#upload-button {
gap: 0.4rem;
font-size: 18px;
cursor: pointer;
}
#upload {
display: none;
}
svg {
pointer-events: none;
}
#example {
font-size: 14px;
text-decoration: underline;
cursor: pointer;
}
#example:hover {
color: #2563EB;
}
canvas {
position: absolute;
width: 100%;
height: 100%;
}
#status {
min-height: 16px;
margin: 8px 0;
}
5.修改App.jsx
import React from "react";
import Transform from "./components/transform";
function App() {
return (
<div>
<Transform></Transform>
</div>
);
}
export default App;
此时可以自行测试是否可用。