CedarAlert - DIY Object and Fire Detection for IP Security Cameras in Python
The purpose of this DIY project is to enhance four low cost outdoor motion detecting security cameras (Amcrest IP4M-1026W) with object and fire detection in a rural high risk fire area, and to provide email alerts with the image in question plus SMS alerts via the Verizon Wireless SMS portal.
Alerts are sent upon recognition of 'fire', 'person', 'bicycle', and 'bear', although the COCO dataset recognizes 80 classes of objects. The alert conditions can be changed in the 'run()' code.
All object recognition events, alert conditions, and images with no objects detected are logged into a JSON based log file and SQLite3 database by default.
In order to avoid too many alerts in a short period of time, alerts are sent no more frequently than 15 minutes, as defined by 'cedar_alert_seconds'. The Amcrest security cameras have a free Android and iOS app, so the video streams from the cameras can be viewed in real-time whenever an alert is received.
The four Amcrest cameras are configured to take three photos two seconds apart at each motion event, and send the images via FTP to a local desktop PC for AI analysis and storage.
This DIY application is provided as a free open source codebase as a courtesy without any promise of support nor guarantee of any kind.
This software is covered by the GNU General Public License v3.0 and any other licenses from other open source code referenced.
The CedarAlert application was developed on, and has been tested on, two Ubuntu 22.04.4 X86_64 desktop PCs without GPUs or TPUs for AI in use that by today's standard may be considered as low performance:
- Intel NUC5i7RYH (5th generation Intel i7 CPU) with 16 GB RAM and 500 GB SSD
- Beelink Mini S12 (12th generation Intel N100 CPU) with 16 GB RAM and 500 GB SSD (about $160 USD)
The CedarAlert specific files start with 'cedar_' to distinguish them from files from https://github.com/WongKinYiu/yolov9 and https://github.com/spacewalk01/yolov5-fire-detection.
The file 'cedar_vars.py' defines variables and creates a JSON object. The values with 'UPDATEME' must be changed (e.g. your SMTP email server domain name 'cedar_email_server') and no empty values are allowed. No CedarAlert processes will run with a value of 'UPDATEME' or an empty value, including the CedarAlert.service.
The YOLOv9 inference code is based upon 'detect_dual.py' and 'yolov9-s-converted.pt' model (weights) from https://github.com/WongKinYiu/yolov9.
To install this repository please run the commands below with a Linux user with 'sudo' rights without a password. See Method 2: Edit the sudoers file.
The 'gh' CLI install instructions are at https://github.com/cli/cli/blob/trunk/docs/install_linux.md.
cd ~
sudo apt update
sudo apt upgrade
sudo apt install -y build-essential libssl-dev libffi-dev python3-dev python3-pip python3-venv sqlite3 git
# clone this repository
git clone https://github.com/audioclassify/CedarAlert.git # or gh repo clone audioclassify/CedarAlert
# create Python environment
cd ~
mkdir -p environments
cd environments
python3 -m venv CedarAlert
source ~/environments/CedarAlert/bin/activate
# CedarAlert is the python env name and the folder name
cd ~/CedarAlert
# install requirements
pip install -r requirements.txt
pip install -r cedar_requirements.txt
# check python and pip versions
python -V
# Python 3.10.12
pip -V
# pip 22.0.2 from /home/cedar/environments/CedarAlert/lib/python3.10/site-pack ages/pip (python 3.10)
Verify CedarAlert Object Detecton with yolov9-s-converted.pt (COCO model)
(CedarAlert) cedar@NUC5i7RYH:~/CedarAlert$ python cedar_detect_dual.py \
--source "./data/images/horses.jpg" \
--weights "./yolov9-s-converted.pt"
# Output (5 horses, 386.3ms)
YOLO 1a55998 Python-3.10.12 torch-2.4.0+cu121 CPU
/home/cedar/CedarAlert/models/experimental.py:243: FutureWarning: You are using `torch.load` with `weights_only=False` (the current default value), which uses the default pickle module implicitly. It is possible to construct malicious pickle data which will execute arbitrary code during unpickling (See https://github.com/pytorch/pytorch/blob/main/SECURITY.md#unt rusted-models for more details). In a future release, the default value for `weights_only` will be flipped to `True`. This limits the functions that could be executed during unpickling. Arbitrary objects will no longer be allowed to be loaded via this mode unless they are explicitly allowlisted by the user via `torch.serialization.add_safe_globals`. We recommend you start setting `weights_only=True` for any use case where you don't have full control of the loaded file. Please open an issue on GitHub for any issues related to this experimental feature.
ckpt = torch.load(attempt_download(w), map_location='cpu') # load
Fusing layers...
gelan-s summary: 489 layers, 7105888 parameters, 34224 gradients, 26.4 GFLOPs
cedar_detect_dual run() LoadImages OK, source: ./data/images/horses.jpg ===
cedar_log_add() jstr: {"found":"horse", "conf":"0.734", "weights":"./yolov9-s-converted.pt", "source":"./data/images/horses.jpg", "save_path":"runs/detect/CedarAlert355/horses.jpg", "ts":"2024-08-31_10-51-23-083410", "email_ts":"email_none", "sms_ts":"sms_none", "exception": "exception_none"}
log_add() j: {'found': 'horse', 'conf': '0.734', 'weights': './yolov9-s-converted.pt', 'source': './data/images/horses.jpg', 'save_path': 'runs/detect/CedarAlert355/horses.jpg', 'ts': '2024-08-31_10-51-23-083410', 'email_ts': 'email_none', 'sms_ts': 'sms_none', 'exception': 'exception_none'}
log_add() sql: INSERT INTO LOG (fa, name, conf, weights, source, save_path, ts, email_ts, sms_ts, exception) VALUES ('found', 'horse', '0.734', './yolov9-s-converted.pt', './data/images/horses.jpg', 'runs/detect/CedarAlert355/horses.jpg', '2024-08-31_10-51-23-083410', 'email_none', 'sms_none', 'exception_none');
[]
cedar_log_add() jstr: {"found":"horse", "conf":"0.753", "weights":"./yolov9-s-converted.pt", "source":"./data/images/horses.jpg", "save_path":"runs/detect/CedarAlert355/horses.jpg", "ts":"2024-08-31_10-51-23-090671", "email_ts":"email_none", "sms_ts":"sms_none", "exception": "exception_none"}
log_add() j: {'found': 'horse', 'conf': '0.753', 'weights': './yolov9-s-converted.pt', 'source': './data/images/horses.jpg', 'save_path': 'runs/detect/CedarAlert355/horses.jpg', 'ts': '2024-08-31_10-51-23-090671', 'email_ts': 'email_none', 'sms_ts': 'sms_none', 'exception': 'exception_none'}
log_add() sql: INSERT INTO LOG (fa, name, conf, weights, source, save_path, ts, email_ts, sms_ts, exception) VALUES ('found', 'horse', '0.753', './yolov9-s-converted.pt', './data/images/horses.jpg', 'runs/detect/CedarAlert355/horses.jpg', '2024-08-31_10-51-23-090671', 'email_none', 'sms_none', 'exception_none');
[]
cedar_log_add() jstr: {"found":"horse", "conf":"0.875", "weights":"./yolov9-s-converted.pt", "source":"./data/images/horses.jpg", "save_path":"runs/detect/CedarAlert355/horses.jpg", "ts":"2024-08-31_10-51-23-098571", "email_ts":"email_none", "sms_ts":"sms_none", "exception": "exception_none"}
log_add() j: {'found': 'horse', 'conf': '0.875', 'weights': './yolov9-s-converted.pt', 'source': './data/images/horses.jpg', 'save_path': 'runs/detect/CedarAlert355/horses.jpg', 'ts': '2024-08-31_10-51-23-098571', 'email_ts': 'email_none', 'sms_ts': 'sms_none', 'exception': 'exception_none'}
log_add() sql: INSERT INTO LOG (fa, name, conf, weights, source, save_path, ts, email_ts, sms_ts, exception) VALUES ('found', 'horse', '0.875', './yolov9-s-converted.pt', './data/images/horses.jpg', 'runs/detect/CedarAlert355/horses.jpg', '2024-08-31_10-51-23-098571', 'email_none', 'sms_none', 'exception_none');
[]
cedar_log_add() jstr: {"found":"horse", "conf":"0.941", "weights":"./yolov9-s-converted.pt", "source":"./data/images/horses.jpg", "save_path":"runs/detect/CedarAlert355/horses.jpg", "ts":"2024-08-31_10-51-23-103017", "email_ts":"email_none", "sms_ts":"sms_none", "exception": "exception_none"}
log_add() j: {'found': 'horse', 'conf': '0.941', 'weights': './yolov9-s-converted.pt', 'source': './data/images/horses.jpg', 'save_path': 'runs/detect/CedarAlert355/horses.jpg', 'ts': '2024-08-31_10-51-23-103017', 'email_ts': 'email_none', 'sms_ts': 'sms_none', 'exception': 'exception_none'}
log_add() sql: INSERT INTO LOG (fa, name, conf, weights, source, save_path, ts, email_ts, sms_ts, exception) VALUES ('found', 'horse', '0.941', './yolov9-s-converted.pt', './data/images/horses.jpg', 'runs/detect/CedarAlert355/horses.jpg', '2024-08-31_10-51-23-103017', 'email_none', 'sms_none', 'exception_none');
[]
cedar_log_add() jstr: {"found":"horse", "conf":"0.950", "weights":"./yolov9-s-converted.pt", "source":"./data/images/horses.jpg", "save_path":"runs/detect/CedarAlert355/horses.jpg", "ts":"2024-08-31_10-51-23-107553", "email_ts":"email_none", "sms_ts":"sms_none", "exception": "exception_none"}
log_add() j: {'found': 'horse', 'conf': '0.950', 'weights': './yolov9-s-converted.pt', 'source': './data/images/horses.jpg', 'save_path': 'runs/detect/CedarAlert355/horses.jpg', 'ts': '2024-08-31_10-51-23-107553', 'email_ts': 'email_none', 'sms_ts': 'sms_none', 'exception': 'exception_none'}
log_add() sql: INSERT INTO LOG (fa, name, conf, weights, source, save_path, ts, email_ts, sms_ts, exception) VALUES ('found', 'horse', '0.950', './yolov9-s-converted.pt', './data/images/horses.jpg', 'runs/detect/CedarAlert355/horses.jpg', '2024-08-31_10-51-23-107553', 'email_none', 'sms_none', 'exception_none');
[]
save_img, cv2.imwrite(save_path, im0), save_path: runs/detect/CedarAlert355/horses.jpg
image 1/1 /home/cedar/CedarAlert/data/images/horses.jpg: 448x640 5 horses, 386.3ms ./yolov9-s-converted.pt
Speed: 1.5ms pre-process, 386.3ms inference, 1.2ms NMS per image at shape (1, 3, 640, 640) ./yolov9-s-converted.pt
Results saved to runs/detect/CedarAlert355