Encourager FUNIX

La consultation du site est totalement libre et gratuite, sans publicités. Les dons sont néanmoins appréciés pour payer l'hébergement et encourager son auteur


Systèmes de videosurveillance - présentation de ZoneMinder

Systèmes de vidéosurveillance

Présentation de ZoneMinder

30 octobre 2025


Présentation

Cette section a pour objectif de vous présenter différents outils pour monter un système de vidéosurveillance basé sur Linux avec l'utilisation de caméras de surveillance indépendantes (IP ou Wifi), analogique, numérique ou de simples webcams, autrement appelé CCTV. Sont présentés dans cette section ZoneMinder, Frigate et motionplus, ils permettent tous d'intégrer un large panel de caméras, de faire de la détection automatique de mouvement et de créer des évènements, ils sont basés également sur un serveur web, permettant via un navigateur de les configurer, de visualiser en temps réel les caméras et de gérer les évènements, que ce soit sur un poste fixe ou sur un mobile. Zoneminder et Frigate sont bien plus évolués et dispose de fonction d'apprentissage automatique et de reconnaissance d'objet, contrairement à motionplus qui est un outil bien plus simple et moins lourd à mettre en œuvre. On pourra considérer également que ZoneMinder est bien plus usine à gaz que Frigate qui s’intègre dans home assistant.
Cette section est décomposée en plusieurs pages:

Installation de la dernière version stable

Zoneminder est considéré comme un des logiciels opensource de vidéosurveillance de référence. Le site officiel est https://zoneminder.com. On y récupère la dernier version qu'on décompresse en tapant

tar xvfz zoneminder-1.36.35.tar.gz

on installera d'abord les packages suivants

- lib64vlc-devel
- perl-Apache-Test-1.430.0-2.mga9.noarch
- perl-AppConfig-1.710.0-7.mga9.noarch
- perl-Archive-Zip-1.680.0-2.mga9.noarch
- perl-Astro-SunTime-0.60.0-5.mga9.noarch
- perl-BSD-Resource-1.291.100-10.mga9.x86_64
- perl-Class-Inspector-1.360.0-3.mga9.noarch
- perl-Class-Load-0.250.0-4.mga9.noarch
- perl-Class-Mix-0.6.0-5.mga9.noarch
- perl-Class-Singleton-1.600.0-2.mga9.noarch
- perl-Class-Std-0.13.0-6.mga9.noarch
- perl-Class-Std-Fast-0.0.8-14.mga9.noarch
- perl-Convert-BinHex-1.125.0-5.mga9.noarch
- perl-Crypt-Eksblowfish-0.9.0-23.mga9.x86_64
- perl-Crypt-Rijndael-1.160.0-4.mga9.x86_64
- perl-Data-Entropy-0.7.0-10.mga9.noarch
- perl-Data-Float-0.13.0-5.mga9.noarch
- perl-Data-Flow-1.20.0-10.mga9.noarch
- perl-Data-OptList-0.113.0-1.mga9.noarch
- perl-Data-UUID-1.227.0-1.mga9.x86_64
- perl-Date-Manip-6.900.0-1.mga9.noarch
- perl-DateTime-1.590.0-1.mga9.x86_64
- perl-DateTime-Locale-1.370.0-1.mga9.noarch
- perl-DateTime-TimeZone-2.600.0-1.mga9.noarch
- perl-DBD-mysql-4.50.0-8.mga9.x86_64
- perl-Device-SerialPort-1.40.0-26.mga9.x86_64
- perl-File-ShareDir-1.118.0-2.mga9.noarch
- perl-HTTP-Lite-2.440.0-6.mga9.noarch
- perl-IO-Interface-1.90.0-14.mga9.x86_64
- perl-IO-SessionData-1.30.0-9.mga9.noarch
- perl-IO-Socket-Multicast-1.120.0-26.mga9.x86_64
- perl-JSON-MaybeXS-1.4.4-1.mga9.noarch
- perl-Linux-Pid-0.40.0-24.mga9.x86_64
- perl-List-AllUtils-0.190.0-2.mga9.noarch
- perl-List-SomeUtils-0.590.0-1.mga9.noarch
- perl-List-UtilsBy-0.120.0-1.mga9.noarch
- perl-MIME-tools-5.510.0-1.mga9.noarch
- perl-Net-SFTP-Foreign-1.930.0-2.mga9.noarch
- perl-Number-Bytes-Human-0.110.0-5.mga9.noarch
- perl-Params-Classify-0.15.0-11.mga9.x86_64
- perl-Params-Util-1.102.0-4.mga9.x86_64
- perl-PHP-Serialization-0.340.0-11.mga9.noarch
- perl-Pod-POM-2.10.0-7.mga9.noarch
- perl-SOAP-Lite-1.270.0-3.mga9.noarch
- perl-SOAP-WSDL-3.4.0-3.mga9.noarch
- perl-Sub-Install-0.929.0-1.mga9.noarch
- perl-Sys-CPU-0.610.0-20.mga9.x86_64
- perl-Sys-MemInfo-0.990.0-13.mga9.x86_64
- perl-Sys-Mmap-0.200.0-6.mga9.x86_64
- perl-Task-Weaken-1.60.0-4.mga9.noarch
- perl-Template-Toolkit-3.101.0-1.mga9.x86_64
- perl-Time-ParseDate-2015.103.0-6.mga9.noarch
- perl-URI-Encode-1.1.1-4.mga9.noarch
- perl-X10-0.30.0-10c.mga9.noarch

On revient dans le répertoire zoneminder-1.36.35 dans lequel on tape successivement

mkdir build
cd build/
cd ..
git clone "https://github.com/ZoneMinder/ZoneMinder.git" zoneminder_release
cd zoneminder_release/
cp -Rf .git ..
cd ..
cd build/
git submodule update --init --recursive

et enfin la commande de configuration avec les paramétrages du nom du serveur MySQL (ZM_DB_HOST) en l’occurrence basé sur MariaDB, l'activation du service systemd (ZM_SYSTEMD), du propriétaire du process httpd (ZM_WEB_USER) et les chemins du répertoire de stockage des évènements (ZM_DIR_EVENTS), des exécutables cgi-bin (ZM_CGI_DIR), du prefix d'installation avec /usr et non /usr/local (CMAKE_INSTALL_PREFIX), du chemin du fichier de configuration (ZM_CONFIG_DIR), du chemin de recherche des modules perl (ZM_PERL_SEARCH_PATH) et des fichiers accessibles par navigateur (ZM_WEBDIR).
Pour mémoire il est nécessaire d'avoir un serveur Apache+PHP+MariaDB fonctionnel.

cmake .. -DMYSQLCLIENT_LIBRARIES=/usr/local/mysql/lib/libmysqlclient.so -DZM_DB_HOST=mariadb-serveur -DZM_WEB_USER=apache -DZM_DIR_EVENTS=/media/motion/events -DZM_CGIDIR=/usr/share/zoneminder/cgi-bin -DCMAKE_INSTALL_PREFIX=/usr -DZM_CONFIG_DIR=/etc/zm -DZM_CONFIG_SUBDIR=/etc/zm/conf.d -DZM_PERL_SEARCH_PATH=/usr/share/perl5/vendor_perl -DZM_SYSTEMD=ON -DZM_WEBDIR=/usr/share/zoneminder/www/

voilà le résultat

-- Detected compiler: /usr/bin/cc
-- Sendfile support: Linux/Solaris sendfile()
-- Building man pages: Yes (default)
-- Could NOT find LibJWT (missing: LIBJWT_LIBRARY)
-- Checking prototype MD5 for HAVE_MD5_OPENSSL - True
-- Using web user: apache
-- Using web group: apache
Building unit tests: No (default)
-- Optional libraries found: zlib cURL OpenSSL PCRE GCrypt AVFormat AVCodec AVDevice AVUtil SWScale SWResample libVLC
-- Optional libraries not found: LIBJWT libVNC
-- Running ZoneMinder configuration generator
Generating '/home/olivier/compilation/zoneminder-1.36.35/build/zm_config_defines.h'
Updating '/home/olivier/compilation/zoneminder-1.36.35/build/db/zm_create.sql'
-- ZoneMinder configuration generator completed successfully
-- Configuring done (0.4s)
-- Generating done (0.1s)
-- Build files have been written to: /home/olivier/compilation/zoneminder-1.36.35/build


on tape ensuite make puis en tant que root make install
j'ai eu beau joué avec la variable ZM_PERL_MM_PARMS il ne m'installait pas les modules perl au bon endroit, j'ai dû taper les commandes ci-dessous manuellement

cp -Rf /root/perl5/lib/perl5/WSDiscovery11 /usr/share/perl5/vendor_perl
cp -Rf /root/perl5/lib/perl5/WSDiscovery10 /usr/share/perl5/vendor_perl
cp -Rf /root/perl5/lib/perl5/WSNotification /usr/share/perl5/vendor_perl
cp -Rf /root/perl5/lib/perl5/ONVIF /usr/share/perl5/vendor_perl
cp -Rf /root/perl5/lib/perl5/WSNotification/ /usr/share/perl5/vendor_perl
cp -Rf /root/perl5/lib/perl5/ZoneMinder* /usr/share/perl5/vendor_perl
cp -Rf /root/perl5/lib/perl5/WSSecurity/ /usr/share/perl5/vendor_perl
cp -Rf /root/perl5/lib/perl5/WSDiscovery /usr/share/perl5/vendor_perl

Il faut commencer par créer une base de données mysql en tapant:

mariadb -u root -p < /usr/share/zoneminder/db/zm_create.sql

on vérifie si la base est bien créée, elle se nomme simplement zm et on crée un utilisateur privilégié zmuser sur la base zm avec le mot de passe zmpass qu'il faudra évidemment changer

mariadb -u root -p

voilà le résultat

Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 25
Server version: 11.4.2-MariaDB Source distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> show databases;
+---------------------+
| Database            |
+---------------------+
| MyMusic82           |
| MyMusic83           |
| MyVideos121         |
| MyVideos131         |
| digikam             |
| digikam_similarites |
| digikam_vignettes   |
| digikam_visages     |
| information_schema  |
| mysql               |
| performance_schema  |
| phpmyadmin          |
| roundcubemail       |
| spamassassin        |
| syncstorage_rs      |
| sys                 |
| tokenserver_rs      |
| zm                  |
+---------------------+
18 rows in set (0,096 sec)

MariaDB [(none)]> use mysql;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MariaDB [mysql]> CREATE USER 'zmuser' IDENTIFIED BY 'zmpass';
Query OK, 0 rows affected (0,087 sec)

MariaDB [mysql]> GRANT ALL ON zm.* TO 'zmuser'@'localhost';
Query OK, 0 rows affected (0,201 sec)

maintenant j'ai créé le fichier /usr/lib/systemd/system/zoneminder.service qui contiendra

[Unit]
Description=ZoneMinder CCTV recording and security system
After=network.target mariadb.service httpd.service
Requires=mariadb.service httpd.service

[Service]
User=apache
Type=forking
ExecStart=/usr/bin/zmpkg.pl start
ExecReload=/usr/bin/zmpkg.pl reload
ExecStop=/usr/bin/zmpkg.pl stop

[Install]
WantedBy=multi-user.target

Attention le user doit correspondre au propriétaire du processus Apache httpd. On active le service en tapant

systemctl enable zoneminder

[retour haut de la page]

Le fichier de configuration /etc/zm/zm.conf ressemble à ça

# ==========================================================================
#
# ZoneMinder Base Configuration
#
# ==========================================================================
#
# *** DO NOT EDIT THIS FILE ***
#
# To make custom changes to the variables below, create a new configuration
# file, with an extention of .conf, under the /etc/zm/conf.d
# folder, containing your desired modifications.
#

# Path to installed data directory, used mostly for finding DB upgrade scripts
ZM_PATH_DATA=/usr/share/zoneminder

# Path to ZoneMinder binaries
ZM_PATH_BIN=/usr/bin

# Path to ZoneMinder libraries (none at present, for future use)
ZM_PATH_LIB=/usr/lib64

# Path to ZoneMinder configuration (this file only at present)
ZM_PATH_CONF=/etc/zm

# Path to ZoneMinder web files
ZM_PATH_WEB=/usr/share/zoneminder/www

# Path to ZoneMinder cgi files
ZM_PATH_CGI=/usr/share/zoneminder/cgi-bin

# Username and group that web daemon (httpd/apache) runs as
# utilisateur et groupe propriétaire du daemon apache httpd
ZM_WEB_USER=apache
ZM_WEB_GROUP=apache

# ZoneMinder database type: so far only mysql is supported
ZM_DB_TYPE=mysql

# ZoneMinder database hostname or ip address and optionally port or unix socket
# Acceptable formats include hostname[:port], ip_address[:port], or
# localhost:/path/to/unix_socket
# le nom du serveur sur lequel tourne le serveur mariadb
ZM_DB_HOST=mariadb-serveur

# ZoneMinder database name
ZM_DB_NAME=zm

# ZoneMinder database user
ZM_DB_USER=zmuser

# ZoneMinder database password
# le mot de passe tel que défini dans mariadb
ZM_DB_PASS=zmpass

# SSL CA certificate for ZoneMinder database
ZM_DB_SSL_CA_CERT=

# SSL client key for ZoneMinder database
ZM_DB_SSL_CLIENT_KEY=

# SSL client cert for ZoneMinder database
ZM_DB_SSL_CLIENT_CERT=

# Do NOT set ZM_SERVER_HOST if you are not using Multi-Server
# You have been warned
#
# The name specified here must have a corresponding entry
# in the Servers tab under Options
ZM_SERVER_HOST=

Autre fichier /etc/zm/conf.d/01-system-paths.conf qui contiendra

# ==========================================================================
#
# ZoneMinder System Paths Configuration
#
# ==========================================================================
#
# This config file contains the variables previously found under Options -> Paths
#
# *** DO NOT EDIT THIS FILE ***
#
# To make custom changes to the variables below, create a new configuration
# file, with an extention of .conf, containing your desired modifications.
#

# Full path to the folder events are recorded to.
# The web account user must have full read/write permission to this folder.
# répertoire où les évènements sont enregistrés
# le détenteur du process httpd doit être proprio, c'est apache
ZM_DIR_EVENTS=/media/motion/events

# Foldername under the webroot where ZoneMinder looks for optional sound files
# to play when an alarm is detected.
ZM_DIR_SOUNDS=sounds

# Full path to the folder where exported archives are stored
# The web account user must have full read/write permission to this folder.
# répertoire où les archives sont exportés
# l'utilisateur apache doit être propriétaire du répertoire
ZM_DIR_EXPORTS=/var/tmp/zm

# ZoneMinder url path to the zms streaming server
ZM_PATH_ZMS=/zm/cgi-bin/nph-zms

# Full Path to ZoneMinder's mapped memory files
# The web account user must have full read/write permission to this folder.
ZM_PATH_MAP=/dev/shm

# Full Path to ZoneMinder's socket folder
# The web account user must have full read/write permission to this folder.
# répertoire des sockets
# l'utilisateur apache doit en être propriétaire
ZM_PATH_SOCKS=/var/run/zm

# Full path to ZoneMinder's log folder
# The web account user must have full read/write permission to this folder.
# répertoire des logs
# l'utilisateur apache doit en être propriétaire
ZM_PATH_LOGS=/var/log/zm

# Full path to ZoneMinder's swap folder
# The web account user must have full read/write permission to this folder.
ZM_PATH_SWAP=/var/tmp/zm

# Full path to optional arp binary
# ZoneMinder will find the arp binary automatically on most systems
ZM_PATH_ARP="/usr/sbin/arp"

#Full path to shutdown binary
ZM_PATH_SHUTDOWN="/sbin/shutdown"

# Path to FFmpeg binary
ZM_PATH_FFMPEG="/usr/local/bin/ffmpeg"

il faudra veiller à ce que l'utilisateur apache soit bien propriétaire de certains répertoires nécessaires au fonctionnement de zoneminder

chown -R apache:apache /var/run/zm
chown -R apache:apache /var/log/zm
chown -R apache:apache /var/lib/zoneminder
chown -R apache:apache /usr/share/zoneminder/www
chown -R apache:apache /var/cache/zoneminder
chown -R apache:apache /etc/zm

accessoirement j'ai créé le lien suivant

ln -s /var/cache/zoneminder/ /usr/share/zoneminder/www/cache

il faudra ensuite modifier la configuration du serveur Apache httpd dans le fichier /usr/local/apache2/conf/httpd/conf, tout d'abord la liste des modules utiles et nécessaires

LoadModule authn_file_module modules/mod_authn_file.so
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule access_compat_module modules/mod_access_compat.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
LoadModule reqtimeout_module modules/mod_reqtimeout.so
LoadModule filter_module modules/mod_filter.so
LoadModule mime_module modules/mod_mime.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule env_module modules/mod_env.so
LoadModule expires_module modules/mod_expires.so
LoadModule headers_module modules/mod_headers.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule version_module modules/mod_version.so
LoadModule ssl_module modules/mod_ssl.so
LoadModule unixd_module modules/mod_unixd.so
LoadModule status_module modules/mod_status.so
LoadModule autoindex_module modules/mod_autoindex.so
LoadModule cgid_module modules/mod_cgid.so
LoadModule dir_module modules/mod_dir.so
LoadModule alias_module modules/mod_alias.so
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule php_module         modules/libphp.so

(...)

# le propriétaire du daemon apache/httpd

User apache
Group apache

(...)

#directives spécifiques zoneminder
<Directory "/usr/share/zoneminder/www">
   Options -Indexes +FollowSymLinks
   AllowOverride All
   Require all granted
</Directory>

<Directory "/var/cache/zoneminder">
    Options -Indexes +FollowSymLinks
    AllowOverride None
    Require all granted
</Directory>

<Directory "/usr/share/zoneminder/cgi-bin">
    Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
    AllowOverride All
    Require all granted
</Directory>

<Directory "/usr/share/zoneminder/www/api">
   RewriteEngine on
   RewriteRule ^$ app/webroot/ [L]
   RewriteRule (.*) app/webroot/$1 [L]
   RewriteBase /zm/api
</Directory>

<Directory "/usr/share/zoneminder/www/api/app">
   RewriteEngine on
   RewriteRule ^$ webroot/ [L]
   RewriteRule (.*) webroot/$1 [L]
   RewriteBase /zm/api
</Directory>

<Directory "/usr/share/zoneminder/www/api/app/webroot">
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [L]
    RewriteBase /zm/api
</Directory>

#alias zoneminder dans cet ordre précis
ScriptAlias /zm/cgi-bin "/usr/share/zoneminder/cgi-bin"
Alias /zm/cache "/var/cache/zoneminder"
Alias /zm "/usr/share/zoneminder/www"

on veillera également à ce que la variable de la zone horaire du fichier /usr/local/apache2/conf/php.ini soit bien initialisée

date.timezone = Europe/Paris

on relance Apache httpd pour la prise en compte de la mise à jour de ces deux derniers fichiers

systemctl httpd restart

et on lance zoneminder en tapant

systemctl start zoneminder

et voilà ce que renvoie la commande

systemctl status zoneminder

● zoneminder.service - ZoneMinder CCTV recording and security system
     Loaded: loaded (/usr/lib/systemd/system/zoneminder.service; disabled; preset: disabled)
     Active: active (running) since Fri 2024-08-09 16:03:47 CEST; 11s ago
    Process: 3570 ExecStart=/usr/bin/zmpkg.pl start (code=exited, status=0/SUCCESS)
   Main PID: 3578 (zmdc.pl)
      Tasks: 5 (limit: 9239)
     Memory: 91.5M
        CPU: 2.077s
     CGroup: /system.slice/zoneminder.service
             ├─3578 /usr/bin/perl -wT /usr/bin/zmdc.pl startup
             ├─3606 /usr/bin/perl -wT /usr/bin/zmfilter.pl --filter_id=1 --daemon
             ├─3610 /usr/bin/perl -wT /usr/bin/zmfilter.pl --filter_id=2 --daemon
             ├─3616 /usr/bin/perl -wT /usr/bin/zmwatch.pl
             └─3620 /usr/bin/perl -wT /usr/bin/zmstats.pl

août 09 16:03:44 ultra.kervao.fr systemd[1]: Starting zoneminder.service...
août 09 16:03:47 ultra.kervao.fr systemd[1]: Started zoneminder.service.

[retour haut de la page]

Mise à jour vers la version instable

On téléchargera la dernière version en tapant la commande

git clone https://github.com/ZoneMinder/ZoneMinder

cela va donner un répertoire ZoneMinder dans lequel on tape

mkdir build
cd build
git submodule update --init --recursive

à ce moment on veillera à avoir installé les packages lib64gsoap-devel et json-devel, on tape ensuite

cmake .. -DMYSQLCLIENT_LIBRARIES=/usr/local/mysql/lib/libmysqlclient.so -DZM_DB_HOST=mariadb-serveur -DZM_WEB_USER=apache -DZM_DIR_EVENTS=/media/motion/events -DZM_CGIDIR=/usr/share/zoneminder/cgi-bin -DCMAKE_INSTALL_PREFIX=/usr/local -DZM_CONFIG_DIR=/etc/zm -DZM_CONFIG_SUBDIR=/etc/zm/conf.d -DZM_PERL_SEARCH_PATH=/usr/share/perl5/vendor_perl -DZM_SYSTEMD=ON -DZM_WEBDIR=/usr/share/zoneminder/www

voici la fin du résultat

-- Found PerlModules: TRUE 
-- Using web user: apache
-- Using web group: apache
-- Checking for one of the modules 'polkit-gobject-1;polkit'
-- Checking for module 'glib-2.0'
--   Found glib-2.0, version 2.76.3
-- Found GLIB2: /usr/lib64/libglib-2.0.so 
-- Found Polkit: /usr/lib64/libpolkit-gobject-1.so 
-- Found OpenSSL: /usr/lib64/libcrypto.so (found suitable version "3.0.15", minimum required is "1.0.1") 
-- The ASM compiler identification is GNU
-- Found assembler: /usr/bin/cc
INFO    Expanding CMAKE_PREFIX_PATH to include package build dir
Building unit tests: No (default)
-- Optional libraries found: zlib cURL OpenSSL PCRE Mosquitto Mosquittopp libVLC gsoap
-- Optional libraries not found: libVNC
-- Enabled crypto backend: openssl
-- Enabled JWT backend: jwt_cpp
-- Running ZoneMinder configuration generator
Generating '/usr/local/linux/securite/ZoneMinder/build/zm_config_defines.h'
Updating '/usr/local/linux/securite/ZoneMinder/build/db/zm_create.sql'
-- ZoneMinder configuration generator completed successfully
-- Configuring done (10.4s)
-- Generating done (0.2s)
-- Build files have been written to: /usr/local/linux/securite/ZoneMinder/build

on tape alors make puis en tant que root

make install
cp -Rf /root/perl5/lib/perl5/WSDiscovery11 /usr/share/perl5/vendor_perl
cp -Rf /root/perl5/lib/perl5/WSDiscovery10 /usr/share/perl5/vendor_perl
cp -Rf /root/perl5/lib/perl5/WSNotification /usr/share/perl5/vendor_perl
cp -Rf /root/perl5/lib/perl5/ONVIF /usr/share/perl5/vendor_perl
cp -Rf /root/perl5/lib/perl5/WSNotification/ /usr/share/perl5/vendor_perl
cp -Rf /root/perl5/lib/perl5/ZoneMinder* /usr/share/perl5/vendor_perl
cp -Rf /root/perl5/lib/perl5/WSSecurity/ /usr/share/perl5/vendor_perl
cp -Rf /root/perl5/lib/perl5/WSDiscovery /usr/share/perl5/vendor_perl
cp -Rf /usr/share/zoneminder/cgi-bin/zms /usr/local/apache2/cgi-bin/nph-zms

et pour éviter cette erreur

avril 26 17:49:33 ultra.kervao.fr zmpkg[1997204]: FAT [Version mismatch, system is version 1.37.66, database is 1.36.35, please run zmupdate.pl to update.]
avril 26 17:49:33 ultra.kervao.fr systemd[1]: zoneminder.service: Control process exited, code=exited, status=255/EXCEPTION
avril 26 17:49:33 ultra.kervao.fr systemd[1]: zoneminder.service: Failed with result 'exit-code'.
avril 26 17:49:33 ultra.kervao.fr systemd[1]: Failed to start zoneminder.service.

on mettra à jour la base de données de zoneminder en tapant

/usr/local/bin/zmupdate.pl

voici une partie du résultat

Initiating database upgrade to version 1.37.66 from version 1.36.35

Do you wish to take a backup of your database prior to upgrading?
This may result in a large file in /var/tmp/zm if you have a lot of events.
Press 'y' for a backup or 'n' to continue : y
Creating backup to /var/tmp/zm/zm-1.36.35.dump. This may take several minutes.
mysqldump: Deprecated program name. It will be removed in a future release, use '/usr/local/mysql/bin/mariadb-dump' instead
Database successfully backed up to /var/tmp/zm/zm-1.36.35.dump, proceeding to upgrade.

Upgrading database to version 1.37.66
Upgrading DB to 1.37.1 from 1.36.35
mysql: Deprecated program name. It will be removed in a future release, use '/usr/local/mysql/bin/mariadb' instead

(...)

Database successfully upgraded to version 1.37.62.
Upgrading DB to 1.37.63 from 1.36.35
mysql: Deprecated program name. It will be removed in a future release, use '/usr/local/mysql/bin/mariadb' instead

Database successfully upgraded to version 1.37.63.
Upgrading DB to 1.37.66 from 1.36.35
mysql: Deprecated program name. It will be removed in a future release, use '/usr/local/mysql/bin/mariadb' instead

Database successfully upgraded to version 1.37.66.

Database upgrade to version 1.37.66 successful.


Utilisation

Voilà l'écran principal avec une caméra rajoutée à partir de la commande Ajouter Caméra avec le mode Modect, c'est à dire qu'il va détecter les mouvements et créer un évènement pour chacun.

Il aura fallu définir la source vidéo de la vue, en mettant le chemin

Puis on définit les caractéristiques de la caméra à partir de la source


Dans Storage on choisira plutôt au niveau de Video Writer Camera Passthrough pour ne pas surcharger zoneminder avec un encodage, cela signifie qu'on écrit la vidéo fournie par la caméra telle quelle.

A noter le paramètre % fusion image référence qui va jouer sur le taux de détection, pour une caméra extérieure il est recommandé de mettre 12,5%. Pour déclencher une alarme on pourra mettre une valeur différence, elle correspond au pourcentage de l'image qui a bougé par rapport à l'image de référence.

Avec plusieurs caméras cela donne


En cliquant sur la caméra on a la vue en temps réel, les évènements sont affichés dans une liste en dessous de la vue de la caméra sélectionnée


Pour visualiser un évènement particulier, il faut cliquer dessus, l'évènement en question est marqué dans la timeline en rouge


Attention pour les caméras fournissant la vidéo avec le codec HEVC, le replay ne sera pas visible sous Firefox dont la fondation refuse de payer les brevets correspondants. En revanche cela marchera très bien avec Gnome web (ancien Epiphany) par exemple.

On dispose d'outils de rejeu vidéo pour visualiser l'évènement en question, on pourra les supprimer au niveau précédent.
Pour avoir un mur d'images avec la caméra, on ira sur Montage


Le menu Options permettra de pouvoir accéder aux différentes options


Les évènements sont sauvegardés par défaut sous /var/lib/zoneminder/www/events, vous pouvez rajouter un espace supplémentaire  en cliquant sur Add new storage


Vous avez tout intérêt à faire un ménage régulier pour ne pas exploser le disque, c'est possible de le faire automatiquement à partir du menu Filtres en sélectionnant PurgeWhenFull avec un nettoyage lancé à partir d'une occupation de 95% du disque.


Pour être prévenu par mail au moindre évènement on configurera l'option Email dans les Options


mais ce n'est pas suffisant il faut créer ensuite un filtre qui déclenchera l'envoi de mail quand le score de détection atteint au moins 5.


Pour affiner encore plus les réglages on peut définir des zones de détection avec des réglages particuliers pour chaque zone, il faut faire glisser les 4 point verts au angle pour la matérialiser.



Pour chaque caméra on pourra donc définir plusieurs zones de détection, ci-dessous il y  a 3 zones actives et 5 zones inactives où aucun évènement ne sera remonté.


Pour plus de détail sur les zones, vous pouvez consulter la documentation officielle ainsi que cette page du wiki et celle là (en anglais), cette page en français est également d'une aide précieuse pour comprendre les types de zone et leur paramétrage.

On peut retenir qu'il existe plusieurs méthodes de déclenchement d'alarme, Alarmed Pixels, Filtered Pixels et blobs sans rentrer dans le détail qui est donné dans les pages citées plus haut, la dernière méthode blobs est donnée pour être la plus efficace. On définira ensuite les seuils de détection à partir de la taille des objets détectés.

Les caméras extérieures restent les plus délicates à régler. J'ai pas mal galéré pour trouver le bon réglage pour ma caméra qui vise le portail qui est plutôt lointain, elle ne détectait rien du tout jusqu'à ce que je reprenne les réglages de cette page qui ont été un bon point de départ, sans que ça soit totalement satisfaisant pour des objets de la taille d'une personne proche du portail.



Dans ce cas il faudra privilégier l'unité pixels plutôt que pourcentage qui permet un réglage plus fin. Dans mon cas (ci-dessous) la surface de la zone fait 204040 pixels, soit vu la forme de ma zone en trapèze, à peu près un rectangle de 900x225 pixels à partir de la il faut s'imaginer la taille d'une personne pour en déduire sa taille en pixel (on peut s'aider de gimp), dans mon cas ça fait à peu près une taille de 25x60pixels, soit 1500pixels qu'on va retrouver dans le champ min de Surface en alarme


Il faut procéder ensuite en tâtonnant pour le reste des paramètres. Maintenant à la détection d'un évènement la ou les zones concernées seront indiquées



Aller encore plus loin avec ZMES

Le serveur de notification d'évènement "Event Notification Server" ou ZMES est un outil complémentaire à zoneminder, il dispose d'une "machine learning" ou d'un apprentissage automatique qui lui permet de reconnaître les objets, qu'ils soient des personnes ou des voitures par exemples.

Le site officiel est  https://github.com/ZoneMinder/zmeventnotification on y récupère les sources qu'on décompresse en tapant

tar xvfz zmeventnotification-6.1.29.tar.gz

cela donne le répertoire zmeventnotification-6.1.29. On pourra choisir également d'installer la version en développement en tapant

git clone https://github.com/ZoneMinder/zmeventnotification

On installera d'abord les packages perl-YAML-LibYAML, perl-Crypt-MySQL, perl-Module-Build-Tiny et perl-CPAN-DistnameInfo. Puis avec CPAN

perl -MCPAN -e "install Crypt::Eksblowfish::Bcrypt"
perl -MCPAN -e "install Protocol::WebSocket"
perl -MCPAN -e "install Net::WebSocket::Server"

perl -MCPAN -e "install Net::MQTT::Simple"


      

sous zmeventnotification-6.1.29 on tape ./install.sh

voilà une partie du résultat

which: no apt-get in (/root/perl5:/usr/local/sbin:/usr/sbin:/usr/local/bin:/usr/bin:/usr/local/mysql/bin:/usr/lib64/qt5/bin:/usr/lib64/qt6/bin)
which: no yum in (/root/perl5:/usr/local/sbin:/usr/sbin:/usr/local/bin:/usr/bin:/usr/local/mysql/bin:/usr/lib64/qt5/bin:/usr/lib64/qt6/bin)

----------- Configured Values ----------------------------
Your distro seems to be ubuntu
Your webserver user seems to be apache
Your webserver group seems to be apache
wget is /usr/bin/wget
installer software is
Install Event Server: prompt
Install Event Server config: prompt
Install Hooks: prompt
Install Hooks config: prompt
Upgrade Hooks config (if applicable): yes
Download and install models (if needed): yes

The Event Server will be installed to /usr/bin
The Event Server config will be installed to /etc/zm
Hooks will be installed to /var/lib/zmeventnotification sub-folders
Hook config files will be installed to /etc/zm

Models that will be checked/installed:
(Note, if you have already downloaded a model, it will not be deleted)
Yolo V3 (INSTALL_YOLOV3): yes
TinyYolo V3 (INSTALL_TINYYOLOV3): yes
Yolo V4 (INSTALL_YOLOV4): yes
Tiny Yolo V4 (INSTALL_TINYYOLOV4): yes
Google Coral Edge TPU (INSTALL_CORAL_EDGETPU): no

If any of this looks wrong, please hit Ctrl+C and edit the variables in this script...

Install Event Server Config [y/N]:y
Replacing ES config & rules file
Success:config copied
Replacing ES rules file
Success:rules copied
====> Remember to fill in the right values in the config files, or your system won't work! <=============



Install Hook [y/N]:y
Installing pip...
install: opérande de fichier cible manquant après 'pip'
Saisissez « install --help » pour plus d'informations.
Installing python3-opencv...
install: opérande de fichier cible manquant après 'python3-opencv'
Saisissez « install --help » pour plus d'informations.
*** Installing Hooks ***
Checking for YoloV3 data files....
yolov3.cfg exists, no need to download
coco.names exists, no need to download
yolov3.weights exists, no need to download

Checking for TinyYOLOV3 data files...
yolov3-tiny.cfg exists, no need to download
coco.names exists, no need to download
yolov3-tiny.weights exists, no need to download

Checking for TinyYOLOV4 data files...
yolov4-tiny.cfg exists, no need to download
coco.names exists, no need to download
yolov4-tiny.weights exists, no need to download

Checking for YOLOV4 data files...
WARNING:Note, you need OpenCV 4.4+ for Yolov4 to work
yolov4.cfg exists, no need to download
coco.names exists, no need to download
yolov4.weights exists, no need to download
*** Installing push api plugins ***
*** Installing detection scripts ***

*** Installing user contributions ***
Copying over contrib/example.py...
Copying over contrib/ftp_selective_upload.py...

Removing old version of zmes_hook_helpers, if any
Installing new version of hooks
sudo -H pip3 -v install hook/
Using pip 23.0.1 from /usr/lib/python3.10/site-packages/pip (python 3.10)
Processing ./hook

(...)

Installing package deps...
Installing gifsicle, if needed...
install : option invalide -- 'q'
Saisissez « install --help » pour plus d'informations.
Skipping Hook install


Install Hook Config [y/N]:y
Replacing Hook config file
Success:config copied
====> Remember to fill in the right values in the config files, or your system won't work! <=============
====> If you changed /etc/zm remember to fix  /var/lib/zmeventnotification/bin/zm_event_start.sh! <========


Creating a migrated objectconfig if required
Current version of file is 1.2
Nothing to migrate

*** Please remember to start the Event Server after this update ***

Il faudra modifier ou créer des fichiers sous /etc/zm tout d'abord secrets.ini qui contiendra

[secrets]

# l'URL pour accéder à zoneminder https://ultra.kervao.fr/zm est à adapter, l'utilisateur et le mot de passe de connexion sont définis dans la page de configuration système

ZMES_PICTURE_URL=https://ultra.kervao.fr/zm/index.php?view=image&eid=EVENTID&fid=objdetect&width=600
ZM_USER=zm-user
ZM_PASSWORD=password

ZM_PORTAL=https://ultra.kervao.fr/zm
ZM_API_PORTAL=https://ultra.kervao.fr/zm/api

# certificat et clé pour une connexion ssl, j'ai réutilisé celles de mon serveur apache
ES_CERT_FILE=/etc/ssl/public/apache.crt
ES_KEY_FILE=/etc/ssl/apache/apache.key

#clé pour la reconnaissance des plaques d'immatriculation, il faudra créer un compte sur ce site https://platerecognizer.com/
PLATEREC_ALPR_KEY=cb5ece0dhkhg1bea8dfd08408ec6cb8370d6c3b5c

On modifiera maintenant le fichier /etc/zm/objectconfig.ini qui contiendra (extraits)

(...)

secrets = /etc/zm/secrets.ini

# portal/user/password are needed if you plan on using ZM's legacy
# auth mechanism to get images

# ne rien modifier il va chercher dans le fichier secrets.ini

portal=!ZM_PORTAL
user=!ZM_USER
password=!ZM_PASSWORD

# api portal is needed if you plan to use tokens to get images
# requires ZM 1.33 or above
api_portal=!ZM_API_PORTAL

# ce paramètre doit être mis à yes en cas de connexion chiffrée avec certificat auto signé
allow_self_signed=yes

(...)

# If you need basic auth to access ZM

#si le répertoire est protégé par mot de passe avec un .htaccess on indiquera le mot de passe ici

basic_user=login-apache
basic_password=password-apache

(...)

# API/password for remote gateway
ml_user=!ML_USER
ml_password=!ML_PASSWORD

(...)

# la clé pour la reconnaissance des plaques, idem au fichier secrets.ini
alpr_key=cb5ece0dhkhg1bea8dfd08408ec6cb8370d6c3b5c

On modifier maintenant /etc/zm/zmeventnotification.ini

[ssl]
# Enable SSL (default: yes)
enable = yes

#idem clé dans le fichier secrets.ini
cert = /etc/ssl/public/apache.crt
key = /etc/ssl/apache/apache.key

Maintenant dans les options et configuration système on cochera les cases OPT_USE_API  et OPT_USE_EVENTNOTIFICATION

On relance zoneminder et on lance ZMES en tapant

sudo -u apache /usr/bin/zmeventnotification.pl

voilà le résultat

Use of uninitialized value $first_arg in string eq at ./zmeventnotification.pl line 62.
27/10/2024 17:31:03.690121 zmeventnotification[163691].INF [main:330] [Running on WebSocket library version:0.004]
27/10/2024 17:31:07.018532 zmeventnotification[163691].INF [main:1010] [PARENT: using config file: /etc/zm/zmeventnotification.ini]
27/10/2024 17:31:07.833499 zmeventnotification[163691].INF [main:1010] [PARENT: using secrets file: /etc/zm/secrets.ini]
Use of uninitialized value $es_debug_level in numeric ge (>=) at ./zmeventnotification.pl line 999.
Use of uninitialized value $es_debug_level in numeric ge (>=) at ./zmeventnotification.pl line 999.
Use of uninitialized value $skip_monitors in split at ./zmeventnotification.pl line 543.
Use of uninitialized value $es_debug_level in numeric ge (>=) at ./zmeventnotification.pl line 999.
Use of uninitialized value $hook_skip_monitors in split at ./zmeventnotification.pl line 732.

avec un évènement

27/10/2024 17:31:26.558583 zmeventnotification[163691].INF [main:1010] [PARENT: Push enabled via FCM]
27/10/2024 17:31:26.558734 zmeventnotification[163691].INF [main:1010] [PARENT: MQTT Disabled]
27/10/2024 17:31:26.558814 zmeventnotification[163691].INF [main:1010] [PARENT: |------- Starting ES version: 6.1.29 ---------|]
Can't ignore signal CHLD, forcing to default.
27/10/2024 17:31:49.322211 zmeventnotification[163691].INF [main:1010] [PARENT: Event Notification daemon v 6.1.29 starting]
27/10/2024 17:31:50.349988 zmeventnotification[163691].INF [main:1010] [PARENT: Re-loading monitors]
Use of uninitialized value in concatenation (.) or string at ./zmeventnotification.pl line 1453.
27/10/2024 17:31:54.071086 zmeventnotification[163691].INF [main:1010] [PARENT: New event 380 reported for Monitor:4 (Name:Camera-4) Motion[last processed eid:]]
27/10/2024 17:31:56.427281 zmeventnotification[163691].INF [main:1010] [PARENT: Secure WS(WSS) is enabled...]
27/10/2024 17:31:56.427365 zmeventnotification[163691].INF [main:1010] [PARENT: Web Socket Event Server listening on port 9000]

pour l'activer en tant que service systemd, on va créer le fichier /usr/lib/systemd/system/zmes.service qui contiendra

[Unit]
Description=ZMES
After=zoneminder.service
Requires=zoneminder.service httpd.service

[Service]
User=apache
Type=simple
ExecStart=/usr/bin/zmeventnotification.pl
Restart=on-failure

[Install]
WantedBy=multi-user.target

on l'activera en tapant

systemclt enable zmes

on le lance en tapant

systemctl start zmes

voici son statut en tapant

systemctl status zmes

● zmes.service - ZMES
     Loaded: loaded (/usr/lib/systemd/system/zmes.service; disabled; preset: disabled)
     Active: active (running) since Thu 2024-10-31 10:43:42 CET; 36s ago
   Main PID: 243499 (zmeventnotifica)
      Tasks: 1 (limit: 9239)
     Memory: 46.3M
        CPU: 784ms
     CGroup: /system.slice/zmes.service
             └─243499 /usr/bin/perl -T /usr/bin/zmeventnotification.pl

oct. 31 10:43:42 ultra.kervao.fr systemd[1]: Started zmes.service.
oct. 31 10:43:42 ultra.kervao.fr zmeventnotification.pl[243499]: Use of uninitialized value $first_arg in string eq at /usr/bin/zmeventnotification.pl line 61.
oct. 31 10:43:43 ultra.kervao.fr zmeventnotification.pl[243499]: Use of uninitialized value $es_debug_level in numeric ge (>=) at /usr/bin/zmeventnotification.pl line 998.
oct. 31 10:43:43 ultra.kervao.fr zmeventnotification.pl[243499]: Use of uninitialized value $es_debug_level in numeric ge (>=) at /usr/bin/zmeventnotification.pl line 998.
oct. 31 10:43:43 ultra.kervao.fr zmeventnotification.pl[243499]: Use of uninitialized value $skip_monitors in split at /usr/bin/zmeventnotification.pl line 542.
oct. 31 10:43:43 ultra.kervao.fr zmeventnotification.pl[243499]: Use of uninitialized value $es_debug_level in numeric ge (>=) at /usr/bin/zmeventnotification.pl line 998.
oct. 31 10:43:43 ultra.kervao.fr zmeventnotification.pl[243499]: Use of uninitialized value $hook_skip_monitors in split at /usr/bin/zmeventnotification.pl line 731.
oct. 31 10:43:44 ultra.kervao.fr zmeventnotification.pl[243505]: Can't ignore signal CHLD, forcing to default.

Et voilà ce que ça va donner au niveau de l'interface, on voit qu'il a identifié des personnes et un véhicule (truck).


Et au niveau du menu Audit Events Report, on pourra cliquer sur les liens où un objet a été identifié

l'objet en question est entouré, ici une personne


dans les version récentes 1.37.X, il faudra cliquer sur l'évènement et sur l'écran à gauche, on a des thumbails pour "first alarmed frame", "frame with the most motion" et "detected objets", en cliquand sur cette dernière, on retrouve l'image du type de ci-dessus.



Faire une mise à jour de zoneminder

En cas de mise à jour de zoneminder, la base de donnée ne sera pas forcément dans le bon format et au lancement vous pourriez avoir un message comme celui-ci

Version mismatch, system is version 1.36.35, database is 1.36.33, please run zmupdate.pl to update

Dans ce cas avec un serveur MariaDB j'ai d'abord créé les liens suivants

ln -s /usr/local/mysql/bin/mariadb-dump /usr/local/bin/mysqldump
ln -s /usr/local/mysql/bin/mariadb /usr/local/bin/mysql


ensuite on tape

/usr/bin/zmupdate.pl

voilà le résultat

Initiating database upgrade to version 1.36.35 from version 1.36.33

Do you wish to take a backup of your database prior to upgrading?
This may result in a large file in /var/tmp/zm if you have a lot of events.
Press 'y' for a backup or 'n' to continue : y
Creating backup to /var/tmp/zm/zm-1.36.33.dump. This may take several minutes.
mysqldump: Deprecated program name. It will be removed in a future release, use '/usr/local/mysql/bin/mariadb-dump' instead
Database successfully backed up to /var/tmp/zm/zm-1.36.33.dump, proceeding to upgrade.

Upgrading database to version 1.36.35
Upgrading DB to 1.36.34 from 1.36.33
mysql: Deprecated program name. It will be removed in a future release, use '/usr/local/mysql/bin/mariadb' instead

Database successfully upgraded to version 1.36.34.

Database upgrade to version 1.36.35 successful.

C'est bon c'est terminé, on peut à nouveau lancer et utiliser zoneminder.

[retour haut de la page]

Piloter zoneminder d'un téléphone portable avec zmNinja

Il est possible d’accéder à zoneminder à partir d’un mobile dès lors que vous avez activé votre serveur LAMP pour être visible sur internet comme indiqué ici et si possible avec une connexion chiffrée comme expliquée par .

L’affichage sur le mobile n’est pas formidable et pas très convivial comme on peut le voir ci-dessous:

Il se trouve qu’il existe une application adhoc qui s’appelle zmNinja. Alors certes cela coûte la modique somme de 4,69€ mais ça vaut le coup d’investir pour si peu pour avoir une visualisation confortable sur mobile.

Tout d’abord sous zoneminder j’ai procédé à quelques configurations pour sécuriser l’accès. J’ai d’abord créé des utilisateurs, un compte admin classique et un compte limité utilisateur.

Ensuite dans les paramètres au niveau de système j'ai activé l'authentification de zoneminder en cochant les cases ci-dessous.

Ensuite tout se passe sur le mobile, où on commence à indiquer l’URL et les mots de passe.


Le premier mot de passe ZM authentication correspond au mot de passe défini dans zoneminder, le deuxième correspond au mot de passe mis en place sous Apache avec le fichier .htaccess pour sécuriser l’accès au répertoire.


La deuxième partie partie de l’écran est ci-dessous où on indiquera l’URL du serveur zoneminder.

L'écran principal


Le mode montage

[retour haut de la page]

Utiliser une clé accélérateur Google Coral avec ZoneMinder

Pour activer la clé Google Coral avec ZoneMinder, on relancer l'installation de zmes en spécifiant qu'on l'utilise en tapant en tant que root

cd zmeventnotification-6.1.29
INSTALL_CORAL_EDGETPU=yes ./install.sh

voilà le résultat

which: no apt-get in (/root/perl5:/usr/local/sbin:/usr/sbin:/usr/local/bin:/usr/bin:/usr/local/mysql/bin:/usr/lib64/qt5/bin:/usr/lib64/qt6/bin)
which: no yum in (/root/perl5:/usr/local/sbin:/usr/sbin:/usr/local/bin:/usr/bin:/usr/local/mysql/bin:/usr/lib64/qt5/bin:/usr/lib64/qt6/bin)

----------- Configured Values ----------------------------
Your distro seems to be ubuntu
Your webserver user seems to be apache
Your webserver group seems to be apache
wget is /usr/bin/wget
installer software is
Install Event Server: prompt
Install Event Server config: prompt
Install Hooks: prompt
Install Hooks config: prompt
Upgrade Hooks config (if applicable): yes
Download and install models (if needed): yes

The Event Server will be installed to /usr/bin
The Event Server config will be installed to /etc/zm
Hooks will be installed to /var/lib/zmeventnotification sub-folders
Hook config files will be installed to /etc/zm

Models that will be checked/installed:
(Note, if you have already downloaded a model, it will not be deleted)
Yolo V3 (INSTALL_YOLOV3): yes
TinyYolo V3 (INSTALL_TINYYOLOV3): yes
Yolo V4 (INSTALL_YOLOV4): yes
Tiny Yolo V4 (INSTALL_TINYYOLOV4): yes
Google Coral Edge TPU (INSTALL_CORAL_EDGETPU): no

If any of this looks wrong, please hit Ctrl+C and edit the variables in this script...


Install Event Server [y/N]:y
*** Installing ES Dependencies ***
 install libconfig-inifiles-perl libcrypt-mysql-perl libcrypt-eksblowfish-perl libmodule-build-perl libyaml-perl libjson-per liblwp-protocol-https-perl libgeos-devl
install: cible 'libyaml-perl': Aucun fichier ou dossier de ce type
./install.sh: ligne 208: apt-cache : commande introuvable
You will have to install Net::WebSocket::Server using cpan.
*** Installing ES ***
Success:Completed, but you will still have to install ES dependencies as per https://zmeventnotification.readthedocs.io/en/latest/guides/install.html#install-dependencies


Install Event Server Config [y/N]:y
Replacing ES config & rules file
Success:config copied
Replacing ES rules file
Success:rules copied
====> Remember to fill in the right values in the config files, or your system won't work! <=============



Install Hook [y/N]:y
Installing pip...


(...)

Success:Done

    |-------------------------- NOTE -------------------------------------|
   
     Hooks are installed, but please make sure you have the right version
     of OpenCV installed. I recommend removing any pip packages you may
     have installed of opencv* and compiling OpenCV 4.4.x+ from source.
     See https://zmeventnotification.readthedocs.io/en/latest/guides/hooks.html#opencv-install

    |----------------------------------------------------------------------|

Installing package deps...
Installing gifsicle, if needed...
install : option invalide -- 'q'
Saisissez « install --help » pour plus d'informations.
Skipping Hook install


Install Hook Config [y/N]:y
Replacing Hook config file
Success:config copied
====> Remember to fill in the right values in the config files, or your system won't work! <=============
====> If you changed /etc/zm remember to fix  /var/lib/zmeventnotification/bin/zm_event_start.sh! <========

    -------------------------- EdgeTPU note ----------------------------

    Note that while edgetpu support has been added, the expectation is
    that you have followed all the instructions at:
    https://coral.ai/docs/accelerator/get-started/ first. Specifically,
    you need to make sure you have:
    1. Installed the right libedgetpu library (max or std)
    2. Installed the right tensorflow-lite library
    3. Installed pycoral APIs as per https://coral.ai/software/#pycoral-api

    If you don't, things will break. Further, you also need to make sure
    your web user (apache) has access to the coral device.
    On my ubuntu system, I needed to do:
        sudo usermod -a -G plugdev www-data
    --------------------------------------------------------------------

Creating a migrated objectconfig if required
Current version of file is 1.2
Nothing to migrate

*** Please remember to start the Event Server after this update ***

maintenant dans le fichier /etc/zm/objectconfig.ini au niveau de la section object voilà les lignes modifiées

[object]

# Updated note: Don't use use_sequence=no. No longer supported reliably
# If you are using legacy format (use_sequence=no) then these parameters will
# be used during ML inferencing
object_detection_pattern=(person|car|motorbike|bus|truck|boat)
object_min_confidence=0.3
object_framework=coral_edgetpu
object_processor=tpu
object_weights={{base_data_path}}/models/coral_edgetpu/ssd_mobilenet_v2_coco_quant_postprocess_edgetpu.tflite
object_labels={{base_data_path}}/models/coral_edgetpu/coco_indexed.names

# Google Coral
# The mobiledet model came out in Nov 2020 and is supposed to be faster and more accurate but YMMV
tpu_object_weights_mobiledet={{base_data_path}}/models/coral_edgetpu/ssdlite_mobiledet_coco_qat_postprocess_edgetpu.tflite
tpu_object_weights_mobilenet={{base_data_path}}/models/coral_edgetpu/ssd_mobilenet_v2_coco_quant_postprocess_edgetpu.tflite
tpu_object_labels={{base_data_path}}/models/coral_edgetpu/coco_indexed.names
tpu_object_framework=coral_edgetpu
tpu_object_processor=tpu
tpu_min_confidence=0.6

tpu_max_frames=3
tpu_delegate = edgetpu
tflite_num_threads=2
object_detection_type=tflite
object_detection_framework=tensorflow
tflite_model=
{{base_data_path}}/models/coral_edgetpu/ssd_mobilenet_v2_coco_quant_postprocess_edgetpu.tflite
labels=
{{base_data_path}}/models/coral_edgetpu/coco_indexed.names

on relance zmes

systemctl restart zmes

pour vérifier si ça marche on peut taper zm_detect sur la base d'un évènement avec un objet particulier

/var/lib/zmeventnotification/bin/zm_detect.py --config /etc/zm/objectconfig.ini --monitor 4 --eventid 53968 --debug

sauf que j'ai rencontré cette erreur

DBG2 [zmesdetect_m4] [Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/pyzm/ml/detect_sequence.py", line 707, in detect_stream
    _b,_l,_c,_m = m.detect(image=frame)
  File "/usr/local/lib/python3.10/site-packages/pyzm/ml/object.py", line 78, in detect
    b,l,c,_model_names = self.model.detect(image)
  File "/usr/local/lib/python3.10/site-packages/pyzm/ml/coral_edgetpu.py", line 167, in detect
    _, scale = common.set_resized_input(
  File "/usr/local/lib/python3.10/site-packages/pycoral/adapters/common.py", line 98, in set_resized_input
    result = resize((w, h))
  File "/usr/local/lib/python3.10/site-packages/pyzm/ml/coral_edgetpu.py", line 168, in <lambda>
    self.model, img.size, lambda size: img.resize(size, Image.ANTIALIAS))
AttributeError: module 'PIL.Image' has no attribute 'ANTIALIAS'
]

pour la résoudre en tant que root, j'ai édité le fichier /usr/local/lib/python3.10/site-packages/pyzm/ml/coral_edgetpu.py en entête j'ai rajouté

import PIL
import numpy as np

puis remplacé cette ligne

    #self.model, img.size, lambda size: img.resize(size, Image.ANTIALIAS))
      self.model, img.size, lambda size: img.resize(size, PIL.Image.LANCZOS))

on retape zm_detect

/var/lib/zmeventnotification/bin/zm_detect.py --config /etc/zm/objectconfig.ini --monitor 4 --eventid 57983 --debug

et là bingo ça marche, voilà le résultat

10/28/25 20:11:30 zmesdetect_m4[1435625] INF ZMLog.py:292 [Setting up signal handler for logs]

10/28/25 20:11:30 zmesdetect_m4[1435625] INF ZMLog.py:301 [Switching global logger to ZMLog]

DBG1 [zmesdetect_m4] [---------| app:6.1.29, pyzm:0.3.64, ES:(?) , OpenCV:4.10.0|------------]
10/28/25 20:11:30 zmesdetect_m4[1435625] INF utils.py:404 [Reading config from: /etc/zm/objectconfig.ini]

10/28/25 20:11:30 zmesdetect_m4[1435625] INF utils.py:409 [Reading secrets from: /etc/zm/secrets.ini]

DBG2 [zmesdetect_m4] [Secret token found in config: !ZM_PORTAL]
DBG2 [zmesdetect_m4] [Secret token found in config: !ZM_USER]
DBG2 [zmesdetect_m4] [Secret token found in config: !ZM_PASSWORD]
DBG2 [zmesdetect_m4] [Secret token found in config: !ZM_API_PORTAL]
DBG2 [zmesdetect_m4] [Secret token found in config: !ML_USER]
DBG2 [zmesdetect_m4] [Secret token found in config: !ML_PASSWORD]
DBG2 [zmesdetect_m4] [Secret token found in config: !PLATEREC_ALPR_KEY]
DBG1 [zmesdetect_m4] [allowing self-signed certs to work...]
DBG2 [zmesdetect_m4] [Now checking for monitor overrides]
DBG2 [zmesdetect_m4] [import_zm_zones: match_reason=False and reason=None]
DBG2 [zmesdetect_m4] [Getting ZM zones using https://ultra.kervao.fr/zm/api/zones/forMonitor/4.json?username=xxx&password=yyy&user=xxx&pass=yyy]
DBG2 [zmesdetect_m4] [importing zoneminder polygon: all [525,249 1279,212 1279,719 470,719]]
DBG3 [zmesdetect_m4] [Finally, doing parameter substitution]
DBG1 [zmesdetect_m4] [Importing local classes for Object/Face]
DBG2 [zmesdetect_m4] [API SSL certificate check has been disbled]
DBG1 [zmesdetect_m4] [using username/password for login]
DBG1 [zmesdetect_m4] [{"version":"1.37.70","apiversion":"2.0"}]
DBG2 [zmesdetect_m4] [Using new token API]
DBG2 [zmesdetect_m4] [using ml_sequence]
DBG2 [zmesdetect_m4] [using stream_sequence]
DBG1 [zmesdetect_m4] [Resetting models, will be loaded on next run]
DBG2 [zmesdetect_m4] [Called detect_stream(stream=57983, ml_overrides={}, options={'frame_strategy': 'most_models', 'frame_set': 'snapshot,alarm', 'contig_frames_before_error': 5, 'max_attempts': 3, 'sleep_between_attempts': 4, 'resize': 800, 'api': <pyzm.api.ZMApi object at 0x7efcd5fc3fd0>, 'polygons': [{'name': 'all', 'value': [(525, 249), (1279, 212), (1279, 719), (470, 719)], 'pattern': None}], 'mid': '4'})]
DBG3 [zmesdetect_m4] [Using manual locking as we are only using one model]
DBG2 [zmesdetect_m4] [Media get SSL certificate check has been disbled]
DBG2 [zmesdetect_m4] [Using URL 57983 for stream]
DBG2 [zmesdetect_m4] [We will only process frames: ['snapshot', 'alarm']]
DBG2 [zmesdetect_m4] [No need to start streams, we are picking images from https://ultra.kervao.fr/zm/index.php?view=image&eid=57983]
DBG2 [zmesdetect_m4] [in detect_stream() polygons=[{'name': 'all', 'value': [(525, 249), (1279, 212), (1279, 719), (470, 719)], 'pattern': None}]]
DBG3 [zmesdetect_m4] [Reading https://ultra.kervao.fr/zm/index.php?view=image&eid=57983&fid=snapshot]
DBG3 [zmesdetect_m4] [make_request called with url=https://ultra.kervao.fr/zm/index.php?view=image&eid=57983&fid=snapshot payload={} type=get query={'token': ''}]
DBG1 [zmesdetect_m4] [perf: Starting for frame:snapshot]
DBG1 [zmesdetect_m4] [Sequence of detection types to execute: ['object']]
DBG1 [zmesdetect_m4] [============ Frame: snapshot Running object detection type in sequence ==================]
DBG2 [zmesdetect_m4] [Loading sequence: TPU object detection]
DBG2 [zmesdetect_m4] [Initializing model  type:object with options:{'name': 'TPU object detection', 'enabled': 'yes', 'object_weights': '/var/lib/zmeventnotification/models/coral_edgetpu/ssdlite_mobiledet_coco_qat_postprocess_edgetpu.tflite', 'object_labels': '/var/lib/zmeventnotification/models/coral_edgetpu/coco_indexed.names', 'object_min_confidence': 0.6, 'object_framework': 'coral_edgetpu', 'tpu_max_processes': 1, 'tpu_max_lock_wait': 100, 'max_detection_size': '90%', 'disable_locks': 'no'}]
DBG2 [zmesdetect_m4] [portalock: max:1, name:pyzm_uid5001_tpu_lock, timeout:100]
DBG2 [zmesdetect_m4] [Loading sequence: YoloV4 GPU/CPU]
DBG2 [zmesdetect_m4] [Initializing model  type:object with options:{'name': 'YoloV4 GPU/CPU', 'enabled': 'yes', 'object_config': '/var/lib/zmeventnotification/models/yolov4/yolov4.cfg', 'object_weights': '/var/lib/zmeventnotification/models/yolov4/yolov4.weights', 'object_labels': '/var/lib/zmeventnotification/models/yolov4/coco.names', 'object_min_confidence': 0.3, 'object_framework': 'opencv', 'object_processor': 'gpu', 'gpu_max_processes': 1, 'gpu_max_lock_wait': 100, 'cpu_max_processes': 3, 'cpu_max_lock_wait': 100, 'max_detection_size': '90%', 'disable_locks': 'no'}]
DBG2 [zmesdetect_m4] [portalock: max:1, name:pyzm_uid5001_gpu_lock, timeout:100]
DBG2 [zmesdetect_m4] [Waiting for pyzm_uid5001_tpu_lock portalock...]
DBG2 [zmesdetect_m4] [Got pyzm_uid5001_tpu_lock portalock]
DBG2 [zmesdetect_m4] [Waiting for pyzm_uid5001_gpu_lock portalock...]
DBG2 [zmesdetect_m4] [Got pyzm_uid5001_gpu_lock portalock]
DBG3 [zmesdetect_m4] [object has a same_model_sequence strategy of first]
DBG1 [zmesdetect_m4] [--------- Frame:snapshot Running variation: #1 -------------]
DBG2 [zmesdetect_m4] [pyzm_uid5001_tpu_lock portalock already acquired]
DBG1 [zmesdetect_m4] [|--------- Loading "TPU object detection" model from disk -------------|]
DBG1 [zmesdetect_m4] [perf: processor:tpu TPU initialization (loading /var/lib/zmeventnotification/models/coral_edgetpu/ssdlite_mobiledet_coco_qat_postprocess_edgetpu.tflite from disk) took: 2657.96 ms]
DBG1 [zmesdetect_m4] [|---------- TPU (input image: 800w*450h) ----------|]
DBG2 [zmesdetect_m4] [Released portalock pyzm_uid5001_tpu_lock]
DBG1 [zmesdetect_m4] [perf: processor:tpu Coral TPU detection took: 36.23 ms]
DBG3 [zmesdetect_m4] [Coral object returning: [],[],[]]
DBG2 [zmesdetect_m4] [core model detection over, got 0 objects. Now filtering]
DBG2 [zmesdetect_m4] [Max object size found to be: 90%]
DBG2 [zmesdetect_m4] [Converted 90% to 324000.0]
DBG2 [zmesdetect_m4] [Returning filtered list of 0 objects.]
DBG2 [zmesdetect_m4] [This model iteration inside object found: labels: [],conf:[]]
DBG2 [zmesdetect_m4] [Called _filter_detections(seq=object, box=[], label=[], conf=[], polygons=[{'name': 'all', 'value': [(525, 249), (1279, 212), (1279, 719), (470, 719)], 'pattern': None}], h=450, w=800, model_names=[])]
DBG2 [zmesdetect_m4] [Max object size found to be: 90%]
DBG2 [zmesdetect_m4] [Converted 90% to 324000.0]
DBG3 [zmesdetect_m4] [resized polygons x=0.625/y=0.625: [{'name': 'all', 'value': [(328, 155), (799, 132), (799, 449), (293, 449)], 'pattern': None}]]
DBG1 [zmesdetect_m4] [--------- Frame:snapshot Running variation: #2 -------------]
DBG2 [zmesdetect_m4] [detect extracted image dimensions as: 800wx450h]
DBG2 [zmesdetect_m4] [pyzm_uid5001_gpu_lock portalock already acquired]
DBG1 [zmesdetect_m4] [|--------- Loading "YoloV4 GPU/CPU" model from disk -------------|]
DBG1 [zmesdetect_m4] [You are using OpenCV >= 4.5.4, making sure we fix getUnconnectedOutLayers() API]
DBG1 [zmesdetect_m4] [perf: processor:gpu Yolo initialization (loading /var/lib/zmeventnotification/models/yolov4/yolov4.weights model from disk) took: 136.60 ms]
DBG2 [zmesdetect_m4] [Setting CUDA backend for OpenCV]
DBG3 [zmesdetect_m4] [If you did not set your CUDA_ARCH_BIN correctly during OpenCV compilation, you will get errors during detection related to invalid device/make_policy]
DBG1 [zmesdetect_m4] [|---------- YOLO (input image: 800w*450h, model resize dimensions: 416w*416h) ----------|]
[ WARN:0@4.781] global net_impl.cpp:178 setUpNet DNN module was not built with CUDA backend; switching to CPU
DBG2 [zmesdetect_m4] [Released pyzm_uid5001_gpu_lock portalock]
DBG1 [zmesdetect_m4] [perf: processor:gpu Yolo detection took: 3932.00 ms]
DBG2 [zmesdetect_m4] [perf: processor:gpu Yolo NMS filtering took: 1.77 ms]
DBG2 [zmesdetect_m4] [core model detection over, got 11 objects. Now filtering]
DBG2 [zmesdetect_m4] [Max object size found to be: 90%]
DBG2 [zmesdetect_m4] [Converted 90% to 324000.0]
DBG2 [zmesdetect_m4] [Ignoring pottedplant [542, 182, 562, 200] as conf. level 0.279738187789917 is lower than 0.3]
DBG2 [zmesdetect_m4] [Returning filtered list of 10 objects.]
DBG2 [zmesdetect_m4] [This model iteration inside object found: labels: ['pottedplant', 'person', 'pottedplant', 'pottedplant', 'pottedplant', 'vase', 'pottedplant', 'pottedplant', 'pottedplant', 'pottedplant'],conf:[0.9017574191093445, 0.8222572207450867, 0.7311447858810425, 0.547961413860321, 0.539945662021637, 0.4644719064235687, 0.43742167949676514, 0.39541205763816833, 0.3663233518600464, 0.31749823689460754]]
DBG2 [zmesdetect_m4] [Called _filter_detections(seq=object, box=[[501, 220, 567, 286], [370, 220, 412, 372], [578, 206, 604, 228], [630, 188, 664, 244], [472, 132, 520, 220], [529, 272, 549, 294], [476, 204, 500, 224], [606, 222, 626, 248], [538, 123, 566, 199], [522, 244, 566, 292]], label=['pottedplant', 'person', 'pottedplant', 'pottedplant', 'pottedplant', 'vase', 'pottedplant', 'pottedplant', 'pottedplant', 'pottedplant'], conf=[0.9017574191093445, 0.8222572207450867, 0.7311447858810425, 0.547961413860321, 0.539945662021637, 0.4644719064235687, 0.43742167949676514, 0.39541205763816833, 0.3663233518600464, 0.31749823689460754], polygons=[{'name': 'all', 'value': [(328, 155), (799, 132), (799, 449), (293, 449)], 'pattern': None}], h=450, w=800, model_names=['yolo', 'yolo', 'yolo', 'yolo', 'yolo', 'yolo', 'yolo', 'yolo', 'yolo', 'yolo'])]
DBG2 [zmesdetect_m4] [Max object size found to be: 90%]
DBG2 [zmesdetect_m4] [Converted 90% to 324000.0]
DBG2 [zmesdetect_m4] [intersection: object:pottedplant,POLYGON ((501 220, 567 220, 567 286, 501 286, 501 220)) intersects polygon:all,POLYGON ((328 155, 799 132, 799 449, 293 449, 328 155))]
DBG2 [zmesdetect_m4] [Using global match pattern: (person|car|motorbike|bus|truck|boat)]
DBG2 [zmesdetect_m4] [all intersects object:pottedplant[[(501, 220), (567, 220), (567, 286), (501, 286)]] but does NOT match your detect pattern filter]
DBG2 [zmesdetect_m4] [intersection: object:person,POLYGON ((370 220, 412 220, 412 372, 370 372, 370 220)) intersects polygon:all,POLYGON ((328 155, 799 132, 799 449, 293 449, 328 155))]
DBG2 [zmesdetect_m4] [Using global match pattern: (person|car|motorbike|bus|truck|boat)]
DBG2 [zmesdetect_m4] [all intersects object:person[[(370, 220), (412, 220), (412, 372), (370, 372)]]]
DBG2 [zmesdetect_m4] [intersection: object:pottedplant,POLYGON ((578 206, 604 206, 604 228, 578 228, 578 206)) intersects polygon:all,POLYGON ((328 155, 799 132, 799 449, 293 449, 328 155))]
DBG2 [zmesdetect_m4] [Using global match pattern: (person|car|motorbike|bus|truck|boat)]
DBG2 [zmesdetect_m4] [all intersects object:pottedplant[[(578, 206), (604, 206), (604, 228), (578, 228)]] but does NOT match your detect pattern filter]
DBG2 [zmesdetect_m4] [intersection: object:pottedplant,POLYGON ((630 188, 664 188, 664 244, 630 244, 630 188)) intersects polygon:all,POLYGON ((328 155, 799 132, 799 449, 293 449, 328 155))]
DBG2 [zmesdetect_m4] [Using global match pattern: (person|car|motorbike|bus|truck|boat)]
DBG2 [zmesdetect_m4] [all intersects object:pottedplant[[(630, 188), (664, 188), (664, 244), (630, 244)]] but does NOT match your detect pattern filter]
DBG2 [zmesdetect_m4] [intersection: object:pottedplant,POLYGON ((472 132, 520 132, 520 220, 472 220, 472 132)) intersects polygon:all,POLYGON ((328 155, 799 132, 799 449, 293 449, 328 155))]
DBG2 [zmesdetect_m4] [Using global match pattern: (person|car|motorbike|bus|truck|boat)]
DBG2 [zmesdetect_m4] [all intersects object:pottedplant[[(472, 132), (520, 132), (520, 220), (472, 220)]] but does NOT match your detect pattern filter]
DBG2 [zmesdetect_m4] [intersection: object:vase,POLYGON ((529 272, 549 272, 549 294, 529 294, 529 272)) intersects polygon:all,POLYGON ((328 155, 799 132, 799 449, 293 449, 328 155))]
DBG2 [zmesdetect_m4] [Using global match pattern: (person|car|motorbike|bus|truck|boat)]
DBG2 [zmesdetect_m4] [all intersects object:vase[[(529, 272), (549, 272), (549, 294), (529, 294)]] but does NOT match your detect pattern filter]
DBG2 [zmesdetect_m4] [intersection: object:pottedplant,POLYGON ((476 204, 500 204, 500 224, 476 224, 476 204)) intersects polygon:all,POLYGON ((328 155, 799 132, 799 449, 293 449, 328 155))]
DBG2 [zmesdetect_m4] [Using global match pattern: (person|car|motorbike|bus|truck|boat)]
DBG2 [zmesdetect_m4] [all intersects object:pottedplant[[(476, 204), (500, 204), (500, 224), (476, 224)]] but does NOT match your detect pattern filter]
DBG2 [zmesdetect_m4] [intersection: object:pottedplant,POLYGON ((606 222, 626 222, 626 248, 606 248, 606 222)) intersects polygon:all,POLYGON ((328 155, 799 132, 799 449, 293 449, 328 155))]
DBG2 [zmesdetect_m4] [Using global match pattern: (person|car|motorbike|bus|truck|boat)]
DBG2 [zmesdetect_m4] [all intersects object:pottedplant[[(606, 222), (626, 222), (626, 248), (606, 248)]] but does NOT match your detect pattern filter]
DBG2 [zmesdetect_m4] [intersection: object:pottedplant,POLYGON ((538 123, 566 123, 566 199, 538 199, 538 123)) intersects polygon:all,POLYGON ((328 155, 799 132, 799 449, 293 449, 328 155))]
DBG2 [zmesdetect_m4] [Using global match pattern: (person|car|motorbike|bus|truck|boat)]
DBG2 [zmesdetect_m4] [all intersects object:pottedplant[[(538, 123), (566, 123), (566, 199), (538, 199)]] but does NOT match your detect pattern filter]
DBG2 [zmesdetect_m4] [intersection: object:pottedplant,POLYGON ((522 244, 566 244, 566 292, 522 292, 522 244)) intersects polygon:all,POLYGON ((328 155, 799 132, 799 449, 293 449, 328 155))]
DBG2 [zmesdetect_m4] [Using global match pattern: (person|car|motorbike|bus|truck|boat)]
DBG2 [zmesdetect_m4] [all intersects object:pottedplant[[(522, 244), (566, 244), (566, 292), (522, 292)]] but does NOT match your detect pattern filter]
DBG2 [zmesdetect_m4] [breaking out of same model loop, as matches found and strategy is "first"]
DBG3 [zmesdetect_m4] [Reading https://ultra.kervao.fr/zm/index.php?view=image&eid=57983&fid=alarm]
DBG3 [zmesdetect_m4] [make_request called with url=https://ultra.kervao.fr/zm/index.php?view=image&eid=57983&fid=alarm payload={} type=get query={'token': ''}]
DBG1 [zmesdetect_m4] [perf: Starting for frame:alarm]
DBG1 [zmesdetect_m4] [Sequence of detection types to execute: ['object']]
DBG1 [zmesdetect_m4] [============ Frame: alarm Running object detection type in sequence ==================]
DBG3 [zmesdetect_m4] [object has a same_model_sequence strategy of first]
DBG1 [zmesdetect_m4] [--------- Frame:alarm Running variation: #1 -------------]
DBG2 [zmesdetect_m4] [Waiting for pyzm_uid5001_tpu_lock portalock...]
DBG2 [zmesdetect_m4] [Got pyzm_uid5001_tpu_lock portalock]
DBG1 [zmesdetect_m4] [|---------- TPU (input image: 800w*450h) ----------|]
DBG2 [zmesdetect_m4] [Released portalock pyzm_uid5001_tpu_lock]
DBG1 [zmesdetect_m4] [perf: processor:tpu Coral TPU detection took: 19.13 ms]
DBG3 [zmesdetect_m4] [Coral object returning: [],[],[]]
DBG2 [zmesdetect_m4] [core model detection over, got 0 objects. Now filtering]
DBG2 [zmesdetect_m4] [Max object size found to be: 90%]
DBG2 [zmesdetect_m4] [Converted 90% to 324000.0]
DBG2 [zmesdetect_m4] [Returning filtered list of 0 objects.]
DBG2 [zmesdetect_m4] [This model iteration inside object found: labels: [],conf:[]]
DBG2 [zmesdetect_m4] [Called _filter_detections(seq=object, box=[], label=[], conf=[], polygons=[{'name': 'all', 'value': [(328, 155), (799, 132), (799, 449), (293, 449)], 'pattern': None}], h=450, w=800, model_names=[])]
DBG2 [zmesdetect_m4] [Max object size found to be: 90%]
DBG2 [zmesdetect_m4] [Converted 90% to 324000.0]
DBG1 [zmesdetect_m4] [--------- Frame:alarm Running variation: #2 -------------]
DBG2 [zmesdetect_m4] [detect extracted image dimensions as: 800wx450h]
DBG2 [zmesdetect_m4] [Waiting for pyzm_uid5001_gpu_lock portalock...]
DBG2 [zmesdetect_m4] [Got pyzm_uid5001_gpu_lock portalock]
DBG1 [zmesdetect_m4] [|---------- YOLO (input image: 800w*450h, model resize dimensions: 416w*416h) ----------|]
DBG2 [zmesdetect_m4] [Released pyzm_uid5001_gpu_lock portalock]
DBG1 [zmesdetect_m4] [perf: processor:gpu Yolo detection took: 1958.64 ms]
DBG2 [zmesdetect_m4] [perf: processor:gpu Yolo NMS filtering took: 1.87 ms]
DBG2 [zmesdetect_m4] [core model detection over, got 11 objects. Now filtering]
DBG2 [zmesdetect_m4] [Max object size found to be: 90%]
DBG2 [zmesdetect_m4] [Converted 90% to 324000.0]
DBG2 [zmesdetect_m4] [Ignoring pottedplant [542, 182, 562, 200] as conf. level 0.279738187789917 is lower than 0.3]
DBG2 [zmesdetect_m4] [Returning filtered list of 10 objects.]
DBG2 [zmesdetect_m4] [This model iteration inside object found: labels: ['pottedplant', 'person', 'pottedplant', 'pottedplant', 'pottedplant', 'vase', 'pottedplant', 'pottedplant', 'pottedplant', 'pottedplant'],conf:[0.9017574191093445, 0.8222572207450867, 0.7311447858810425, 0.547961413860321, 0.539945662021637, 0.4644719064235687, 0.43742167949676514, 0.39541205763816833, 0.3663233518600464, 0.31749823689460754]]
DBG2 [zmesdetect_m4] [Called _filter_detections(seq=object, box=[[501, 220, 567, 286], [370, 220, 412, 372], [578, 206, 604, 228], [630, 188, 664, 244], [472, 132, 520, 220], [529, 272, 549, 294], [476, 204, 500, 224], [606, 222, 626, 248], [538, 123, 566, 199], [522, 244, 566, 292]], label=['pottedplant', 'person', 'pottedplant', 'pottedplant', 'pottedplant', 'vase', 'pottedplant', 'pottedplant', 'pottedplant', 'pottedplant'], conf=[0.9017574191093445, 0.8222572207450867, 0.7311447858810425, 0.547961413860321, 0.539945662021637, 0.4644719064235687, 0.43742167949676514, 0.39541205763816833, 0.3663233518600464, 0.31749823689460754], polygons=[{'name': 'all', 'value': [(328, 155), (799, 132), (799, 449), (293, 449)], 'pattern': None}], h=450, w=800, model_names=['yolo', 'yolo', 'yolo', 'yolo', 'yolo', 'yolo', 'yolo', 'yolo', 'yolo', 'yolo'])]
DBG2 [zmesdetect_m4] [Max object size found to be: 90%]
DBG2 [zmesdetect_m4] [Converted 90% to 324000.0]
DBG2 [zmesdetect_m4] [intersection: object:pottedplant,POLYGON ((501 220, 567 220, 567 286, 501 286, 501 220)) intersects polygon:all,POLYGON ((328 155, 799 132, 799 449, 293 449, 328 155))]
DBG2 [zmesdetect_m4] [Using global match pattern: (person|car|motorbike|bus|truck|boat)]
DBG2 [zmesdetect_m4] [all intersects object:pottedplant[[(501, 220), (567, 220), (567, 286), (501, 286)]] but does NOT match your detect pattern filter]
DBG2 [zmesdetect_m4] [intersection: object:person,POLYGON ((370 220, 412 220, 412 372, 370 372, 370 220)) intersects polygon:all,POLYGON ((328 155, 799 132, 799 449, 293 449, 328 155))]
DBG2 [zmesdetect_m4] [Using global match pattern: (person|car|motorbike|bus|truck|boat)]
DBG2 [zmesdetect_m4] [all intersects object:person[[(370, 220), (412, 220), (412, 372), (370, 372)]]]
DBG2 [zmesdetect_m4] [intersection: object:pottedplant,POLYGON ((578 206, 604 206, 604 228, 578 228, 578 206)) intersects polygon:all,POLYGON ((328 155, 799 132, 799 449, 293 449, 328 155))]
DBG2 [zmesdetect_m4] [Using global match pattern: (person|car|motorbike|bus|truck|boat)]
DBG2 [zmesdetect_m4] [all intersects object:pottedplant[[(578, 206), (604, 206), (604, 228), (578, 228)]] but does NOT match your detect pattern filter]
DBG2 [zmesdetect_m4] [intersection: object:pottedplant,POLYGON ((630 188, 664 188, 664 244, 630 244, 630 188)) intersects polygon:all,POLYGON ((328 155, 799 132, 799 449, 293 449, 328 155))]
DBG2 [zmesdetect_m4] [Using global match pattern: (person|car|motorbike|bus|truck|boat)]
DBG2 [zmesdetect_m4] [all intersects object:pottedplant[[(630, 188), (664, 188), (664, 244), (630, 244)]] but does NOT match your detect pattern filter]
DBG2 [zmesdetect_m4] [intersection: object:pottedplant,POLYGON ((472 132, 520 132, 520 220, 472 220, 472 132)) intersects polygon:all,POLYGON ((328 155, 799 132, 799 449, 293 449, 328 155))]
DBG2 [zmesdetect_m4] [Using global match pattern: (person|car|motorbike|bus|truck|boat)]
DBG2 [zmesdetect_m4] [all intersects object:pottedplant[[(472, 132), (520, 132), (520, 220), (472, 220)]] but does NOT match your detect pattern filter]
DBG2 [zmesdetect_m4] [intersection: object:vase,POLYGON ((529 272, 549 272, 549 294, 529 294, 529 272)) intersects polygon:all,POLYGON ((328 155, 799 132, 799 449, 293 449, 328 155))]
DBG2 [zmesdetect_m4] [Using global match pattern: (person|car|motorbike|bus|truck|boat)]
DBG2 [zmesdetect_m4] [all intersects object:vase[[(529, 272), (549, 272), (549, 294), (529, 294)]] but does NOT match your detect pattern filter]
DBG2 [zmesdetect_m4] [intersection: object:pottedplant,POLYGON ((476 204, 500 204, 500 224, 476 224, 476 204)) intersects polygon:all,POLYGON ((328 155, 799 132, 799 449, 293 449, 328 155))]
DBG2 [zmesdetect_m4] [Using global match pattern: (person|car|motorbike|bus|truck|boat)]
DBG2 [zmesdetect_m4] [all intersects object:pottedplant[[(476, 204), (500, 204), (500, 224), (476, 224)]] but does NOT match your detect pattern filter]
DBG2 [zmesdetect_m4] [intersection: object:pottedplant,POLYGON ((606 222, 626 222, 626 248, 606 248, 606 222)) intersects polygon:all,POLYGON ((328 155, 799 132, 799 449, 293 449, 328 155))]
DBG2 [zmesdetect_m4] [Using global match pattern: (person|car|motorbike|bus|truck|boat)]
DBG2 [zmesdetect_m4] [all intersects object:pottedplant[[(606, 222), (626, 222), (626, 248), (606, 248)]] but does NOT match your detect pattern filter]
DBG2 [zmesdetect_m4] [intersection: object:pottedplant,POLYGON ((538 123, 566 123, 566 199, 538 199, 538 123)) intersects polygon:all,POLYGON ((328 155, 799 132, 799 449, 293 449, 328 155))]
DBG2 [zmesdetect_m4] [Using global match pattern: (person|car|motorbike|bus|truck|boat)]
DBG2 [zmesdetect_m4] [all intersects object:pottedplant[[(538, 123), (566, 123), (566, 199), (538, 199)]] but does NOT match your detect pattern filter]
DBG2 [zmesdetect_m4] [intersection: object:pottedplant,POLYGON ((522 244, 566 244, 566 292, 522 292, 522 244)) intersects polygon:all,POLYGON ((328 155, 799 132, 799 449, 293 449, 328 155))]
DBG2 [zmesdetect_m4] [Using global match pattern: (person|car|motorbike|bus|truck|boat)]
DBG2 [zmesdetect_m4] [all intersects object:pottedplant[[(522, 244), (566, 244), (566, 292), (522, 292)]] but does NOT match your detect pattern filter]
DBG2 [zmesdetect_m4] [breaking out of same model loop, as matches found and strategy is "first"]
DBG2 [zmesdetect_m4] [pyzm_uid5001_tpu_lock portalock already released]
DBG2 [zmesdetect_m4] [pyzm_uid5001_gpu_lock portalock already released]
DBG1 [zmesdetect_m4] [perf: TOTAL detection sequence (with image loads) took: 9666.38 ms  to process 57983]
10/28/25 20:11:40 zmesdetect_m4[1435625] INF zm_detect.py:476 [Prediction string:[s] detected:person:82% ]

DBG1 [zmesdetect_m4] [Prediction string JSON:{"labels": ["person"], "boxes": [[370, 220, 412, 372]], "frame_id": "snapshot", "confidences": [0.8222572207450867], "image_dimensions": {"original": [720, 1280], "resized": [450, 800]}}]
[s] detected:person:82% --SPLIT--{"labels": ["person"], "boxes": [[370, 220, 412, 372]], "frame_id": "snapshot", "confidences": [0.8222572207450867], "image_dimensions": {"original": [720, 1280], "resized": [450, 800]}}
DBG1 [zmesdetect_m4] [Closing logs]

Si vous avez l'erreur suivante dans les logs

requests.exceptions.HTTPError: 500 Server Error: Internal Server Error for url: https://ultra.kervao.fr/zm/api/host/login.json

c'est qu'il manque l'extension apcu à PHP, on va la récupérer ici https://github.com/krakjoe/apcu/releases, on décompresse en tapant

tar xvfz apcu-5.1.24.tar.gz
cd apcu-5.1.24
phpize
./configure --enable-apcu
make

et en tant que root make install

on modifiera /usr/local/apache2/conf/php.ini en rajoutant

extension=apcu
apc.enabled=1
apc.enable_cli=1
on relance apache. Pour cette autre erreur

oct. 27 16:10:04 ultra.kervao.fr zm_detect.py[149699]: ERR [zmesdetect_m4] [Turning DB logging off. Could not connect to DB, message was:(mysql.connector.errors.DatabaseError) 1273 (HY000): Unknown collation: 'utf8mb4_0900_ai_ci'
                                                       (Background on this error at: http://sqlalche.me/e/13/4xp6)]

cela vient du fait que j'utilise mariadb qui n'a pas repris certains paramétrages de MySQL, j'ai dû remplacer les occurences de utf8mb4_0900_ai_ci par utf8mb4_unicode_520_ci dans les fichiers

/usr/local/lib64/python3.10/site-packages/mysql/connector/aio/charsets.py
/usr/local/lib64/python3.10/site-packages/mysql/connector/charsets.py

la commande ci-dessous permettra de voir si tout fonctionne correctement, il faudra indiquer un numéro d'évènement et de caméra.

sudo -u apache /var/lib/zmeventnotification/bin/zm_detect.py --config /etc/zm/objectconfig.ini --eventid 375 --monitorid 4 --debug

Si zoneminder semble fonctionner mais que vous avez un écran blanc au lieu de l'image il faudra sans doute éditer le fichier /etc/zm/conf.d/01-system-paths.conf et y indiquer

ZM_PATH_ZMS=/zm/cgi-bin/nph-zms

Quelques sites pour davantage d'informations
et bien sûr le forum https://forums.zoneminder.com/