mirror of
				https://github.com/blakeblackshear/frigate.git
				synced 2025-10-27 10:52:11 +01: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