mirror of
https://github.com/blakeblackshear/frigate.git
synced 2025-07-26 13:47:03 +02:00
Small Tweaks (#17652)
* Ensure that hailo uses correct labelmap * Make whole button clickable * Add weblate to readme * Update docs for HEIC * Fix explore chip icon logic * Sort regardless of case * Don't allow selection * Fix image uploading
This commit is contained in:
parent
664889d487
commit
e9787c5a88
12
README.md
12
README.md
@ -4,6 +4,10 @@
|
||||
|
||||
# Frigate - NVR With Realtime Object Detection for IP Cameras
|
||||
|
||||
<a href="https://hosted.weblate.org/engage/frigate-nvr/">
|
||||
<img src="https://hosted.weblate.org/widget/frigate-nvr/language-badge.svg" alt="Translation status" />
|
||||
</a>
|
||||
|
||||
\[English\] | [简体中文](https://github.com/blakeblackshear/frigate/blob/dev/README_CN.md)
|
||||
|
||||
A complete and local NVR designed for [Home Assistant](https://www.home-assistant.io) with AI object detection. Uses OpenCV and Tensorflow to perform realtime object detection locally for IP cameras.
|
||||
@ -32,21 +36,25 @@ If you would like to make a donation to support development, please use [Github
|
||||
## Screenshots
|
||||
|
||||
### Live dashboard
|
||||
|
||||
<div>
|
||||
<img width="800" alt="Live dashboard" src="https://github.com/blakeblackshear/frigate/assets/569905/5e713cb9-9db5-41dc-947a-6937c3bc376e">
|
||||
</div>
|
||||
|
||||
### Streamlined review workflow
|
||||
|
||||
<div>
|
||||
<img width="800" alt="Streamlined review workflow" src="https://github.com/blakeblackshear/frigate/assets/569905/6fed96e8-3b18-40e5-9ddc-31e6f3c9f2ff">
|
||||
</div>
|
||||
|
||||
### Multi-camera scrubbing
|
||||
|
||||
<div>
|
||||
<img width="800" alt="Multi-camera scrubbing" src="https://github.com/blakeblackshear/frigate/assets/569905/d6788a15-0eeb-4427-a8d4-80b93cae3d74">
|
||||
</div>
|
||||
|
||||
### Built-in mask and zone editor
|
||||
|
||||
<div>
|
||||
<img width="800" alt="Multi-camera scrubbing" src="https://github.com/blakeblackshear/frigate/assets/569905/d7885fc3-bfe6-452f-b7d0-d957cb3e31f5">
|
||||
</div>
|
||||
@ -54,3 +62,7 @@ If you would like to make a donation to support development, please use [Github
|
||||
## Translations
|
||||
|
||||
We use [Weblate](https://hosted.weblate.org/projects/frigate-nvr/) to support language translations. Contributions are always welcome.
|
||||
|
||||
<a href="https://hosted.weblate.org/engage/frigate-nvr/">
|
||||
<img src="https://hosted.weblate.org/widget/frigate-nvr/multi-auto.svg" alt="Translation status" />
|
||||
</a>
|
||||
|
@ -136,3 +136,7 @@ Face recognition does not run on the recording stream, this would be suboptimal
|
||||
1. The latency of accessing the recordings means the notifications would not include the names of recognized people because recognition would not complete until after.
|
||||
2. The embedding models used run on a set image size, so larger images will be scaled down to match this anyway.
|
||||
3. Motion clarity is much more important than extra pixels, over-compression and motion blur are much more detrimental to results than resolution.
|
||||
|
||||
### I get an unknown error when taking a photo directly with my iPhone
|
||||
|
||||
By default iOS devices will use HEIC (High Efficiency Image Container) for images, but this format is not supported for uploads. Choosing `large` as the format instead of `original` will use JPG which will work correctly.
|
||||
|
@ -163,6 +163,7 @@ model:
|
||||
input_pixel_format: rgb
|
||||
input_dtype: int
|
||||
model_type: yolo-generic
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
|
||||
# The detector automatically selects the default model based on your hardware:
|
||||
# - For Hailo-8 hardware: YOLOv6n (default: yolov6n.hef)
|
||||
@ -219,6 +220,7 @@ model:
|
||||
input_pixel_format: rgb
|
||||
input_dtype: int
|
||||
model_type: yolo-generic
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
# Optional: Specify a local model path.
|
||||
# path: /config/model_cache/hailo/custom_model.hef
|
||||
#
|
||||
|
@ -44,23 +44,31 @@ export default function SearchThumbnail({
|
||||
[searchResult, onClick],
|
||||
);
|
||||
|
||||
const objectLabel = useMemo(() => {
|
||||
if (
|
||||
!config ||
|
||||
!searchResult.sub_label ||
|
||||
!config.model.attributes_map[searchResult.label]
|
||||
) {
|
||||
return searchResult.label;
|
||||
}
|
||||
|
||||
return `${searchResult.label}-verified`;
|
||||
}, [config, searchResult]);
|
||||
|
||||
const hasRecognizedPlate = useMemo(
|
||||
() => (searchResult.data.recognized_license_plate?.length || 0) > 0,
|
||||
[searchResult],
|
||||
);
|
||||
|
||||
const objectLabel = useMemo(() => {
|
||||
if (!config) {
|
||||
return searchResult.label;
|
||||
}
|
||||
|
||||
if (!searchResult.sub_label) {
|
||||
return `${searchResult.label}${hasRecognizedPlate ? "-plate" : ""}`;
|
||||
}
|
||||
|
||||
if (
|
||||
config.model.attributes_map[searchResult.label]?.includes(
|
||||
searchResult.sub_label,
|
||||
)
|
||||
) {
|
||||
return searchResult.sub_label;
|
||||
}
|
||||
|
||||
return `${searchResult.label}-verified`;
|
||||
}, [config, hasRecognizedPlate, searchResult]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="relative size-full cursor-pointer"
|
||||
@ -102,10 +110,7 @@ export default function SearchThumbnail({
|
||||
className={`z-0 flex items-center justify-between gap-1 space-x-1 bg-gray-500 bg-gradient-to-br from-gray-400 to-gray-500 text-xs`}
|
||||
onClick={() => onClick(searchResult, false, true)}
|
||||
>
|
||||
{getIconForLabel(
|
||||
`${objectLabel}${hasRecognizedPlate ? "-plate" : ""}`,
|
||||
"size-3 text-white",
|
||||
)}
|
||||
{getIconForLabel(objectLabel, "size-3 text-white")}
|
||||
{Math.round(
|
||||
(searchResult.data.score ??
|
||||
searchResult.data.top_score ??
|
||||
|
@ -32,7 +32,11 @@ export default function ImageEntry({
|
||||
const [preview, setPreview] = useState<string | null>(null);
|
||||
|
||||
const formSchema = z.object({
|
||||
file: z.instanceof(File, { message: "Please select an image file." }),
|
||||
file: z
|
||||
.instanceof(File, { message: t("imageEntry.validation.selectImage") })
|
||||
.refine((file) =>
|
||||
accept["image/*"].includes(`.${file.type.split("/")[1]}`),
|
||||
),
|
||||
});
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
|
@ -462,6 +462,13 @@ export function SubFilterContent({
|
||||
setSubLabels,
|
||||
}: SubFilterContentProps) {
|
||||
const { t } = useTranslation(["components/filter"]);
|
||||
const sortedSubLabels = useMemo(
|
||||
() =>
|
||||
[...allSubLabels].sort((a, b) =>
|
||||
a.toLowerCase().localeCompare(b.toLowerCase()),
|
||||
),
|
||||
[allSubLabels],
|
||||
);
|
||||
return (
|
||||
<div className="overflow-x-hidden">
|
||||
<DropdownMenuSeparator className="mb-3" />
|
||||
@ -482,7 +489,7 @@ export function SubFilterContent({
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-2.5 flex flex-col gap-2.5">
|
||||
{allSubLabels.map((item) => (
|
||||
{sortedSubLabels.map((item) => (
|
||||
<FilterSwitch
|
||||
key={item}
|
||||
label={item.replaceAll("_", " ")}
|
||||
|
@ -690,7 +690,7 @@ function FaceAttemptGroup({
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-row justify-between">
|
||||
<div className="capitalize">
|
||||
<div className="select-none capitalize">
|
||||
Person
|
||||
{event?.sub_label
|
||||
? `: ${event.sub_label} (${Math.round((event.data.sub_label_score || 0) * 100)}%)`
|
||||
@ -848,7 +848,7 @@ function FaceAttempt({
|
||||
: "outline-transparent duration-500",
|
||||
)}
|
||||
>
|
||||
<div className="relative w-full overflow-hidden rounded-lg *:text-card-foreground">
|
||||
<div className="relative w-full select-none overflow-hidden rounded-lg *:text-card-foreground">
|
||||
<img
|
||||
ref={imgRef}
|
||||
className={cn("size-44", isMobile && "w-full")}
|
||||
@ -866,7 +866,7 @@ function FaceAttempt({
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-2">
|
||||
<div className="select-none p-2">
|
||||
<div className="flex w-full flex-row items-center justify-between gap-2">
|
||||
<div className="flex flex-col items-start text-xs text-primary-variant">
|
||||
<div className="capitalize">{data.name}</div>
|
||||
|
@ -1479,17 +1479,17 @@ function FrigateCameraFeatures({
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<div
|
||||
className="flex cursor-pointer flex-col gap-1"
|
||||
onClick={() =>
|
||||
navigate(`/settings?page=debug&camera=${camera.name}`)
|
||||
}
|
||||
>
|
||||
<div className="flex items-center justify-between text-sm font-medium leading-none">
|
||||
{t("streaming.debugView", {
|
||||
ns: "components/dialog",
|
||||
})}
|
||||
<LuExternalLink
|
||||
onClick={() =>
|
||||
navigate(`/settings?page=debug&camera=${camera.name}`)
|
||||
}
|
||||
className="ml-2 inline-flex size-5 cursor-pointer"
|
||||
/>
|
||||
<LuExternalLink className="ml-2 inline-flex size-5" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user