// ==UserScript== // @name MF-REID框大小检测 // @namespace http://tampermonkey.net/ // @version 1.0.0 // @description 检测REID行人项目所有帧中宽<20或高<40的不合规框(行人主框+其他行人框),悬浮窗显示不合格帧号与数量 // @match https://label.mindflow.com.cn/image* // @grant none // @run-at document-start // ==/UserScript== (function () { 'use strict'; // ========== 数据存储 ========== const frameIndexMap = {}; // frameId -> 帧号(indexNo),来自 task/info const frameDataCache = {}; // frameId -> LOCATE 组列表,来自 result/find let scanTimer = null; // ========== 检测规则 ========== const MIN_W = 20; // 最小宽度 const MIN_H = 40; // 最小高度 // ========== 悬浮窗 UI ========== let panelDom = null; let contentDom = null; function showToast(msg) { const tip = document.createElement("div"); tip.style.cssText = "position:fixed;top:24px;left:50%;transform:translateX(-50%);background:#222;color:#fff;padding:8px 14px;border-radius:6px;z-index:999999999;font-size:13px;"; tip.innerText = msg; document.body.appendChild(tip); setTimeout(() => tip.remove(), 2500); } function makeBtn(text, click) { const s = document.createElement('span'); s.innerText = text; s.style.cssText = "width:26px;height:26px;border-radius:6px;background:#e5e7eb;display:flex;align-items:center;justify-content:center;cursor:pointer;font-weight:bold;"; s.onclick = click; return s; } function initPanel() { if (panelDom && document.body.contains(panelDom)) return; panelDom = document.createElement('div'); panelDom.style.cssText = ` position: fixed; z-index: 999999999; width: 460px; left:15px; top:70px; background:#fff; border:1px solid #d1d5db; border-radius:10px; box-shadow:0 4px 20px rgba(0,0,0,0.15); font-family:"Microsoft YaHei"; font-size:13px; overflow:hidden; `; const header = document.createElement('div'); header.style.cssText = "display:flex;gap:6px;align-items:center;padding:8px 12px;background:#f3f4f6;border-bottom:1px solid #ddd;cursor:move;"; header.innerHTML = `MF-REID框大小检测`; const btnWrap = document.createElement('div'); btnWrap.style.display = 'flex'; btnWrap.append(makeBtn("↻", () => runScan(true)), makeBtn("✕", () => panelDom.remove())); header.appendChild(btnWrap); panelDom.append(header); contentDom = document.createElement('div'); contentDom.style.padding = "12px"; contentDom.style.maxHeight = "500px"; contentDom.style.overflowY = "auto"; panelDom.append(contentDom); // 拖拽 let drag = false, ox, oy; header.onmousedown = e => { drag = true; const r = panelDom.getBoundingClientRect(); ox = e.clientX - r.left; oy = e.clientY - r.top; document.onmousemove = ev => { panelDom.style.left = (ev.clientX - ox) + 'px'; panelDom.style.top = (ev.clientY - oy) + 'px'; }; document.onmouseup = () => { drag = false; document.onmousemove = null; }; }; document.body.appendChild(panelDom); } // ========== 核心扫描 ========== function checkFrame(frameId) { const groups = frameDataCache[frameId]; const bad = { main: [], other: [] }; for (const group of groups) { const toolName = group.labelToolName || ''; const isMain = toolName.indexOf('主框') !== -1; const objs = group.labelObjects || {}; for (const uuid in objs) { const obj = objs[uuid]; if (obj.valid === false) continue; // 跳过无效框 const g = obj.geometry || {}; const w = g.width, h = g.height; if (typeof w !== 'number' || typeof h !== 'number') continue; if (w < MIN_W || h < MIN_H) { const item = { uuid: obj.uuid || uuid, indexNumber: obj.indexNumber, w, h, toolName }; if (isMain) bad.main.push(item); else bad.other.push(item); } } } return bad; } function runScan(manual) { if (!panelDom || !document.body.contains(panelDom)) initPanel(); const frameIds = Object.keys(frameDataCache); const results = []; // {frameNo, frameId, main:[], other:[]} let totalBad = 0; for (const fid of frameIds) { const bad = checkFrame(fid); const cnt = bad.main.length + bad.other.length; if (cnt > 0) { totalBad += cnt; results.push({ frameNo: frameIndexMap[fid] || '?', frameId: fid, main: bad.main, other: bad.other }); } } // 按帧号排序 results.sort((a, b) => (a.frameNo === '?' ? 99999 : a.frameNo) - (b.frameNo === '?' ? 99999 : b.frameNo)); let html = ''; if (results.length === 0) { html = `