add type to detections

This commit is contained in:
Armen Rohalov
2025-05-06 20:03:09 +03:00
parent 1e1e8ae97d
commit a3604f6d36
8 changed files with 97 additions and 21 deletions
@@ -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>
+3 -1
View File
@@ -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>
+4 -8
View File
@@ -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>
);
}
+3 -1
View File
@@ -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}
/>
)}
</>
+5
View File
@@ -0,0 +1,5 @@
export const detectionTypes = {
day: 'day',
night: 'night',
winter: 'winter'
}
+8 -7
View File
@@ -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';
if (detectionType === detectionTypes.day){
ctx.fillText(detection.class.Name || 'Unknown', x, y - 5);
} else {
ctx.fillText(`${detection.class.Name} (${detectionType}) `|| 'Unknown', x, y - 5);
}
});
}