mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-05-07 05:55:27 +03:00
Compare commits
3 Commits
603d9f7d27
...
ae0c1ca941
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae0c1ca941 | ||
|
|
29a747ca83 | ||
|
|
2d0ad54661 |
@ -19,11 +19,6 @@ from frigate.util.object import calculate_region
|
|||||||
from ..types import DataProcessorMetrics
|
from ..types import DataProcessorMetrics
|
||||||
from .api import RealTimeProcessorApi
|
from .api import RealTimeProcessorApi
|
||||||
|
|
||||||
try:
|
|
||||||
from tflite_runtime.interpreter import Interpreter
|
|
||||||
except ModuleNotFoundError:
|
|
||||||
from tensorflow.lite.python.interpreter import Interpreter
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@ -35,7 +30,7 @@ class BirdRealTimeProcessor(RealTimeProcessorApi):
|
|||||||
metrics: DataProcessorMetrics,
|
metrics: DataProcessorMetrics,
|
||||||
):
|
):
|
||||||
super().__init__(config, metrics)
|
super().__init__(config, metrics)
|
||||||
self.interpreter: Interpreter = None
|
self.interpreter: Any | None = None
|
||||||
self.sub_label_publisher = sub_label_publisher
|
self.sub_label_publisher = sub_label_publisher
|
||||||
self.tensor_input_details: dict[str, Any] = None
|
self.tensor_input_details: dict[str, Any] = None
|
||||||
self.tensor_output_details: dict[str, Any] = None
|
self.tensor_output_details: dict[str, Any] = None
|
||||||
@ -82,6 +77,11 @@ class BirdRealTimeProcessor(RealTimeProcessorApi):
|
|||||||
|
|
||||||
@redirect_output_to_logger(logger, logging.DEBUG)
|
@redirect_output_to_logger(logger, logging.DEBUG)
|
||||||
def __build_detector(self) -> None:
|
def __build_detector(self) -> None:
|
||||||
|
try:
|
||||||
|
from tflite_runtime.interpreter import Interpreter
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
from tensorflow.lite.python.interpreter import Interpreter
|
||||||
|
|
||||||
self.interpreter = Interpreter(
|
self.interpreter = Interpreter(
|
||||||
model_path=os.path.join(MODEL_CACHE_DIR, "bird/bird.tflite"),
|
model_path=os.path.join(MODEL_CACHE_DIR, "bird/bird.tflite"),
|
||||||
num_threads=2,
|
num_threads=2,
|
||||||
|
|||||||
@ -29,11 +29,6 @@ from frigate.util.object import box_overlaps, calculate_region
|
|||||||
from ..types import DataProcessorMetrics
|
from ..types import DataProcessorMetrics
|
||||||
from .api import RealTimeProcessorApi
|
from .api import RealTimeProcessorApi
|
||||||
|
|
||||||
try:
|
|
||||||
from tflite_runtime.interpreter import Interpreter
|
|
||||||
except ModuleNotFoundError:
|
|
||||||
from tensorflow.lite.python.interpreter import Interpreter
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
MAX_OBJECT_CLASSIFICATIONS = 16
|
MAX_OBJECT_CLASSIFICATIONS = 16
|
||||||
@ -52,7 +47,7 @@ class CustomStateClassificationProcessor(RealTimeProcessorApi):
|
|||||||
self.requestor = requestor
|
self.requestor = requestor
|
||||||
self.model_dir = os.path.join(MODEL_CACHE_DIR, self.model_config.name)
|
self.model_dir = os.path.join(MODEL_CACHE_DIR, self.model_config.name)
|
||||||
self.train_dir = os.path.join(CLIPS_DIR, self.model_config.name, "train")
|
self.train_dir = os.path.join(CLIPS_DIR, self.model_config.name, "train")
|
||||||
self.interpreter: Interpreter | None = None
|
self.interpreter: Any | None = None
|
||||||
self.tensor_input_details: dict[str, Any] | None = None
|
self.tensor_input_details: dict[str, Any] | None = None
|
||||||
self.tensor_output_details: dict[str, Any] | None = None
|
self.tensor_output_details: dict[str, Any] | None = None
|
||||||
self.labelmap: dict[int, str] = {}
|
self.labelmap: dict[int, str] = {}
|
||||||
@ -74,6 +69,11 @@ class CustomStateClassificationProcessor(RealTimeProcessorApi):
|
|||||||
|
|
||||||
@redirect_output_to_logger(logger, logging.DEBUG)
|
@redirect_output_to_logger(logger, logging.DEBUG)
|
||||||
def __build_detector(self) -> None:
|
def __build_detector(self) -> None:
|
||||||
|
try:
|
||||||
|
from tflite_runtime.interpreter import Interpreter
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
from tensorflow.lite.python.interpreter import Interpreter
|
||||||
|
|
||||||
model_path = os.path.join(self.model_dir, "model.tflite")
|
model_path = os.path.join(self.model_dir, "model.tflite")
|
||||||
labelmap_path = os.path.join(self.model_dir, "labelmap.txt")
|
labelmap_path = os.path.join(self.model_dir, "labelmap.txt")
|
||||||
|
|
||||||
@ -345,7 +345,7 @@ class CustomObjectClassificationProcessor(RealTimeProcessorApi):
|
|||||||
self.model_config = model_config
|
self.model_config = model_config
|
||||||
self.model_dir = os.path.join(MODEL_CACHE_DIR, self.model_config.name)
|
self.model_dir = os.path.join(MODEL_CACHE_DIR, self.model_config.name)
|
||||||
self.train_dir = os.path.join(CLIPS_DIR, self.model_config.name, "train")
|
self.train_dir = os.path.join(CLIPS_DIR, self.model_config.name, "train")
|
||||||
self.interpreter: Interpreter | None = None
|
self.interpreter: Any | None = None
|
||||||
self.sub_label_publisher = sub_label_publisher
|
self.sub_label_publisher = sub_label_publisher
|
||||||
self.requestor = requestor
|
self.requestor = requestor
|
||||||
self.tensor_input_details: dict[str, Any] | None = None
|
self.tensor_input_details: dict[str, Any] | None = None
|
||||||
@ -368,6 +368,11 @@ class CustomObjectClassificationProcessor(RealTimeProcessorApi):
|
|||||||
|
|
||||||
@redirect_output_to_logger(logger, logging.DEBUG)
|
@redirect_output_to_logger(logger, logging.DEBUG)
|
||||||
def __build_detector(self) -> None:
|
def __build_detector(self) -> None:
|
||||||
|
try:
|
||||||
|
from tflite_runtime.interpreter import Interpreter
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
from tensorflow.lite.python.interpreter import Interpreter
|
||||||
|
|
||||||
model_path = os.path.join(self.model_dir, "model.tflite")
|
model_path = os.path.join(self.model_dir, "model.tflite")
|
||||||
labelmap_path = os.path.join(self.model_dir, "labelmap.txt")
|
labelmap_path = os.path.join(self.model_dir, "labelmap.txt")
|
||||||
|
|
||||||
|
|||||||
@ -146,6 +146,29 @@ class EmbeddingMaintainer(threading.Thread):
|
|||||||
self.detected_license_plates: dict[str, dict[str, Any]] = {}
|
self.detected_license_plates: dict[str, dict[str, Any]] = {}
|
||||||
self.genai_client = get_genai_client(config)
|
self.genai_client = get_genai_client(config)
|
||||||
|
|
||||||
|
# Pre-import TensorFlow/tflite on main thread to avoid atexit registration issues
|
||||||
|
# when importing from worker threads later (e.g., during dynamic config updates)
|
||||||
|
if (
|
||||||
|
self.config.classification.bird.enabled
|
||||||
|
or len(self.config.classification.custom) > 0
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
from tflite_runtime.interpreter import Interpreter # noqa: F401
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
try:
|
||||||
|
from tensorflow.lite.python.interpreter import ( # noqa: F401
|
||||||
|
Interpreter,
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.debug(
|
||||||
|
"Pre-imported TensorFlow Interpreter on main thread for classification models"
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(
|
||||||
|
f"Failed to pre-import TensorFlow Interpreter: {e}. "
|
||||||
|
"Classification models may fail to load if added dynamically."
|
||||||
|
)
|
||||||
|
|
||||||
# model runners to share between realtime and post processors
|
# model runners to share between realtime and post processors
|
||||||
if self.config.lpr.enabled:
|
if self.config.lpr.enabled:
|
||||||
lpr_model_runner = LicensePlateModelRunner(
|
lpr_model_runner = LicensePlateModelRunner(
|
||||||
|
|||||||
@ -141,7 +141,37 @@ export default function Step3ChooseExamples({
|
|||||||
);
|
);
|
||||||
await Promise.all(categorizePromises);
|
await Promise.all(categorizePromises);
|
||||||
|
|
||||||
// Step 2.5: Create empty folders for classes that don't have any images
|
// Step 2.5: Delete any unselected images from train folder
|
||||||
|
// For state models, all images must be classified, so unselected images should be removed
|
||||||
|
// For object models, unselected images are assigned to "none" so they're already categorized
|
||||||
|
if (step1Data.modelType === "state") {
|
||||||
|
try {
|
||||||
|
// Fetch current train images to see what's left after categorization
|
||||||
|
const trainImagesResponse = await axios.get<string[]>(
|
||||||
|
`/classification/${step1Data.modelName}/train`,
|
||||||
|
);
|
||||||
|
const remainingTrainImages = trainImagesResponse.data || [];
|
||||||
|
|
||||||
|
const categorizedImageNames = new Set(Object.keys(classifications));
|
||||||
|
const unselectedImages = remainingTrainImages.filter(
|
||||||
|
(imageName) => !categorizedImageNames.has(imageName),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (unselectedImages.length > 0) {
|
||||||
|
await axios.post(
|
||||||
|
`/classification/${step1Data.modelName}/train/delete`,
|
||||||
|
{
|
||||||
|
ids: unselectedImages,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// Silently fail - unselected images will remain but won't cause issues
|
||||||
|
// since the frontend filters out images that don't match expected format
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2.6: Create empty folders for classes that don't have any images
|
||||||
// This ensures all classes are available in the dataset view later
|
// This ensures all classes are available in the dataset view later
|
||||||
const classesWithImages = new Set(
|
const classesWithImages = new Set(
|
||||||
Object.values(classifications).filter((c) => c && c !== "none"),
|
Object.values(classifications).filter((c) => c && c !== "none"),
|
||||||
|
|||||||
@ -866,6 +866,12 @@ function TrainGrid({
|
|||||||
};
|
};
|
||||||
})
|
})
|
||||||
.filter((data) => {
|
.filter((data) => {
|
||||||
|
// Ignore images that don't match the expected format (event-camera-timestamp-state-score.webp)
|
||||||
|
// Expected format has 5 parts when split by "-", and score should be a valid number
|
||||||
|
if (data.score === undefined || isNaN(data.score) || !data.name) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!trainFilter) {
|
if (!trainFilter) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user