From a1f13e4ce7cb2f7b63bbb0d351ae6e6eedc2b70d Mon Sep 17 00:00:00 2001 From: LemonNeko Date: Mon, 1 Sep 2025 00:41:55 +0800 Subject: [PATCH] feat(devlog): add nms example for devlog-2026-08-26 (#537) --- docs/.vitepress/components/MotionToggle.vue | 2 +- .../DevLog-2025.08.26/components/nms-iou.vue | 203 ++++++++++++++++++ .../zh-Hans/blog/DevLog-2025.08.26/index.md | 10 + 3 files changed, 214 insertions(+), 1 deletion(-) create mode 100644 docs/content/zh-Hans/blog/DevLog-2025.08.26/components/nms-iou.vue diff --git a/docs/.vitepress/components/MotionToggle.vue b/docs/.vitepress/components/MotionToggle.vue index fa7924a62..a1d128e8b 100644 --- a/docs/.vitepress/components/MotionToggle.vue +++ b/docs/.vitepress/components/MotionToggle.vue @@ -20,7 +20,7 @@ watchPostEffect(() => { +import type { Ref } from 'vue' + +import { useDraggable, useElementBounding } from '@vueuse/core' +import { computed, ref, useTemplateRef } from 'vue' + +interface Detection { + x: number + y: number + width: number + height: number + confidence: number + className: string +} + +const box1 = ref( + { x: 100, y: 100, width: 200, height: 200, confidence: 0.9, className: 'box_1' }, +) + +const box2 = ref( + { x: 150, y: 150, width: 200, height: 200, confidence: 0.8, className: 'box_2' }, +) + +const colors = ref([ + { labelBg: 'bg-red', border: 'border-red outline-red', bg: 'bg-red/30' }, + { labelBg: 'bg-green', border: 'border-green outline-green', bg: 'bg-green/30' }, +]) + +const containerEl = useTemplateRef('containerEl') +const containerBounding = useElementBounding(containerEl, { immediate: true, windowResize: true }) + +const object1El = useTemplateRef('object1El') +const object1HandleEl = useTemplateRef('object1HandleEl') +const object2El = useTemplateRef('object2El') +const object2HandleEl = useTemplateRef('object2HandleEl') +function setupDraggableBox( + box: Ref, + el: Ref, + handle: Ref, +) { + useDraggable(el, { + handle, + initialValue: { x: box.value.x, y: box.value.y }, + onMove(p) { + box.value.x = Math.round(p.x - containerBounding.left.value) + box.value.y = Math.round(p.y - containerBounding.top.value) + }, + }) +} + +setupDraggableBox(box1, object1El, object1HandleEl) +setupDraggableBox(box2, object2El, object2HandleEl) + +const isOverlapping = computed(() => { + const b1 = box1.value + const b2 = box2.value + return ( + b1.x < b2.x + b2.width + && b1.x + b1.width > b2.x + && b1.y < b2.y + b2.height + && b1.y + b1.height > b2.y + ) +}) + +const intersect = computed(() => { + // no overlap + if (!isOverlapping.value) { + return { + xLeft: 0, + yTop: 0, + xRight: 0, + yBottom: 0, + width: 0, + height: 0, + area: 0, + } + } + + const xLeft = Math.max(box1.value.x, box2.value.x) + const yTop = Math.max(box1.value.y, box2.value.y) + const xRight = Math.min(box1.value.x + box1.value.width, box2.value.x + box2.value.width) + const yBottom = Math.min(box1.value.y + box1.value.height, box2.value.y + box2.value.height) + + const width = xRight - xLeft + const height = yBottom - yTop + + return { + xLeft, + yTop, + xRight, + yBottom, + width, + height, + area: width * height, + } +}) + +const union = computed(() => { + return { + area: box1.value.width * box1.value.height + box2.value.width * box2.value.height - intersect.value.area, + } +}) + +const iou = computed(() => { + if (union.value.area === 0) + return 0 + return intersect.value.area / union.value.area +}) + + + diff --git a/docs/content/zh-Hans/blog/DevLog-2025.08.26/index.md b/docs/content/zh-Hans/blog/DevLog-2025.08.26/index.md index 2b199acd1..d46d9d94e 100644 --- a/docs/content/zh-Hans/blog/DevLog-2025.08.26/index.md +++ b/docs/content/zh-Hans/blog/DevLog-2025.08.26/index.md @@ -8,6 +8,10 @@ preview-cover: # TODO --- + + 大家好久不见,我是 [@LemonNeko](https://github.com/LemonNekoGH),AIRI 的维护者之一。~~啊,有点厌倦这样开场了,像 LLM 一样。~~ 我的上一篇 [DevLog](../DevLog-2025.07.18/index.md) 中提到,我浅浅地看了一下 [Factorio Learning Environment](https://arxiv.org/abs/2503.09617) 论文,并且简单说了一下我们打算如何改进 `airi-factorio`,但是...今天想和大家分享的并不是这个,而是关于纯视觉方向的进展。 @@ -176,6 +180,12 @@ function nms(boxes: Box[], iouThreshold: number): Box[] { 可以在[这里](https://github.com/moeru-ai/airi-factorio/tree/ba46a4e47b31187dd064b06314b595b551ed3411/apps/factorio-yolo-v0-playground)看整个 Playground 的源代码。 +也可以在下面这个可视化组件游玩体验 IOU 和 NMS 的效果,通过拖动标签来改变框框位置: + +
+ +
+ ### 发现的问题 在这么实践下来,我发现了几个问题: