Overlay image with a segmentation mask #897
Unanswered
charlielito
asked this question in
Q&A
Replies: 2 comments 8 replies
-
What is the format of your segmentation mask? |
Beta Was this translation helpful? Give feedback.
5 replies
-
Until this is supported natively by the Image panel, you can easily accomplish the blending with a user script. Quick and dirty, borrows a lot from the default template: Userscriptimport { Input, Message, Time } from "./types";
import { RawImage } from "@foxglove/schemas";
type Image = Message<"sensor_msgs/Image">;
type Output = Message<"foxglove.RawImage">;
export const inputs = [
"/image_color",
"/segmentation",
];
export const output = "/overlay";
let lastReceiveTime: Time = { sec: 0, nsec: 0 };
let lastReceivedImg: Image;
let inSync: Boolean = false;
const image_overlay: {
image?: Image;
segmentation?: Image;
} = {};
type GlobalVariables = { blendAlpha: number };
function blendImages(
image1Data: Uint8Array,
image2Data: Uint8Array,
blendPercentage: number,
): Uint8Array {
if (image1Data.length !== image2Data.length) {
throw new Error("Image data lengths do not match");
}
blendPercentage = Math.max(0, Math.min(100, blendPercentage));
const blendedImageData = new Uint8Array(image1Data.length);
// Blend pixel values
for (let i = 0; i < image1Data.length; i += 3) {
const b1 = image1Data[i];
const g1 = image1Data[i + 1];
const r1 = image1Data[i + 2];
const b2 = image2Data[i];
const g2 = image2Data[i + 1];
const r2 = image2Data[i + 2];
const blendedB = Math.round(
(b1 * (100 - blendPercentage) + b2 * blendPercentage) / 100,
);
const blendedG = Math.round(
(g1 * (100 - blendPercentage) + g2 * blendPercentage) / 100,
);
const blendedR = Math.round(
(r1 * (100 - blendPercentage) + r2 * blendPercentage) / 100,
);
blendedImageData[i] = blendedB;
blendedImageData[i + 1] = blendedG;
blendedImageData[i + 2] = blendedR;
}
return blendedImageData;
}
// This function is called with messages from your input topics.
// The first argument is an event with the topic, receive time, and message.
// Use the `Input<...>` helper to get the correct event type for your input topic messages.
export default function script(
event:
| Input<"/image_color">
| Input<"/segmentation">,
globalVars: GlobalVariables,
): Output | undefined {
if (event.topic === inputs[1]) {
image_overlay.segmentation = event.message;
inSync = false;
} else if (event.topic === inputs[0]) {
lastReceiveTime.sec = event.receiveTime.sec;
lastReceiveTime.nsec = event.receiveTime.nsec;
lastReceivedImg = event.message;
}
if (!inSync) {
// Compare Timestamps 100 ms range
if (
Math.abs(
event.receiveTime.sec * 1e9 +
event.receiveTime.nsec -
(lastReceiveTime.sec * 1e9 + lastReceiveTime.nsec),
) < 1e8
) {
image_overlay.image = lastReceivedImg;
inSync = true;
}
}
if (
image_overlay.image != undefined &&
image_overlay.segmentation != undefined
) {
let out_image: Output = {
timestamp: image_overlay.segmentation.header.stamp,
frame_id: image_overlay.segmentation.header.frame_id,
encoding: image_overlay.image.encoding,
height: image_overlay.image.height,
width: image_overlay.image.width,
step: image_overlay.image.step,
data: blendImages(
image_overlay.image.data,
image_overlay.segmentation.data,
globalVars.blendAlpha,
),
};
return out_image;
}
return undefined;
} For equal timestamps you can skip the timestamp logic. |
Beta Was this translation helpful? Give feedback.
3 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Hi! It would be awesome to be able to overlay some segmentation maps (stored in a topic of image type) into another normal image. Something like this:
Currently, ASFAIK the only way to do something similar is using ImageMarkers, but it is not flexible enough and doesn't give us per-pixel visualization.
Do you know if you are planning to do this or how could we implement this?
Beta Was this translation helpful? Give feedback.
All reactions