segment anything backend
No files matched your search
@@ -18,7 +18,7 @@ wheels/
|
|||||||
*.npy
|
*.npy
|
||||||
*.ts
|
*.ts
|
||||||
model_ts*.txt
|
model_ts*.txt
|
||||||
|
*.pth
|
||||||
# onnx models
|
# onnx models
|
||||||
*.onnx
|
*.onnx
|
||||||
|
|
||||||
@@ -40,3 +40,4 @@ _darcs
|
|||||||
**/node_modules
|
**/node_modules
|
||||||
yarn.lock
|
yarn.lock
|
||||||
package-lock.json
|
package-lock.json
|
||||||
|
/notebooks
|
||||||
|
Before Width: | Height: | Size: 3.5 MiB |
|
Before Width: | Height: | Size: 130 KiB |
|
Before Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 568 KiB |
|
Before Width: | Height: | Size: 854 KiB |
|
Before Width: | Height: | Size: 1.2 MiB |
@@ -1,126 +0,0 @@
|
|||||||
## Segment Anything Simple Web demo
|
|
||||||
|
|
||||||
This **front-end only** React based web demo shows how to load a fixed image and corresponding `.npy` file of the SAM image embedding, and run the SAM ONNX model in the browser using Web Assembly with mulithreading enabled by `SharedArrayBuffer`, Web Worker, and SIMD128.
|
|
||||||
|
|
||||||
<img src="https://github.com/facebookresearch/segment-anything/raw/main/assets/minidemo.gif" width="500"/>
|
|
||||||
|
|
||||||
## Run the app
|
|
||||||
|
|
||||||
Install Yarn
|
|
||||||
|
|
||||||
```
|
|
||||||
npm install --g yarn
|
|
||||||
```
|
|
||||||
|
|
||||||
Build and run:
|
|
||||||
|
|
||||||
```
|
|
||||||
yarn && yarn start
|
|
||||||
```
|
|
||||||
|
|
||||||
Navigate to [`http://localhost:8081/`](http://localhost:8081/)
|
|
||||||
|
|
||||||
Move your cursor around to see the mask prediction update in real time.
|
|
||||||
|
|
||||||
## Export the image embedding
|
|
||||||
|
|
||||||
In the [ONNX Model Example notebook](https://github.com/facebookresearch/segment-anything/blob/main/notebooks/onnx_model_example.ipynb) upload the image of your choice and generate and save corresponding embedding.
|
|
||||||
|
|
||||||
Initialize the predictor:
|
|
||||||
|
|
||||||
```python
|
|
||||||
checkpoint = "sam_vit_h_4b8939.pth"
|
|
||||||
model_type = "vit_h"
|
|
||||||
sam = sam_model_registry[model_type](checkpoint=checkpoint)
|
|
||||||
sam.to(device='cuda')
|
|
||||||
predictor = SamPredictor(sam)
|
|
||||||
```
|
|
||||||
|
|
||||||
Set the new image and export the embedding:
|
|
||||||
|
|
||||||
```
|
|
||||||
image = cv2.imread('src/assets/dogs.jpg')
|
|
||||||
predictor.set_image(image)
|
|
||||||
image_embedding = predictor.get_image_embedding().cpu().numpy()
|
|
||||||
np.save("dogs_embedding.npy", image_embedding)
|
|
||||||
```
|
|
||||||
|
|
||||||
Save the new image and embedding in `src/assets/data`.
|
|
||||||
|
|
||||||
## Export the ONNX model
|
|
||||||
|
|
||||||
You also need to export the quantized ONNX model from the [ONNX Model Example notebook](https://github.com/facebookresearch/segment-anything/blob/main/notebooks/onnx_model_example.ipynb).
|
|
||||||
|
|
||||||
Run the cell in the notebook which saves the `sam_onnx_quantized_example.onnx` file, download it and copy it to the path `/model/sam_onnx_quantized_example.onnx`.
|
|
||||||
|
|
||||||
Here is a snippet of the export/quantization code:
|
|
||||||
|
|
||||||
```
|
|
||||||
onnx_model_path = "sam_onnx_example.onnx"
|
|
||||||
onnx_model_quantized_path = "sam_onnx_quantized_example.onnx"
|
|
||||||
quantize_dynamic(
|
|
||||||
model_input=onnx_model_path,
|
|
||||||
model_output=onnx_model_quantized_path,
|
|
||||||
optimize_model=True,
|
|
||||||
per_channel=False,
|
|
||||||
reduce_range=False,
|
|
||||||
weight_type=QuantType.QUInt8,
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
**NOTE: if you change the ONNX model by using a new checkpoint you need to also re-export the embedding.**
|
|
||||||
|
|
||||||
## Update the image, embedding, model in the app
|
|
||||||
|
|
||||||
Update the following file paths at the top of`App.tsx`:
|
|
||||||
|
|
||||||
```py
|
|
||||||
const IMAGE_PATH = "/assets/data/dogs.jpg";
|
|
||||||
const IMAGE_EMBEDDING = "/assets/data/dogs_embedding.npy";
|
|
||||||
const MODEL_DIR = "/model/sam_onnx_quantized_example.onnx";
|
|
||||||
```
|
|
||||||
|
|
||||||
## ONNX multithreading with SharedArrayBuffer
|
|
||||||
|
|
||||||
To use multithreading, the appropriate headers need to be set to create a cross origin isolation state which will enable use of `SharedArrayBuffer` (see this [blog post](https://cloudblogs.microsoft.com/opensource/2021/09/02/onnx-runtime-web-running-your-machine-learning-model-in-browser/) for more details)
|
|
||||||
|
|
||||||
The headers below are set in `configs/webpack/dev.js`:
|
|
||||||
|
|
||||||
```js
|
|
||||||
headers: {
|
|
||||||
"Cross-Origin-Opener-Policy": "same-origin",
|
|
||||||
"Cross-Origin-Embedder-Policy": "credentialless",
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Structure of the app
|
|
||||||
|
|
||||||
**`App.tsx`**
|
|
||||||
|
|
||||||
- Initializes ONNX model
|
|
||||||
- Loads image embedding and image
|
|
||||||
- Runs the ONNX model based on input prompts
|
|
||||||
|
|
||||||
**`Stage.tsx`**
|
|
||||||
|
|
||||||
- Handles mouse move interaction to update the ONNX model prompt
|
|
||||||
|
|
||||||
**`Tool.tsx`**
|
|
||||||
|
|
||||||
- Renders the image and the mask prediction
|
|
||||||
|
|
||||||
**`helpers/maskUtils.tsx`**
|
|
||||||
|
|
||||||
- Conversion of ONNX model output from array to an HTMLImageElement
|
|
||||||
|
|
||||||
**`helpers/onnxModelAPI.tsx`**
|
|
||||||
|
|
||||||
- Formats the inputs for the ONNX model
|
|
||||||
|
|
||||||
**`helpers/scaleHelper.tsx`**
|
|
||||||
|
|
||||||
- Handles image scaling logic for SAM (longest size 1024)
|
|
||||||
|
|
||||||
**`hooks/`**
|
|
||||||
|
|
||||||
- Handle shared state for the app
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
||||||
// All rights reserved.
|
|
||||||
|
|
||||||
// This source code is licensed under the license found in the
|
|
||||||
// LICENSE file in the root directory of this source tree.
|
|
||||||
|
|
||||||
const { resolve } = require("path");
|
|
||||||
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
|
||||||
const FriendlyErrorsWebpackPlugin = require("friendly-errors-webpack-plugin");
|
|
||||||
const CopyPlugin = require("copy-webpack-plugin");
|
|
||||||
const webpack = require("webpack");
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
entry: "./src/index.tsx",
|
|
||||||
resolve: {
|
|
||||||
extensions: [".js", ".jsx", ".ts", ".tsx"],
|
|
||||||
},
|
|
||||||
output: {
|
|
||||||
path: resolve(__dirname, "dist"),
|
|
||||||
},
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.mjs$/,
|
|
||||||
include: /node_modules/,
|
|
||||||
type: "javascript/auto",
|
|
||||||
resolve: {
|
|
||||||
fullySpecified: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: [/\.jsx?$/, /\.tsx?$/],
|
|
||||||
use: ["ts-loader"],
|
|
||||||
exclude: /node_modules/,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.css$/,
|
|
||||||
use: ["style-loader", "css-loader"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.(scss|sass)$/,
|
|
||||||
use: ["style-loader", "css-loader", "postcss-loader"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.(jpe?g|png|gif|svg)$/i,
|
|
||||||
use: [
|
|
||||||
"file-loader?hash=sha512&digest=hex&name=img/[contenthash].[ext]",
|
|
||||||
"image-webpack-loader?bypassOnDebug&optipng.optimizationLevel=7&gifsicle.interlaced=false",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.(woff|woff2|ttf)$/,
|
|
||||||
use: {
|
|
||||||
loader: "url-loader",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new CopyPlugin({
|
|
||||||
patterns: [
|
|
||||||
{
|
|
||||||
from: "node_modules/onnxruntime-web/dist/*.wasm",
|
|
||||||
to: "[name][ext]",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
from: "model",
|
|
||||||
to: "model",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
from: "src/assets",
|
|
||||||
to: "assets",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
new HtmlWebpackPlugin({
|
|
||||||
template: "./src/assets/index.html",
|
|
||||||
}),
|
|
||||||
new FriendlyErrorsWebpackPlugin(),
|
|
||||||
new webpack.ProvidePlugin({
|
|
||||||
process: "process/browser",
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
};
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
||||||
// All rights reserved.
|
|
||||||
|
|
||||||
// This source code is licensed under the license found in the
|
|
||||||
// LICENSE file in the root directory of this source tree.
|
|
||||||
|
|
||||||
// development config
|
|
||||||
const { merge } = require("webpack-merge");
|
|
||||||
const commonConfig = require("./common");
|
|
||||||
|
|
||||||
module.exports = merge(commonConfig, {
|
|
||||||
mode: "development",
|
|
||||||
devServer: {
|
|
||||||
hot: true, // enable HMR on the server
|
|
||||||
open: true,
|
|
||||||
// These headers enable the cross origin isolation state
|
|
||||||
// needed to enable use of SharedArrayBuffer for ONNX
|
|
||||||
// multithreading.
|
|
||||||
headers: {
|
|
||||||
"Cross-Origin-Opener-Policy": "same-origin",
|
|
||||||
"Cross-Origin-Embedder-Policy": "credentialless",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
devtool: "cheap-module-source-map",
|
|
||||||
});
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
||||||
// All rights reserved.
|
|
||||||
|
|
||||||
// This source code is licensed under the license found in the
|
|
||||||
// LICENSE file in the root directory of this source tree.
|
|
||||||
|
|
||||||
// production config
|
|
||||||
const { merge } = require("webpack-merge");
|
|
||||||
const { resolve } = require("path");
|
|
||||||
const Dotenv = require("dotenv-webpack");
|
|
||||||
const commonConfig = require("./common");
|
|
||||||
|
|
||||||
module.exports = merge(commonConfig, {
|
|
||||||
mode: "production",
|
|
||||||
output: {
|
|
||||||
filename: "js/bundle.[contenthash].min.js",
|
|
||||||
path: resolve(__dirname, "../../dist"),
|
|
||||||
publicPath: "/",
|
|
||||||
},
|
|
||||||
devtool: "source-map",
|
|
||||||
plugins: [new Dotenv()],
|
|
||||||
});
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "segment-anything-mini-demo",
|
|
||||||
"version": "0.1.0",
|
|
||||||
"license": "MIT",
|
|
||||||
"scripts": {
|
|
||||||
"build": "yarn run clean-dist && webpack --config=configs/webpack/prod.js && mv dist/*.wasm dist/js",
|
|
||||||
"clean-dist": "rimraf dist/*",
|
|
||||||
"lint": "eslint './src/**/*.{js,ts,tsx}' --quiet",
|
|
||||||
"start": "yarn run start-dev",
|
|
||||||
"test": "yarn run start-model-test",
|
|
||||||
"start-dev": "webpack serve --config=configs/webpack/dev.js"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@babel/core": "^7.18.13",
|
|
||||||
"@babel/preset-env": "^7.18.10",
|
|
||||||
"@babel/preset-react": "^7.18.6",
|
|
||||||
"@babel/preset-typescript": "^7.18.6",
|
|
||||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.7",
|
|
||||||
"@testing-library/react": "^13.3.0",
|
|
||||||
"@types/node": "^18.7.13",
|
|
||||||
"@types/react": "^18.0.17",
|
|
||||||
"@types/react-dom": "^18.0.6",
|
|
||||||
"@types/underscore": "^1.11.4",
|
|
||||||
"@typescript-eslint/eslint-plugin": "^5.35.1",
|
|
||||||
"@typescript-eslint/parser": "^5.35.1",
|
|
||||||
"babel-loader": "^8.2.5",
|
|
||||||
"copy-webpack-plugin": "^11.0.0",
|
|
||||||
"css-loader": "^6.7.1",
|
|
||||||
"dotenv": "^16.0.2",
|
|
||||||
"dotenv-webpack": "^8.0.1",
|
|
||||||
"eslint": "^8.22.0",
|
|
||||||
"eslint-plugin-react": "^7.31.0",
|
|
||||||
"file-loader": "^6.2.0",
|
|
||||||
"fork-ts-checker-webpack-plugin": "^7.2.13",
|
|
||||||
"friendly-errors-webpack-plugin": "^1.7.0",
|
|
||||||
"html-webpack-plugin": "^5.5.0",
|
|
||||||
"image-webpack-loader": "^8.1.0",
|
|
||||||
"postcss-loader": "^7.0.1",
|
|
||||||
"postcss-preset-env": "^7.8.0",
|
|
||||||
"process": "^0.11.10",
|
|
||||||
"rimraf": "^3.0.2",
|
|
||||||
"sass": "^1.54.5",
|
|
||||||
"sass-loader": "^13.0.2",
|
|
||||||
"style-loader": "^3.3.1",
|
|
||||||
"tailwindcss": "^3.1.8",
|
|
||||||
"ts-loader": "^9.3.1",
|
|
||||||
"typescript": "^4.8.2",
|
|
||||||
"webpack": "^5.74.0",
|
|
||||||
"webpack-cli": "^4.10.0",
|
|
||||||
"webpack-dev-server": "^4.10.0",
|
|
||||||
"webpack-dotenv-plugin": "^2.1.0",
|
|
||||||
"webpack-merge": "^5.8.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"npyjs": "^0.4.0",
|
|
||||||
"onnxruntime-web": "^1.14.0",
|
|
||||||
"react": "^18.2.0",
|
|
||||||
"react-dom": "^18.2.0",
|
|
||||||
"underscore": "^1.13.6",
|
|
||||||
"react-refresh": "^0.14.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
||||||
// All rights reserved.
|
|
||||||
|
|
||||||
// This source code is licensed under the license found in the
|
|
||||||
// LICENSE file in the root directory of this source tree.
|
|
||||||
|
|
||||||
const tailwindcss = require("tailwindcss");
|
|
||||||
module.exports = {
|
|
||||||
plugins: ["postcss-preset-env", 'tailwindcss/nesting', tailwindcss],
|
|
||||||
};
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
||||||
// All rights reserved.
|
|
||||||
|
|
||||||
// This source code is licensed under the license found in the
|
|
||||||
// LICENSE file in the root directory of this source tree.
|
|
||||||
|
|
||||||
import { InferenceSession, Tensor } from "onnxruntime-web";
|
|
||||||
import React, { useContext, useEffect, useState } from "react";
|
|
||||||
import "./assets/scss/App.scss";
|
|
||||||
import { handleImageScale } from "./components/helpers/scaleHelper";
|
|
||||||
import { modelScaleProps } from "./components/helpers/Interfaces";
|
|
||||||
import { onnxMaskToImage } from "./components/helpers/maskUtils";
|
|
||||||
import { modelData } from "./components/helpers/onnxModelAPI";
|
|
||||||
import Stage from "./components/Stage";
|
|
||||||
import AppContext from "./components/hooks/createContext";
|
|
||||||
const ort = require("onnxruntime-web");
|
|
||||||
/* @ts-ignore */
|
|
||||||
import npyjs from "npyjs";
|
|
||||||
|
|
||||||
// Define image, embedding and model paths
|
|
||||||
const IMAGE_PATH = "/assets/data/dogs.jpg";
|
|
||||||
const IMAGE_EMBEDDING = "/assets/data/dogs_embedding.npy";
|
|
||||||
const MODEL_DIR = "/model/sam_onnx_quantized_example.onnx";
|
|
||||||
|
|
||||||
const App = () => {
|
|
||||||
const {
|
|
||||||
clicks: [clicks],
|
|
||||||
image: [, setImage],
|
|
||||||
maskImg: [, setMaskImg],
|
|
||||||
} = useContext(AppContext)!;
|
|
||||||
const [model, setModel] = useState<InferenceSession | null>(null); // ONNX model
|
|
||||||
const [tensor, setTensor] = useState<Tensor | null>(null); // Image embedding tensor
|
|
||||||
|
|
||||||
// The ONNX model expects the input to be rescaled to 1024.
|
|
||||||
// The modelScale state variable keeps track of the scale values.
|
|
||||||
const [modelScale, setModelScale] = useState<modelScaleProps | null>(null);
|
|
||||||
|
|
||||||
// Initialize the ONNX model. load the image, and load the SAM
|
|
||||||
// pre-computed image embedding
|
|
||||||
useEffect(() => {
|
|
||||||
// Initialize the ONNX model
|
|
||||||
const initModel = async () => {
|
|
||||||
try {
|
|
||||||
if (MODEL_DIR === undefined) return;
|
|
||||||
const URL: string = MODEL_DIR;
|
|
||||||
const model = await InferenceSession.create(URL);
|
|
||||||
setModel(model);
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
initModel();
|
|
||||||
|
|
||||||
// Load the image
|
|
||||||
const url = new URL(IMAGE_PATH, location.origin);
|
|
||||||
loadImage(url);
|
|
||||||
|
|
||||||
// Load the Segment Anything pre-computed embedding
|
|
||||||
Promise.resolve(loadNpyTensor(IMAGE_EMBEDDING, "float32")).then(
|
|
||||||
(embedding) => setTensor(embedding)
|
|
||||||
);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const loadImage = async (url: URL) => {
|
|
||||||
try {
|
|
||||||
const img = new Image();
|
|
||||||
img.src = url.href;
|
|
||||||
img.onload = () => {
|
|
||||||
const { height, width, samScale } = handleImageScale(img);
|
|
||||||
setModelScale({
|
|
||||||
height: height, // original image height
|
|
||||||
width: width, // original image width
|
|
||||||
samScale: samScale, // scaling factor for image which has been resized to longest side 1024
|
|
||||||
});
|
|
||||||
img.width = width;
|
|
||||||
img.height = height;
|
|
||||||
setImage(img);
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Decode a Numpy file into a tensor.
|
|
||||||
const loadNpyTensor = async (tensorFile: string, dType: string) => {
|
|
||||||
let npLoader = new npyjs();
|
|
||||||
const npArray = await npLoader.load(tensorFile);
|
|
||||||
const tensor = new ort.Tensor(dType, npArray.data, npArray.shape);
|
|
||||||
return tensor;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Run the ONNX model every time clicks has changed
|
|
||||||
useEffect(() => {
|
|
||||||
runONNX();
|
|
||||||
}, [clicks]);
|
|
||||||
|
|
||||||
const runONNX = async () => {
|
|
||||||
try {
|
|
||||||
if (
|
|
||||||
model === null ||
|
|
||||||
clicks === null ||
|
|
||||||
tensor === null ||
|
|
||||||
modelScale === null
|
|
||||||
)
|
|
||||||
return;
|
|
||||||
else {
|
|
||||||
// Preapre the model input in the correct format for SAM.
|
|
||||||
// The modelData function is from onnxModelAPI.tsx.
|
|
||||||
const feeds = modelData({
|
|
||||||
clicks,
|
|
||||||
tensor,
|
|
||||||
modelScale,
|
|
||||||
});
|
|
||||||
if (feeds === undefined) return;
|
|
||||||
// Run the SAM ONNX model with the feeds returned from modelData()
|
|
||||||
const results = await model.run(feeds);
|
|
||||||
const output = results[model.outputNames[0]];
|
|
||||||
// The predicted mask returned from the ONNX model is an array which is
|
|
||||||
// rendered as an HTML image using onnxMaskToImage() from maskUtils.tsx.
|
|
||||||
setMaskImg(onnxMaskToImage(output.data, output.dims[2], output.dims[3]));
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return <Stage />;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default App;
|
|
||||||
|
Before Width: | Height: | Size: 438 KiB |
@@ -1,18 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en" dir="ltr" prefix="og: https://ogp.me/ns#" class="w-full h-full">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta
|
|
||||||
name="viewport"
|
|
||||||
content="width=device-width, initial-scale=1, shrink-to-fit=no"
|
|
||||||
/>
|
|
||||||
<title>Segment Anything Demo</title>
|
|
||||||
|
|
||||||
<!-- Meta Tags -->
|
|
||||||
<meta property="og:type" content="website" />
|
|
||||||
<meta property="og:title" content="Segment Anything Demo" />
|
|
||||||
</head>
|
|
||||||
<body class="w-full h-full">
|
|
||||||
<div id="root" class="w-full h-full"></div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
@tailwind base;
|
|
||||||
@tailwind components;
|
|
||||||
@tailwind utilities;
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
||||||
// All rights reserved.
|
|
||||||
|
|
||||||
// This source code is licensed under the license found in the
|
|
||||||
// LICENSE file in the root directory of this source tree.
|
|
||||||
|
|
||||||
import React, { useContext } from "react";
|
|
||||||
import * as _ from "underscore";
|
|
||||||
import Tool from "./Tool";
|
|
||||||
import { modelInputProps } from "./helpers/Interfaces";
|
|
||||||
import AppContext from "./hooks/createContext";
|
|
||||||
|
|
||||||
const Stage = () => {
|
|
||||||
const {
|
|
||||||
clicks: [, setClicks],
|
|
||||||
image: [image],
|
|
||||||
} = useContext(AppContext)!;
|
|
||||||
|
|
||||||
const getClick = (x: number, y: number): modelInputProps => {
|
|
||||||
const clickType = 1;
|
|
||||||
return { x, y, clickType };
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get mouse position and scale the (x, y) coordinates back to the natural
|
|
||||||
// scale of the image. Update the state of clicks with setClicks to trigger
|
|
||||||
// the ONNX model to run and generate a new mask via a useEffect in App.tsx
|
|
||||||
const handleMouseMove = _.throttle((e: any) => {
|
|
||||||
let el = e.nativeEvent.target;
|
|
||||||
const rect = el.getBoundingClientRect();
|
|
||||||
let x = e.clientX - rect.left;
|
|
||||||
let y = e.clientY - rect.top;
|
|
||||||
const imageScale = image ? image.width / el.offsetWidth : 1;
|
|
||||||
x *= imageScale;
|
|
||||||
y *= imageScale;
|
|
||||||
const click = getClick(x, y);
|
|
||||||
if (click) setClicks([click]);
|
|
||||||
}, 15);
|
|
||||||
|
|
||||||
const flexCenterClasses = "flex items-center justify-center";
|
|
||||||
return (
|
|
||||||
<div className={`${flexCenterClasses} w-full h-full`}>
|
|
||||||
<div className={`${flexCenterClasses} relative w-[90%] h-[90%]`}>
|
|
||||||
<Tool handleMouseMove={handleMouseMove} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Stage;
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
||||||
// All rights reserved.
|
|
||||||
|
|
||||||
// This source code is licensed under the license found in the
|
|
||||||
// LICENSE file in the root directory of this source tree.
|
|
||||||
|
|
||||||
import React, { useContext, useEffect, useState } from "react";
|
|
||||||
import AppContext from "./hooks/createContext";
|
|
||||||
import { ToolProps } from "./helpers/Interfaces";
|
|
||||||
import * as _ from "underscore";
|
|
||||||
|
|
||||||
const Tool = ({ handleMouseMove }: ToolProps) => {
|
|
||||||
const {
|
|
||||||
image: [image],
|
|
||||||
maskImg: [maskImg, setMaskImg],
|
|
||||||
} = useContext(AppContext)!;
|
|
||||||
|
|
||||||
// Determine if we should shrink or grow the images to match the
|
|
||||||
// width or the height of the page and setup a ResizeObserver to
|
|
||||||
// monitor changes in the size of the page
|
|
||||||
const [shouldFitToWidth, setShouldFitToWidth] = useState(true);
|
|
||||||
const bodyEl = document.body;
|
|
||||||
const fitToPage = () => {
|
|
||||||
if (!image) return;
|
|
||||||
const imageAspectRatio = image.width / image.height;
|
|
||||||
const screenAspectRatio = window.innerWidth / window.innerHeight;
|
|
||||||
setShouldFitToWidth(imageAspectRatio > screenAspectRatio);
|
|
||||||
};
|
|
||||||
const resizeObserver = new ResizeObserver((entries) => {
|
|
||||||
for (const entry of entries) {
|
|
||||||
if (entry.target === bodyEl) {
|
|
||||||
fitToPage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
useEffect(() => {
|
|
||||||
fitToPage();
|
|
||||||
resizeObserver.observe(bodyEl);
|
|
||||||
return () => {
|
|
||||||
resizeObserver.unobserve(bodyEl);
|
|
||||||
};
|
|
||||||
}, [image]);
|
|
||||||
|
|
||||||
const imageClasses = "";
|
|
||||||
const maskImageClasses = `absolute opacity-40 pointer-events-none`;
|
|
||||||
|
|
||||||
// Render the image and the predicted mask image on top
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{image && (
|
|
||||||
<img
|
|
||||||
onMouseMove={handleMouseMove}
|
|
||||||
onMouseOut={() => _.defer(() => setMaskImg(null))}
|
|
||||||
onTouchStart={handleMouseMove}
|
|
||||||
src={image.src}
|
|
||||||
className={`${
|
|
||||||
shouldFitToWidth ? "w-full" : "h-full"
|
|
||||||
} ${imageClasses}`}
|
|
||||||
></img>
|
|
||||||
)}
|
|
||||||
{maskImg && (
|
|
||||||
<img
|
|
||||||
src={maskImg.src}
|
|
||||||
className={`${
|
|
||||||
shouldFitToWidth ? "w-full" : "h-full"
|
|
||||||
} ${maskImageClasses}`}
|
|
||||||
></img>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Tool;
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
||||||
// All rights reserved.
|
|
||||||
|
|
||||||
// This source code is licensed under the license found in the
|
|
||||||
// LICENSE file in the root directory of this source tree.
|
|
||||||
|
|
||||||
import { Tensor } from "onnxruntime-web";
|
|
||||||
|
|
||||||
export interface modelScaleProps {
|
|
||||||
samScale: number;
|
|
||||||
height: number;
|
|
||||||
width: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface modelInputProps {
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
clickType: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface modeDataProps {
|
|
||||||
clicks?: Array<modelInputProps>;
|
|
||||||
tensor: Tensor;
|
|
||||||
modelScale: modelScaleProps;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ToolProps {
|
|
||||||
handleMouseMove: (e: any) => void;
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
||||||
// All rights reserved.
|
|
||||||
|
|
||||||
// This source code is licensed under the license found in the
|
|
||||||
// LICENSE file in the root directory of this source tree.
|
|
||||||
|
|
||||||
// Convert the onnx model mask prediction to ImageData
|
|
||||||
function arrayToImageData(input: any, width: number, height: number) {
|
|
||||||
const [r, g, b, a] = [0, 114, 189, 255]; // the masks's blue color
|
|
||||||
const arr = new Uint8ClampedArray(4 * width * height).fill(0);
|
|
||||||
for (let i = 0; i < input.length; i++) {
|
|
||||||
|
|
||||||
// Threshold the onnx model mask prediction at 0.0
|
|
||||||
// This is equivalent to thresholding the mask using predictor.model.mask_threshold
|
|
||||||
// in python
|
|
||||||
if (input[i] > 0.0) {
|
|
||||||
arr[4 * i + 0] = r;
|
|
||||||
arr[4 * i + 1] = g;
|
|
||||||
arr[4 * i + 2] = b;
|
|
||||||
arr[4 * i + 3] = a;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new ImageData(arr, height, width);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use a Canvas element to produce an image from ImageData
|
|
||||||
function imageDataToImage(imageData: ImageData) {
|
|
||||||
const canvas = imageDataToCanvas(imageData);
|
|
||||||
const image = new Image();
|
|
||||||
image.src = canvas.toDataURL();
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Canvas elements can be created from ImageData
|
|
||||||
function imageDataToCanvas(imageData: ImageData) {
|
|
||||||
const canvas = document.createElement("canvas");
|
|
||||||
const ctx = canvas.getContext("2d");
|
|
||||||
canvas.width = imageData.width;
|
|
||||||
canvas.height = imageData.height;
|
|
||||||
ctx?.putImageData(imageData, 0, 0);
|
|
||||||
return canvas;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert the onnx model mask output to an HTMLImageElement
|
|
||||||
export function onnxMaskToImage(input: any, width: number, height: number) {
|
|
||||||
return imageDataToImage(arrayToImageData(input, width, height));
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
||||||
// All rights reserved.
|
|
||||||
|
|
||||||
// This source code is licensed under the license found in the
|
|
||||||
// LICENSE file in the root directory of this source tree.
|
|
||||||
|
|
||||||
import { Tensor } from "onnxruntime-web";
|
|
||||||
import { modeDataProps } from "./Interfaces";
|
|
||||||
|
|
||||||
const modelData = ({ clicks, tensor, modelScale }: modeDataProps) => {
|
|
||||||
const imageEmbedding = tensor;
|
|
||||||
let pointCoords;
|
|
||||||
let pointLabels;
|
|
||||||
let pointCoordsTensor;
|
|
||||||
let pointLabelsTensor;
|
|
||||||
|
|
||||||
// Check there are input click prompts
|
|
||||||
if (clicks) {
|
|
||||||
let n = clicks.length;
|
|
||||||
|
|
||||||
// If there is no box input, a single padding point with
|
|
||||||
// label -1 and coordinates (0.0, 0.0) should be concatenated
|
|
||||||
// so initialize the array to support (n + 1) points.
|
|
||||||
pointCoords = new Float32Array(2 * (n + 1));
|
|
||||||
pointLabels = new Float32Array(n + 1);
|
|
||||||
|
|
||||||
// Add clicks and scale to what SAM expects
|
|
||||||
for (let i = 0; i < n; i++) {
|
|
||||||
pointCoords[2 * i] = clicks[i].x * modelScale.samScale;
|
|
||||||
pointCoords[2 * i + 1] = clicks[i].y * modelScale.samScale;
|
|
||||||
pointLabels[i] = clicks[i].clickType;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add in the extra point/label when only clicks and no box
|
|
||||||
// The extra point is at (0, 0) with label -1
|
|
||||||
pointCoords[2 * n] = 0.0;
|
|
||||||
pointCoords[2 * n + 1] = 0.0;
|
|
||||||
pointLabels[n] = -1.0;
|
|
||||||
|
|
||||||
// Create the tensor
|
|
||||||
pointCoordsTensor = new Tensor("float32", pointCoords, [1, n + 1, 2]);
|
|
||||||
pointLabelsTensor = new Tensor("float32", pointLabels, [1, n + 1]);
|
|
||||||
}
|
|
||||||
const imageSizeTensor = new Tensor("float32", [
|
|
||||||
modelScale.height,
|
|
||||||
modelScale.width,
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (pointCoordsTensor === undefined || pointLabelsTensor === undefined)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// There is no previous mask, so default to an empty tensor
|
|
||||||
const maskInput = new Tensor(
|
|
||||||
"float32",
|
|
||||||
new Float32Array(256 * 256),
|
|
||||||
[1, 1, 256, 256]
|
|
||||||
);
|
|
||||||
// There is no previous mask, so default to 0
|
|
||||||
const hasMaskInput = new Tensor("float32", [0]);
|
|
||||||
|
|
||||||
return {
|
|
||||||
image_embeddings: imageEmbedding,
|
|
||||||
point_coords: pointCoordsTensor,
|
|
||||||
point_labels: pointLabelsTensor,
|
|
||||||
orig_im_size: imageSizeTensor,
|
|
||||||
mask_input: maskInput,
|
|
||||||
has_mask_input: hasMaskInput,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export { modelData };
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
||||||
// All rights reserved.
|
|
||||||
|
|
||||||
// This source code is licensed under the license found in the
|
|
||||||
// LICENSE file in the root directory of this source tree.
|
|
||||||
|
|
||||||
|
|
||||||
// Helper function for handling image scaling needed for SAM
|
|
||||||
const handleImageScale = (image: HTMLImageElement) => {
|
|
||||||
// Input images to SAM must be resized so the longest side is 1024
|
|
||||||
const LONG_SIDE_LENGTH = 1024;
|
|
||||||
let w = image.naturalWidth;
|
|
||||||
let h = image.naturalHeight;
|
|
||||||
const samScale = LONG_SIDE_LENGTH / Math.max(h, w);
|
|
||||||
return { height: h, width: w, samScale };
|
|
||||||
};
|
|
||||||
|
|
||||||
export { handleImageScale };
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
||||||
// All rights reserved.
|
|
||||||
|
|
||||||
// This source code is licensed under the license found in the
|
|
||||||
// LICENSE file in the root directory of this source tree.
|
|
||||||
|
|
||||||
import React, { useState } from "react";
|
|
||||||
import { modelInputProps } from "../helpers/Interfaces";
|
|
||||||
import AppContext from "./createContext";
|
|
||||||
|
|
||||||
const AppContextProvider = (props: {
|
|
||||||
children: React.ReactElement<any, string | React.JSXElementConstructor<any>>;
|
|
||||||
}) => {
|
|
||||||
const [clicks, setClicks] = useState<Array<modelInputProps> | null>(null);
|
|
||||||
const [image, setImage] = useState<HTMLImageElement | null>(null);
|
|
||||||
const [maskImg, setMaskImg] = useState<HTMLImageElement | null>(null);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<AppContext.Provider
|
|
||||||
value={{
|
|
||||||
clicks: [clicks, setClicks],
|
|
||||||
image: [image, setImage],
|
|
||||||
maskImg: [maskImg, setMaskImg],
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{props.children}
|
|
||||||
</AppContext.Provider>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default AppContextProvider;
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
||||||
// All rights reserved.
|
|
||||||
|
|
||||||
// This source code is licensed under the license found in the
|
|
||||||
// LICENSE file in the root directory of this source tree.
|
|
||||||
|
|
||||||
import { createContext } from "react";
|
|
||||||
import { modelInputProps } from "../helpers/Interfaces";
|
|
||||||
|
|
||||||
interface contextProps {
|
|
||||||
clicks: [
|
|
||||||
clicks: modelInputProps[] | null,
|
|
||||||
setClicks: (e: modelInputProps[] | null) => void
|
|
||||||
];
|
|
||||||
image: [
|
|
||||||
image: HTMLImageElement | null,
|
|
||||||
setImage: (e: HTMLImageElement | null) => void
|
|
||||||
];
|
|
||||||
maskImg: [
|
|
||||||
maskImg: HTMLImageElement | null,
|
|
||||||
setMaskImg: (e: HTMLImageElement | null) => void
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
const AppContext = createContext<contextProps | null>(null);
|
|
||||||
|
|
||||||
export default AppContext;
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
||||||
// All rights reserved.
|
|
||||||
|
|
||||||
// This source code is licensed under the license found in the
|
|
||||||
// LICENSE file in the root directory of this source tree.
|
|
||||||
|
|
||||||
import * as React from "react";
|
|
||||||
import { createRoot } from "react-dom/client";
|
|
||||||
import AppContextProvider from "./components/hooks/context";
|
|
||||||
import App from "./App";
|
|
||||||
const container = document.getElementById("root");
|
|
||||||
const root = createRoot(container!);
|
|
||||||
root.render(
|
|
||||||
<AppContextProvider>
|
|
||||||
<App/>
|
|
||||||
</AppContextProvider>
|
|
||||||
);
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
||||||
// All rights reserved.
|
|
||||||
|
|
||||||
// This source code is licensed under the license found in the
|
|
||||||
// LICENSE file in the root directory of this source tree.
|
|
||||||
|
|
||||||
/** @type {import('tailwindcss').Config} */
|
|
||||||
module.exports = {
|
|
||||||
content: ["./src/**/*.{html,js,tsx}"],
|
|
||||||
theme: {},
|
|
||||||
plugins: [],
|
|
||||||
};
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"lib": ["dom", "dom.iterable", "esnext"],
|
|
||||||
"allowJs": true,
|
|
||||||
"skipLibCheck": true,
|
|
||||||
"strict": true,
|
|
||||||
"forceConsistentCasingInFileNames": true,
|
|
||||||
"noEmit": false,
|
|
||||||
"esModuleInterop": true,
|
|
||||||
"module": "esnext",
|
|
||||||
"moduleResolution": "node",
|
|
||||||
"resolveJsonModule": true,
|
|
||||||
"isolatedModules": true,
|
|
||||||
"jsx": "react",
|
|
||||||
"incremental": true,
|
|
||||||
"target": "ESNext",
|
|
||||||
"useDefineForClassFields": true,
|
|
||||||
"allowSyntheticDefaultImports": true,
|
|
||||||
"outDir": "./dist/",
|
|
||||||
"sourceMap": true
|
|
||||||
},
|
|
||||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "src"],
|
|
||||||
"exclude": ["node_modules"]
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import base64
|
||||||
|
import numpy as np
|
||||||
|
import cv2
|
||||||
|
from segment_anything import sam_model_registry, SamPredictor
|
||||||
|
import torch
|
||||||
|
import time
|
||||||
|
from flask import Flask, request
|
||||||
|
|
||||||
|
# check torch version and if cuda is available
|
||||||
|
print(torch.__version__)
|
||||||
|
print(torch.cuda.is_available())
|
||||||
|
# checkpoint = "sam_vit_b_01ec64.pth"
|
||||||
|
print(time.time())
|
||||||
|
# set large model related configs
|
||||||
|
checkpoint = "notebooks/sam_vit_h_4b8939.pth"
|
||||||
|
model_type = "vit_h"
|
||||||
|
sam = sam_model_registry[model_type](checkpoint=checkpoint)
|
||||||
|
sam.to(device='cuda')
|
||||||
|
predictor = SamPredictor(sam)
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def base64_to_image(base64_code):
|
||||||
|
img_data = base64.b64decode(base64_code)
|
||||||
|
img_array = np.fromstring(img_data, np.uint8)
|
||||||
|
img = cv2.imdecode(img_array, cv2.COLOR_RGB2BGR)
|
||||||
|
return img
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/embedding', methods=["GET", "POST"])
|
||||||
|
def index():
|
||||||
|
print('request received')
|
||||||
|
if (request.method != 'POST'):
|
||||||
|
return 'Only support POST method'
|
||||||
|
|
||||||
|
content_type = request.headers.get('Content-Type')
|
||||||
|
if (content_type == 'application/json'):
|
||||||
|
print('start calculate embedding')
|
||||||
|
base64data = request.get_json()['imgurl']
|
||||||
|
image = base64_to_image(base64data)
|
||||||
|
predictor.set_image(image)
|
||||||
|
image_embedding = predictor.get_image_embedding().cpu().numpy()
|
||||||
|
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
|
||||||
|
print(time.time())
|
||||||
|
return image_embedding
|
||||||
|
else:
|
||||||
|
return 'Content-Type not supported!'
|
||||||
|
|
||||||
|
|
||||||
|
app.run(port=2020, host="127.0.0.1", debug=True)
|
||||||
|
print('server starts working')
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
"cells": [
|
"cells": [
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 1,
|
"execution_count": 10,
|
||||||
"id": "5fa21d44",
|
"id": "5fa21d44",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 2,
|
"execution_count": 11,
|
||||||
"id": "072e25b8",
|
"id": "072e25b8",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
@@ -79,7 +79,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 3,
|
"execution_count": 12,
|
||||||
"id": "4fe300fb",
|
"id": "4fe300fb",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
@@ -89,7 +89,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 4,
|
"execution_count": 13,
|
||||||
"id": "0685a2f5",
|
"id": "0685a2f5",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
@@ -120,7 +120,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 5,
|
"execution_count": 14,
|
||||||
"id": "560725a2",
|
"id": "560725a2",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
@@ -133,7 +133,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 6,
|
"execution_count": 15,
|
||||||
"id": "74b6e5f0",
|
"id": "74b6e5f0",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
@@ -164,7 +164,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 7,
|
"execution_count": 16,
|
||||||
"id": "ad354922",
|
"id": "ad354922",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
@@ -175,13 +175,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 8,
|
"execution_count": 17,
|
||||||
"id": "e0ac8c67",
|
"id": "e0ac8c67",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"image/png": "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 truncated
|
"image/png": "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 truncated
|
||||||
"text/plain": [
|
"text/plain": [
|
||||||
"<Figure size 2000x2000 with 1 Axes>"
|
"<Figure size 2000x2000 with 1 Axes>"
|
||||||
]
|
]
|
||||||
@@ -215,10 +215,29 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 10,
|
"execution_count": 18,
|
||||||
"id": "1848a108",
|
"id": "1848a108",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [
|
||||||
|
{
|
||||||
|
"ename": "AssertionError",
|
||||||
|
"evalue": "Torch not compiled with CUDA enabled",
|
||||||
|
"output_type": "error",
|
||||||
|
"traceback": [
|
||||||
|
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
|
||||||
|
"\u001b[1;31mAssertionError\u001b[0m Traceback (most recent call last)",
|
||||||
|
"\u001b[1;32me:\\Sam-test\\segment-anything\\notebooks\\automatic_mask_generator_example.ipynb 单元格 17\u001b[0m line \u001b[0;36m1\n\u001b[0;32m <a href='vscode-notebook-cell:/e%3A/Sam-test/segment-anything/notebooks/automatic_mask_generator_example.ipynb#X22sZmlsZQ%3D%3D?line=7'>8</a>\u001b[0m device \u001b[39m=\u001b[39m \u001b[39m\"\u001b[39m\u001b[39mcuda\u001b[39m\u001b[39m\"\u001b[39m\n\u001b[0;32m <a href='vscode-notebook-cell:/e%3A/Sam-test/segment-anything/notebooks/automatic_mask_generator_example.ipynb#X22sZmlsZQ%3D%3D?line=9'>10</a>\u001b[0m sam \u001b[39m=\u001b[39m sam_model_registry[model_type](checkpoint\u001b[39m=\u001b[39msam_checkpoint)\n\u001b[1;32m---> <a href='vscode-notebook-cell:/e%3A/Sam-test/segment-anything/notebooks/automatic_mask_generator_example.ipynb#X22sZmlsZQ%3D%3D?line=10'>11</a>\u001b[0m sam\u001b[39m.\u001b[39;49mto(device\u001b[39m=\u001b[39;49mdevice)\n\u001b[0;32m <a href='vscode-notebook-cell:/e%3A/Sam-test/segment-anything/notebooks/automatic_mask_generator_example.ipynb#X22sZmlsZQ%3D%3D?line=12'>13</a>\u001b[0m mask_generator \u001b[39m=\u001b[39m SamAutomaticMaskGenerator(sam)\n",
|
||||||
|
"File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\torch\\nn\\modules\\module.py:1160\u001b[0m, in \u001b[0;36mModule.to\u001b[1;34m(self, *args, **kwargs)\u001b[0m\n\u001b[0;32m 1156\u001b[0m \u001b[39mreturn\u001b[39;00m t\u001b[39m.\u001b[39mto(device, dtype \u001b[39mif\u001b[39;00m t\u001b[39m.\u001b[39mis_floating_point() \u001b[39mor\u001b[39;00m t\u001b[39m.\u001b[39mis_complex() \u001b[39melse\u001b[39;00m \u001b[39mNone\u001b[39;00m,\n\u001b[0;32m 1157\u001b[0m non_blocking, memory_format\u001b[39m=\u001b[39mconvert_to_format)\n\u001b[0;32m 1158\u001b[0m \u001b[39mreturn\u001b[39;00m t\u001b[39m.\u001b[39mto(device, dtype \u001b[39mif\u001b[39;00m t\u001b[39m.\u001b[39mis_floating_point() \u001b[39mor\u001b[39;00m t\u001b[39m.\u001b[39mis_complex() \u001b[39melse\u001b[39;00m \u001b[39mNone\u001b[39;00m, non_blocking)\n\u001b[1;32m-> 1160\u001b[0m \u001b[39mreturn\u001b[39;00m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_apply(convert)\n",
|
||||||
|
"File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\torch\\nn\\modules\\module.py:810\u001b[0m, in \u001b[0;36mModule._apply\u001b[1;34m(self, fn, recurse)\u001b[0m\n\u001b[0;32m 808\u001b[0m \u001b[39mif\u001b[39;00m recurse:\n\u001b[0;32m 809\u001b[0m \u001b[39mfor\u001b[39;00m module \u001b[39min\u001b[39;00m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39mchildren():\n\u001b[1;32m--> 810\u001b[0m module\u001b[39m.\u001b[39;49m_apply(fn)\n\u001b[0;32m 812\u001b[0m \u001b[39mdef\u001b[39;00m \u001b[39mcompute_should_use_set_data\u001b[39m(tensor, tensor_applied):\n\u001b[0;32m 813\u001b[0m \u001b[39mif\u001b[39;00m torch\u001b[39m.\u001b[39m_has_compatible_shallow_copy_type(tensor, tensor_applied):\n\u001b[0;32m 814\u001b[0m \u001b[39m# If the new tensor has compatible tensor type as the existing tensor,\u001b[39;00m\n\u001b[0;32m 815\u001b[0m \u001b[39m# the current behavior is to change the tensor in-place using `.data =`,\u001b[39;00m\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 820\u001b[0m \u001b[39m# global flag to let the user control whether they want the future\u001b[39;00m\n\u001b[0;32m 821\u001b[0m \u001b[39m# behavior of overwriting the existing tensor or not.\u001b[39;00m\n",
|
||||||
|
"File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\torch\\nn\\modules\\module.py:810\u001b[0m, in \u001b[0;36mModule._apply\u001b[1;34m(self, fn, recurse)\u001b[0m\n\u001b[0;32m 808\u001b[0m \u001b[39mif\u001b[39;00m recurse:\n\u001b[0;32m 809\u001b[0m \u001b[39mfor\u001b[39;00m module \u001b[39min\u001b[39;00m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39mchildren():\n\u001b[1;32m--> 810\u001b[0m module\u001b[39m.\u001b[39;49m_apply(fn)\n\u001b[0;32m 812\u001b[0m \u001b[39mdef\u001b[39;00m \u001b[39mcompute_should_use_set_data\u001b[39m(tensor, tensor_applied):\n\u001b[0;32m 813\u001b[0m \u001b[39mif\u001b[39;00m torch\u001b[39m.\u001b[39m_has_compatible_shallow_copy_type(tensor, tensor_applied):\n\u001b[0;32m 814\u001b[0m \u001b[39m# If the new tensor has compatible tensor type as the existing tensor,\u001b[39;00m\n\u001b[0;32m 815\u001b[0m \u001b[39m# the current behavior is to change the tensor in-place using `.data =`,\u001b[39;00m\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 820\u001b[0m \u001b[39m# global flag to let the user control whether they want the future\u001b[39;00m\n\u001b[0;32m 821\u001b[0m \u001b[39m# behavior of overwriting the existing tensor or not.\u001b[39;00m\n",
|
||||||
|
"File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\torch\\nn\\modules\\module.py:810\u001b[0m, in \u001b[0;36mModule._apply\u001b[1;34m(self, fn, recurse)\u001b[0m\n\u001b[0;32m 808\u001b[0m \u001b[39mif\u001b[39;00m recurse:\n\u001b[0;32m 809\u001b[0m \u001b[39mfor\u001b[39;00m module \u001b[39min\u001b[39;00m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39mchildren():\n\u001b[1;32m--> 810\u001b[0m module\u001b[39m.\u001b[39;49m_apply(fn)\n\u001b[0;32m 812\u001b[0m \u001b[39mdef\u001b[39;00m \u001b[39mcompute_should_use_set_data\u001b[39m(tensor, tensor_applied):\n\u001b[0;32m 813\u001b[0m \u001b[39mif\u001b[39;00m torch\u001b[39m.\u001b[39m_has_compatible_shallow_copy_type(tensor, tensor_applied):\n\u001b[0;32m 814\u001b[0m \u001b[39m# If the new tensor has compatible tensor type as the existing tensor,\u001b[39;00m\n\u001b[0;32m 815\u001b[0m \u001b[39m# the current behavior is to change the tensor in-place using `.data =`,\u001b[39;00m\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 820\u001b[0m \u001b[39m# global flag to let the user control whether they want the future\u001b[39;00m\n\u001b[0;32m 821\u001b[0m \u001b[39m# behavior of overwriting the existing tensor or not.\u001b[39;00m\n",
|
||||||
|
"File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\torch\\nn\\modules\\module.py:833\u001b[0m, in \u001b[0;36mModule._apply\u001b[1;34m(self, fn, recurse)\u001b[0m\n\u001b[0;32m 829\u001b[0m \u001b[39m# Tensors stored in modules are graph leaves, and we don't want to\u001b[39;00m\n\u001b[0;32m 830\u001b[0m \u001b[39m# track autograd history of `param_applied`, so we have to use\u001b[39;00m\n\u001b[0;32m 831\u001b[0m \u001b[39m# `with torch.no_grad():`\u001b[39;00m\n\u001b[0;32m 832\u001b[0m \u001b[39mwith\u001b[39;00m torch\u001b[39m.\u001b[39mno_grad():\n\u001b[1;32m--> 833\u001b[0m param_applied \u001b[39m=\u001b[39m fn(param)\n\u001b[0;32m 834\u001b[0m should_use_set_data \u001b[39m=\u001b[39m compute_should_use_set_data(param, param_applied)\n\u001b[0;32m 835\u001b[0m \u001b[39mif\u001b[39;00m should_use_set_data:\n",
|
||||||
|
"File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\torch\\nn\\modules\\module.py:1158\u001b[0m, in \u001b[0;36mModule.to.<locals>.convert\u001b[1;34m(t)\u001b[0m\n\u001b[0;32m 1155\u001b[0m \u001b[39mif\u001b[39;00m convert_to_format \u001b[39mis\u001b[39;00m \u001b[39mnot\u001b[39;00m \u001b[39mNone\u001b[39;00m \u001b[39mand\u001b[39;00m t\u001b[39m.\u001b[39mdim() \u001b[39min\u001b[39;00m (\u001b[39m4\u001b[39m, \u001b[39m5\u001b[39m):\n\u001b[0;32m 1156\u001b[0m \u001b[39mreturn\u001b[39;00m t\u001b[39m.\u001b[39mto(device, dtype \u001b[39mif\u001b[39;00m t\u001b[39m.\u001b[39mis_floating_point() \u001b[39mor\u001b[39;00m t\u001b[39m.\u001b[39mis_complex() \u001b[39melse\u001b[39;00m \u001b[39mNone\u001b[39;00m,\n\u001b[0;32m 1157\u001b[0m non_blocking, memory_format\u001b[39m=\u001b[39mconvert_to_format)\n\u001b[1;32m-> 1158\u001b[0m \u001b[39mreturn\u001b[39;00m t\u001b[39m.\u001b[39;49mto(device, dtype \u001b[39mif\u001b[39;49;00m t\u001b[39m.\u001b[39;49mis_floating_point() \u001b[39mor\u001b[39;49;00m t\u001b[39m.\u001b[39;49mis_complex() \u001b[39melse\u001b[39;49;00m \u001b[39mNone\u001b[39;49;00m, non_blocking)\n",
|
||||||
|
"File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\torch\\cuda\\__init__.py:289\u001b[0m, in \u001b[0;36m_lazy_init\u001b[1;34m()\u001b[0m\n\u001b[0;32m 284\u001b[0m \u001b[39mraise\u001b[39;00m \u001b[39mRuntimeError\u001b[39;00m(\n\u001b[0;32m 285\u001b[0m \u001b[39m\"\u001b[39m\u001b[39mCannot re-initialize CUDA in forked subprocess. To use CUDA with \u001b[39m\u001b[39m\"\u001b[39m\n\u001b[0;32m 286\u001b[0m \u001b[39m\"\u001b[39m\u001b[39mmultiprocessing, you must use the \u001b[39m\u001b[39m'\u001b[39m\u001b[39mspawn\u001b[39m\u001b[39m'\u001b[39m\u001b[39m start method\u001b[39m\u001b[39m\"\u001b[39m\n\u001b[0;32m 287\u001b[0m )\n\u001b[0;32m 288\u001b[0m \u001b[39mif\u001b[39;00m \u001b[39mnot\u001b[39;00m \u001b[39mhasattr\u001b[39m(torch\u001b[39m.\u001b[39m_C, \u001b[39m\"\u001b[39m\u001b[39m_cuda_getDeviceCount\u001b[39m\u001b[39m\"\u001b[39m):\n\u001b[1;32m--> 289\u001b[0m \u001b[39mraise\u001b[39;00m \u001b[39mAssertionError\u001b[39;00m(\u001b[39m\"\u001b[39m\u001b[39mTorch not compiled with CUDA enabled\u001b[39m\u001b[39m\"\u001b[39m)\n\u001b[0;32m 290\u001b[0m \u001b[39mif\u001b[39;00m _cudart \u001b[39mis\u001b[39;00m \u001b[39mNone\u001b[39;00m:\n\u001b[0;32m 291\u001b[0m \u001b[39mraise\u001b[39;00m \u001b[39mAssertionError\u001b[39;00m(\n\u001b[0;32m 292\u001b[0m \u001b[39m\"\u001b[39m\u001b[39mlibcudart functions unavailable. It looks like you have a broken build?\u001b[39m\u001b[39m\"\u001b[39m\n\u001b[0;32m 293\u001b[0m )\n",
|
||||||
|
"\u001b[1;31mAssertionError\u001b[0m: Torch not compiled with CUDA enabled"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
"source": [
|
"source": [
|
||||||
"import sys\n",
|
"import sys\n",
|
||||||
"sys.path.append(\"..\")\n",
|
"sys.path.append(\"..\")\n",
|
||||||
@@ -245,7 +264,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 11,
|
"execution_count": null,
|
||||||
"id": "391771c1",
|
"id": "391771c1",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
@@ -270,7 +289,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 13,
|
"execution_count": null,
|
||||||
"id": "4fae8d66",
|
"id": "4fae8d66",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
@@ -297,7 +316,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 28,
|
"execution_count": null,
|
||||||
"id": "77ac29c5",
|
"id": "77ac29c5",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"scrolled": false
|
"scrolled": false
|
||||||
@@ -340,7 +359,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 24,
|
"execution_count": null,
|
||||||
"id": "68364513",
|
"id": "68364513",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
@@ -358,7 +377,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 25,
|
"execution_count": null,
|
||||||
"id": "bebcdaf1",
|
"id": "bebcdaf1",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
@@ -368,7 +387,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 26,
|
"execution_count": null,
|
||||||
"id": "b8473f3c",
|
"id": "b8473f3c",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
@@ -389,7 +408,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 27,
|
"execution_count": null,
|
||||||
"id": "fb702ae3",
|
"id": "fb702ae3",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
@@ -437,7 +456,7 @@
|
|||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.8.0"
|
"version": "3.10.11"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nbformat": 4,
|
"nbformat": 4,
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import numpy as np
|
||||||
|
import cv2
|
||||||
|
from segment_anything import sam_model_registry, SamPredictor
|
||||||
|
import torch
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
# check torch version and if cuda is available
|
||||||
|
print(torch.__version__)
|
||||||
|
print(torch.cuda.is_available())
|
||||||
|
# checkpoint = "sam_vit_b_01ec64.pth"
|
||||||
|
print(time.time())
|
||||||
|
# set large model related configs
|
||||||
|
checkpoint = "notebooks/sam_vit_h_4b8939.pth"
|
||||||
|
model_type = "vit_h"
|
||||||
|
sam = sam_model_registry[model_type](checkpoint=checkpoint)
|
||||||
|
sam.to(device='cuda')
|
||||||
|
predictor = SamPredictor(sam)
|
||||||
|
|
||||||
|
image_name = 'r.jpg'
|
||||||
|
image = cv2.imread('notebooks/images/' + image_name)
|
||||||
|
predictor.set_image(image)
|
||||||
|
image_embedding = predictor.get_image_embedding().cpu().numpy()
|
||||||
|
np.save(image_name + ".npy", image_embedding)
|
||||||
|
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
|
||||||