ReactJS中利用Segmentation数据绘制图像分割掩码的实现方法求助
Got it, let's tackle drawing segmentation masks with your existing React Canvas setup. First, let's break down your segmentation data: it's a list of polygon coordinates (each pair of numbers is an [x, y] point) that form a closed shape. We can use Canvas's 2D context to draw and fill this polygon as a semi-transparent mask (or outline it, if you prefer).
Here's the modified version of your code with segmentation mask support, plus explanations of key changes:
import React, { useRef, useEffect, useState } from 'react'; import './App.css'; import 'bootstrap/dist/css/bootstrap.min.css'; function App() { const [data, setData] = useState([]); const canvas = useRef(); let ctx = null; // Initialize canvas context and set dimensions useEffect(() => { const canvasEle = canvas.current; // Match canvas dimensions to your image size (assuming 512x512 here) canvasEle.width = 512; canvasEle.height = 512; ctx = canvasEle.getContext("2d"); }, []); // Draw bounding box (your existing function, kept for reference) const drawRect = (info, style = {}) => { const { x, y, w, h } = info; const { borderColor = 'black', borderWidth = 1 } = style; ctx.beginPath(); ctx.strokeStyle = borderColor; ctx.lineWidth = borderWidth; ctx.rect(x, y, w, h); ctx.stroke(); }; // New function to draw segmentation mask const drawSegmentationMask = (segmentation, style = {}) => { const { fillColor = 'rgba(255, 0, 0, 0.3)', strokeColor = 'red', strokeWidth = 2 } = style; // Your segmentation data uses a single polygon per annotation const points = segmentation[0]; if (!points || points.length < 2) return; ctx.beginPath(); // Move to the first coordinate point ctx.moveTo(points[0], points[1]); // Loop through remaining points to draw the polygon for (let i = 2; i < points.length; i += 2) { ctx.lineTo(points[i], points[i + 1]); } // Close the path to complete the shape ctx.closePath(); // Fill the mask with semi-transparent color (so image shows through) ctx.fillStyle = fillColor; ctx.fill(); // Optional: Add an outline around the mask for clarity ctx.strokeStyle = strokeColor; ctx.lineWidth = strokeWidth; ctx.stroke(); }; const getData = () => { fetch('/test.json', { headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' } }) .then(response => response.json()) .then(myJson => { setData(myJson.annotations); // Clear canvas first to prevent overlapping drawings ctx.clearRect(0, 0, canvas.current.width, canvas.current.height); // Loop through all annotations to draw both bbox and mask myJson.annotations.forEach(anno => { // Draw bounding box from bbox data const [x, y, w, h] = anno.bbox; drawRect({ x, y, w, h }, { borderColor: 'blue', borderWidth: 2 }); // Draw segmentation mask from polygon data drawSegmentationMask(anno.segmentation, { fillColor: 'rgba(0, 255, 0, 0.3)', strokeColor: 'green', strokeWidth: 2 }); }); }); }; useEffect(() => { getData(); }, []); return ( <div className="App"> <canvas style={{ height: "512px", width: "512px", backgroundImage: `url("https://karthiknbucket1.s3.ap-southeast-1.amazonaws.com/00000001.png")`, backgroundPosition: "center", backgroundSize: "100% 100%" }} ref={canvas} ></canvas> </div> ); } export default App;
Key Changes Explained:
Fixed Canvas Dimensions: We explicitly set the canvas to match your image size (512x512) to ensure your JSON coordinates align perfectly with the canvas pixel space.
drawSegmentationMaskFunction:- Parses the flat list of coordinates into
[x,y]pairs to build a polygon path - Uses semi-transparent fill color so you can still see the underlying image
- Adds an optional outline to make the mask boundaries clearer
- Parses the flat list of coordinates into
Updated
getDataFunction:- Clears the canvas before drawing to avoid overlapping if you re-fetch data
- Loops through all annotations instead of just one, drawing both the bounding box and segmentation mask for each object
Style Customization: Adjust
fillColor(use RGBA for transparency) andstrokeColorvalues to match your desired visual style.
Quick Notes:
- If your image ever scales differently than the canvas, you'll need to add a scaling factor to the coordinates (e.g., multiply each x/y by
canvas.width / originalImageWidth). For your current setup though, this isn't needed since the background is set to100% 100%. - This code handles
iscrowd: 0annotations (polygon format). If you ever haveiscrowd: 1entries, they use RLE (run-length encoding) which requires a different parsing approach.
内容的提问来源于stack exchange,提问作者Karthikeyan M

