|
/**
|
* 图片辅助工具函数集合
|
* 整合了原有的imageHelper和gallery/imageUtils功能
|
*/
|
|
/**
|
* 将十六进制颜色转换为rgba
|
* @param {string} hex - 十六进制颜色
|
* @param {number} alpha - 透明度 (0-1)
|
* @returns {string} rgba颜色字符串
|
*/
|
export function hexToRgba(hex, alpha = 0.2) {
|
if (!hex || !hex.startsWith('#')) return `rgba(0, 0, 0, ${alpha})`
|
const r = parseInt(hex.slice(1, 3), 16)
|
const g = parseInt(hex.slice(3, 5), 16)
|
const b = parseInt(hex.slice(5, 7), 16)
|
return `rgba(${r}, ${g}, ${b}, ${alpha})`
|
}
|
|
/**
|
* 获取占位图像
|
*/
|
export function getPlaceholderImage() {
|
return new URL("../../static/common/icon_loading.png", import.meta.url).href
|
}
|
|
/**
|
* 图像加载错误处理
|
*/
|
export function handleImageError(event) {
|
console.warn("[ImageHelper] 图像加载失败:", event.target?.src)
|
|
// 防止无限循环:如果已经是占位图还失败,就不再尝试替换
|
const placeholderImage = getPlaceholderImage()
|
if (event.target && event.target.src === placeholderImage) {
|
console.error("[ImageHelper] 占位图像也加载失败,停止重试")
|
event.target.onerror = null
|
return
|
}
|
|
// 设置默认占位图
|
if (event.target) {
|
event.target.src = placeholderImage
|
}
|
}
|
|
/**
|
* 获取完整图片路径
|
*/
|
export function getFullImagePath(imagePath, projectPath) {
|
if (!imagePath || !projectPath) {
|
return ""
|
}
|
// 如果已经是绝对路径,直接返回
|
if (imagePath.startsWith('/')) {
|
return imagePath
|
}
|
return `${projectPath}/${imagePath}`
|
}
|
|
/**
|
* 获取图片的拆分分配类型(用于tooltip)
|
*/
|
export function getImageSplitTypeForTooltip(image, selectedSplit) {
|
if (!image || !selectedSplit) {
|
return "未选择拆分"
|
}
|
|
const assignments = selectedSplit.assignments || {}
|
const splitType = assignments[image.id]
|
|
if (!splitType) {
|
return "未分配"
|
}
|
|
switch (splitType) {
|
case "train":
|
return "训练集"
|
case "val":
|
return "验证集"
|
case "test":
|
return "测试集"
|
default:
|
return "未分配"
|
}
|
}
|
|
/**
|
* 获取图片的所有类别信息(用于显示类别标签)
|
*/
|
export function getImageCategories(image, projectTypes) {
|
if (!image?.annotations || image.annotations.length === 0) {
|
return []
|
}
|
if (!projectTypes || projectTypes.length === 0) {
|
return []
|
}
|
|
// 收集所有标注的类别ID(去重)
|
const categoryIds = new Set()
|
image.annotations.forEach(ann => {
|
if (ann.categoryId !== undefined && ann.categoryId !== null) {
|
categoryIds.add(ann.categoryId)
|
}
|
})
|
|
// 从项目类别中查找对应的类别信息
|
const categories = []
|
categoryIds.forEach(categoryId => {
|
const category = projectTypes.find(t => {
|
// 类型转换以处理可能的字符串和数字比较
|
return t.key === categoryId || String(t.key) === String(categoryId)
|
})
|
if (category) {
|
categories.push(category)
|
}
|
})
|
|
return categories
|
}
|
|
/**
|
* 获取项目显示名称,对已删除项目添加标记
|
*/
|
export function getProjectDisplayName(project) {
|
const baseName = project.project?.name || project.name || "未命名项目"
|
if (project.status === "removed" || project.exists === false) {
|
return `${baseName} (已删除)`
|
}
|
return baseName
|
}
|
|
/**
|
* 计算多边形面积
|
* @param {Array} points - 多边形顶点数组
|
* @returns {number} 面积
|
*/
|
export function calculatePolygonArea(points) {
|
if (!points || points.length < 3) return 0;
|
|
let area = 0;
|
for (let i = 0; i < points.length; i++) {
|
const j = (i + 1) % points.length;
|
area += points[i].x * points[j].y;
|
area -= points[j].x * points[i].y;
|
}
|
|
return Math.abs(area / 2);
|
}
|
|
/**
|
* 清理重复图像数据和冗余字段
|
*/
|
export async function cleanDuplicateImages(images) {
|
if (!images) return { images: [], hasChanges: false }
|
|
const uniqueImages = []
|
const seenIds = new Set()
|
const seenPaths = new Set()
|
let hasChanges = false
|
|
images.forEach((img) => {
|
// 清理重复的image字段(如果与path相同)
|
let cleanedImg = { ...img }
|
if (
|
cleanedImg.image &&
|
cleanedImg.path &&
|
cleanedImg.image === cleanedImg.path
|
) {
|
delete cleanedImg.image // 删除重复的字段
|
hasChanges = true
|
console.log(`[ImageHelper] 清理重复字段: ${img.name}`)
|
}
|
|
// 确保必要字段存在
|
if (!cleanedImg.annotations) {
|
cleanedImg.annotations = []
|
hasChanges = true
|
}
|
|
// 检查重复图像
|
if (!seenIds.has(img.id) && !seenPaths.has(img.path)) {
|
uniqueImages.push(cleanedImg)
|
seenIds.add(img.id)
|
seenPaths.add(img.path)
|
} else {
|
console.log(`[ImageHelper] 移除重复图像: ${img.name}`)
|
hasChanges = true
|
}
|
})
|
|
return {
|
images: uniqueImages,
|
hasChanges: hasChanges || uniqueImages.length !== images.length
|
}
|
}
|