mirror of
https://github.com/azaion/ui.git
synced 2026-04-22 09:16:35 +00:00
add type to detections
This commit is contained in:
@@ -8,6 +8,7 @@ import * as AnnotationService from '../../services/AnnotationService';
|
||||
import AnnotationControls from '../AnnotationControls/AnnotationControls';
|
||||
import saveAnnotation from '../../services/DataHandler';
|
||||
import './AnnotationMain.css';
|
||||
import { detectionTypes } from '../../constants/detectionTypes';
|
||||
|
||||
function AnnotationMain() {
|
||||
const [files, setFiles] = useState([]);
|
||||
@@ -21,6 +22,7 @@ function AnnotationMain() {
|
||||
const [videoWidth, setVideoWidth] = useState(640);
|
||||
const [videoHeight, setVideoHeight] = useState(480);
|
||||
const [errorMessage, setErrorMessage] = useState("");
|
||||
const [detectionType, setDetectionType] = useState(detectionTypes.day)
|
||||
|
||||
const videoRef = useRef(null);
|
||||
const containerRef = useRef(null);
|
||||
@@ -71,7 +73,8 @@ function AnnotationMain() {
|
||||
const imageData = AnnotationService.createAnnotationImage(
|
||||
videoRef,
|
||||
detections,
|
||||
safeContainerRef
|
||||
safeContainerRef,
|
||||
detectionType
|
||||
);
|
||||
|
||||
if (imageData) {
|
||||
@@ -186,7 +189,11 @@ function AnnotationMain() {
|
||||
onDropNewFiles={handleDropNewFiles}
|
||||
/>
|
||||
|
||||
<DetectionClassList onClassSelect={handleClassSelect} />
|
||||
<DetectionClassList
|
||||
onClassSelect={handleClassSelect}
|
||||
detectionType={detectionType}
|
||||
setDetectionType={setDetectionType}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='player-wrapper' >
|
||||
@@ -214,6 +221,7 @@ function AnnotationMain() {
|
||||
onDetectionsChange={handleDetectionsChange}
|
||||
onSelectionChange={handleSelectionChange}
|
||||
detectionClass={selectedClass}
|
||||
detectionType={detectionType}
|
||||
/>
|
||||
</VideoPlayer>
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,8 @@ function CanvasEditor({
|
||||
onDetectionsChange,
|
||||
onSelectionChange,
|
||||
children,
|
||||
detectionClass
|
||||
detectionClass,
|
||||
detectionType
|
||||
}) {
|
||||
const containerRef = useRef(null);
|
||||
const [currentDetection, setCurrentDetection] = useState(initialCurrentDetection);
|
||||
@@ -258,6 +259,7 @@ function CanvasEditor({
|
||||
onDetectionMouseDown={handleDetectionMouseDown}
|
||||
currentDetection={currentDetection}
|
||||
onResize={handleResize}
|
||||
detectionType={detectionType}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import { detectionTypes } from '../constants/detectionTypes';
|
||||
|
||||
function Detection({ detection, isSelected, onDetectionMouseDown, onResize }) {
|
||||
function Detection({ detection, isSelected, onDetectionMouseDown, onResize, detectionType }) {
|
||||
if (!detection || !detection.class) {
|
||||
return null;
|
||||
}
|
||||
@@ -13,10 +14,6 @@ function Detection({ detection, isSelected, onDetectionMouseDown, onResize }) {
|
||||
}
|
||||
|
||||
// Use startsWith to correctly handle RGBA and hex colors
|
||||
const backgroundColor = color.startsWith('rgba')
|
||||
? color.replace(/rgba\((\d+),\s*(\d+),\s*(\d+),\s*[\d.]+\)/, 'rgba($1, $2, $3, 0.4)')
|
||||
: color.replace(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/, 'rgba($1, $2, $3, 0.4)');
|
||||
|
||||
const borderColor = color.startsWith('rgba')
|
||||
? color.replace(/rgba\((\d+),\s*(\d+),\s*(\d+),\s*[\d.]+\)/, 'rgba($1, $2, $3, 1)')
|
||||
: color;
|
||||
@@ -40,7 +37,6 @@ function Detection({ detection, isSelected, onDetectionMouseDown, onResize }) {
|
||||
top: `${detection.y1}px`,
|
||||
width: `${detection.x2 - detection.x1}px`,
|
||||
height: `${detection.y2 - detection.y1}px`,
|
||||
backgroundColor: backgroundColor,
|
||||
border: `2px solid ${borderColor}`,
|
||||
boxSizing: 'border-box',
|
||||
cursor: isSelected ? 'move' : 'default',
|
||||
@@ -50,7 +46,7 @@ function Detection({ detection, isSelected, onDetectionMouseDown, onResize }) {
|
||||
|
||||
if (isSelected) {
|
||||
style.border = `3px solid black`;
|
||||
style.boxShadow = `0 0 4px 2px ${borderColor}`;
|
||||
style.boxShadow = `0 0 4px 4px ${borderColor}`;
|
||||
}
|
||||
|
||||
const handleMouseDown = (e) => {
|
||||
@@ -92,7 +88,7 @@ function Detection({ detection, isSelected, onDetectionMouseDown, onResize }) {
|
||||
textShadow: '1px 1px 2px black',
|
||||
pointerEvents: 'none'
|
||||
}}>
|
||||
{detection.class.Name}
|
||||
{detection.class.Name} {detectionType !== detectionTypes.day && '(' + detectionType + ')'}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -22,3 +22,35 @@
|
||||
margin-bottom: 2px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.detection-type-group {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
gap: 5%;
|
||||
padding: 10px 12px;
|
||||
}
|
||||
|
||||
.detection-type-btn {
|
||||
width: 25%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 18px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.detection-type-btn:hover {
|
||||
background: #d6eed5;
|
||||
}
|
||||
|
||||
.active-type {
|
||||
color: white;
|
||||
background: black;
|
||||
}
|
||||
|
||||
.active-type:hover {
|
||||
cursor: default;
|
||||
background: black;
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import DetectionClass from '../../models/DetectionClass';
|
||||
import './DetectionClassList.css';
|
||||
import { MdOutlineNightlightRound, MdOutlineWbSunny } from "react-icons/md";
|
||||
import { FaRegSnowflake } from 'react-icons/fa';
|
||||
import { detectionTypes } from '../../constants/detectionTypes';
|
||||
|
||||
function DetectionClassList({ onClassSelect }) {
|
||||
function DetectionClassList({ onClassSelect, detectionType, setDetectionType }) {
|
||||
const [detectionClasses, setDetectionClasses] = useState([]);
|
||||
const [selectedClass, setSelectedClass] = useState(null);
|
||||
|
||||
@@ -83,6 +86,10 @@ function DetectionClassList({ onClassSelect }) {
|
||||
onClassSelect && onClassSelect(cls);
|
||||
};
|
||||
|
||||
const handleTypeClick = (type) => {
|
||||
setDetectionType(type);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='class-list'>
|
||||
<h3 className='menu-title'>Classes</h3>
|
||||
@@ -107,6 +114,29 @@ function DetectionClassList({ onClassSelect }) {
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
|
||||
<div className='detection-type-group'>
|
||||
<button className={detectionType == detectionTypes.day
|
||||
? 'detection-type-btn active-type'
|
||||
: 'detection-type-btn'} title='День'
|
||||
onClick={() => handleTypeClick(detectionTypes.day)}>
|
||||
<MdOutlineWbSunny />
|
||||
</button>
|
||||
|
||||
<button className={detectionType == detectionTypes.night
|
||||
? 'detection-type-btn active-type'
|
||||
: 'detection-type-btn'} title='Ніч'
|
||||
onClick={() => handleTypeClick(detectionTypes.night)}>
|
||||
<MdOutlineNightlightRound />
|
||||
</button>
|
||||
|
||||
<button className={detectionType == detectionTypes.winter
|
||||
? 'detection-type-btn active-type'
|
||||
: 'detection-type-btn'} title='Зима'
|
||||
onClick={() => handleTypeClick(detectionTypes.winter)}>
|
||||
<FaRegSnowflake />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import React from 'react';
|
||||
import Detection from './Detection';
|
||||
|
||||
function DetectionContainer({ detections, selectedDetectionIndices, onDetectionMouseDown, currentDetection, onResize }) {
|
||||
function DetectionContainer({ detections, selectedDetectionIndices, onDetectionMouseDown, currentDetection, onResize, detectionType }) {
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -13,6 +13,7 @@ function DetectionContainer({ detections, selectedDetectionIndices, onDetectionM
|
||||
isSelected={selectedDetectionIndices.includes(index)}
|
||||
onDetectionMouseDown={(e) => onDetectionMouseDown(e, index)}
|
||||
onResize={(e, position) => onResize(e, index, position)}
|
||||
detectionType={detectionType}
|
||||
/>
|
||||
))}
|
||||
{currentDetection && (
|
||||
@@ -21,6 +22,7 @@ function DetectionContainer({ detections, selectedDetectionIndices, onDetectionM
|
||||
isSelected={false}
|
||||
onDetectionMouseDown={() => {}} // No-op handler for the current detection
|
||||
onResize={() => {}} // No-op handler for the current detection
|
||||
detectionType={detectionType}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
export const detectionTypes = {
|
||||
day: 'day',
|
||||
night: 'night',
|
||||
winter: 'winter'
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
import { detectionTypes } from "../constants/detectionTypes";
|
||||
|
||||
export const calculateRelativeCoordinates = (e, containerRef) => {
|
||||
if (!containerRef.current) return { x: 0, y: 0 };
|
||||
const containerRect = containerRef.current.getBoundingClientRect();
|
||||
@@ -13,7 +15,7 @@ export const isMouseOverDetection = (x, y, detection, containerRef) => {
|
||||
return relativeX >= detection.x1 && relativeX <= detection.x2 && relativeY >= detection.y1 && relativeY <= detection.y2;
|
||||
};
|
||||
|
||||
export const createAnnotationImage = (videoRef, detections, containerRef) => {
|
||||
export const createAnnotationImage = (videoRef, detections, containerRef, detectionType) => {
|
||||
if (!videoRef?.current || !containerRef?.current) {
|
||||
console.warn("Missing video or container reference");
|
||||
return null;
|
||||
@@ -39,17 +41,12 @@ export const createAnnotationImage = (videoRef, detections, containerRef) => {
|
||||
detections.forEach(detection => {
|
||||
if (!detection?.class) return;
|
||||
|
||||
// Ensure proper opacity for background - consistently using 0.4 opacity
|
||||
const bgColor = detection.class.Color?.startsWith('rgba')
|
||||
? detection.class.Color.replace(/rgba\((\d+),\s*(\d+),\s*(\d+),\s*[\d.]+\)/, 'rgba($1, $2, $3, 0.4)')
|
||||
: detection.class.Color?.replace(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/, 'rgba($1, $2, $3, 0.4)') || 'rgba(255, 0, 0, 0.4)';
|
||||
|
||||
// Ensure full opacity for border
|
||||
const borderColor = detection.class.Color?.startsWith('rgba')
|
||||
? detection.class.Color.replace(/rgba\((\d+),\s*(\d+),\s*(\d+),\s*[\d.]+\)/, 'rgba($1, $2, $3, 1)')
|
||||
: detection.class.Color || 'rgba(255, 0, 0, 1)';
|
||||
|
||||
ctx.fillStyle = bgColor;
|
||||
ctx.fillStyle = 'rgba(255, 255, 255, 0)';
|
||||
ctx.strokeStyle = borderColor;
|
||||
|
||||
const x = Math.max(0, detection.x1 || 0) * detection.kw;
|
||||
@@ -63,7 +60,11 @@ export const createAnnotationImage = (videoRef, detections, containerRef) => {
|
||||
|
||||
ctx.fillStyle = 'white';
|
||||
ctx.font = '12px Arial';
|
||||
ctx.fillText(detection.class.Name || 'Unknown', x, y - 5);
|
||||
if (detectionType === detectionTypes.day){
|
||||
ctx.fillText(detection.class.Name || 'Unknown', x, y - 5);
|
||||
} else {
|
||||
ctx.fillText(`${detection.class.Name} (${detectionType}) `|| 'Unknown', x, y - 5);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user