当前位置: 首页 > news >正文

猫咪如厕检测与分类识别系统系列【四】融合检测日志输出及前端展示界面制作

✅ 前情提要


家里养了三只猫咪,其中一只布偶猫经常出入厕所。但因为平时忙于学业,没法时刻关注牠的行为。我知道猫咪的如厕频率和时长与健康状况密切相关,频繁如厕可能是泌尿问题,停留过久也可能是便秘或不适。为了更科学地了解牠的如厕习惯,我计划搭建一个基于视频监控和AI识别的系统,自动识别猫咪进出厕所的行为,记录如厕时间和停留时长,并区分不同猫咪。这样即使我不在家,也能掌握猫咪的健康状态,更安心地照顾它们。

已完成工作:

✅猫咪如厕检测与分类识别系统系列【一】 功能需求分析及猫咪分类特征提取
✅猫咪如厕检测与分类识别系统系列【二】多图上传及猫咪分类特征提取更新
✅猫咪如厕检测与分类识别系统系列【三】 融合yolov11目标检测

计划工作:

✅ 猫咪管理功能:已完成猫咪照片上传与名称登记模块。
✅ 多图上传与分类特征提取:已支持批量上传猫咪图像并自动更新个体特征库。
🔄 目标检测与事件识别集成(YOLOv11):功能开发中,已实现猫咪行为自动识别,正在集成至页面。
⏳ 检测区域绘制功能:待开发,计划支持用户自定义如厕检测区域。
⏳ 事件行为记录模块:待完善,将实现如厕进出时间、停留时长等事件记录功能。
⏳ 检测结果推流展示:待更新,计划支持算法结果实时推流。
⏳ 整体运行结果推流整合:待更新,计划集成检测图像与系统状态为统一视频流输出。

本次将继续制作 实时检测模块中的Flask 页面展示记录:🔜 现在我们要继续完成的:

✅ 1. 如厕事件记录系统:

  • 记录猫进入、

  • 显示:

    • 猫咪名字

    • 进入时间

    • 离开时间

    • 如厕时长

    • 图片预览

  • 可按时间筛选、导出记录


✅ 第一步:添加如厕记录系统(记录 + 存图)

🔧 toilet_logger.py(事件记录模块)

import os
import csv
from datetime import datetime

class ToiletLogger:
    def __init__(self, save_dir="records", csv_path="records/toilet_log.csv"):
        self.save_dir = save_dir
        self.csv_path = csv_path
        os.makedirs(save_dir, exist_ok=True)

        # 创建CSV头
        if not os.path.exists(self.csv_path):
            with open(self.csv_path, 'w', newline='') as f:
                writer = csv.writer(f)
                writer.writerow(["Name", "Enter Time", "Exit Time", "Duration(s)", "Enter Image", "Exit Image"])

    def log(self, name, entry_time, exit_time, enter_img, exit_img):
        duration = round(exit_time - entry_time, 2)
        enter_time_str = datetime.fromtimestamp(entry_time).strftime("%Y-%m-%d %H:%M:%S")
        exit_time_str = datetime.fromtimestamp(exit_time).strftime("%Y-%m-%d %H:%M:%S")

        enter_path = os.path.join(self.save_dir, enter_img)
        exit_path = os.path.join(self.save_dir, exit_img)

        with open(self.csv_path, 'a', newline='') as f:
            writer = csv.writer(f)
            writer.writerow([name, enter_time_str, exit_time_str, duration, enter_path, exit_path])

✅ 第二步:在 main.py 检测逻辑中调用记录器

加入:

from toilet_logger import ToiletLogger
logger = ToiletLogger()

然后在状态变化处加上记录逻辑:

# 进入区域
if detected and not cat_present:
    entry_time = time.time()
    cat_enter_img = f"{cat_name}_enter_{int(entry_time)}.jpg"
    cv2.imwrite(f"records/{cat_enter_img}", frame)
    print(f"🐱 {cat_name} 进入区域")

# 离开区域
if not detected and cat_present:
    exit_time = time.time()
    cat_exit_img = f"{cat_name}_exit_{int(exit_time)}.jpg"
    cv2.imwrite(f"records/{cat_exit_img}", frame)
    duration = round(exit_time - entry_time, 2)
    logger.log(cat_name, entry_time, exit_time, cat_enter_img, cat_exit_img)
    print(f"🚪 {cat_name} 离开区域,用时 {duration} 秒")

✅ 第三步:Flask 页面展示记录

页面功能:

  • 展示如厕记录表格

  • 显示进入/离开时间、图片、猫名


你可以先测试下这部分如厕记录逻辑是否正常工作:
🐾 猫进入 → 保存图片 → 离开 → 记录进 CSV → records/ 下有图像和日志。


目录结构:

已分析

# 项目结构
dirs = [
    "cat_monitor/recognizer",
    "cat_monitor/web/templates",
    "cat_monitor/web/static/uploads",
    "cat_monitor/data/embeddings",
    "cat_monitor/records"
]
#main.py
import cv2
import time
import numpy as np
from recognizer.embedder import CatEmbedder
from recognizer.database import CatDatabase
from recognizer.matcher import CatMatcher
from toilet\_logger import ToiletLogger
from ultralytics import YOLO

# 初始化模型与识别器

model = YOLO("yolov11.pt") \# 替换为你的模型路径

embedder = CatEmbedder()

db = CatDatabase()

matcher = CatMatcher(db)

logger = ToiletLogger()

  

# RTSP 摄像头地址

rtsp_url = "rtsp://192.168.0.102:554/stream1"

cap = cv2.VideoCapture(rtsp_url)

cap.set(cv2.CA\_PROP_BUFFERSIZE, 1)


# 区域设定(如厕区域)

TOILET_REGION = (100, 100, 400, 400)


# 状态追踪

cat_present= False

entry_time = None

cat_name = "Unknown"
 

cv2.namedWindow("Cat Monitor", cv2.WINDOW\_NORMAL)

cv2.resizeWindow("Cat Monitor", 960, 720)
while True:

ret, frame = cap.read()

if not ret:

✅ 主程序 main.py 已写入,支持:

  • RTSP 视频流读取

  • YOLOv11 检测 + 区域判断

  • 猫咪识别(调用分类模块)

  • 如厕进入/离开状态跟踪

  • 自动保存图像并写入记录日志

接下来我会继续添加:

  1. toilet_logger.py(如厕记录模块)

  2. 分类模块:embedder.py, database.py, matcher.py

  3. Flask 前端页面(用于展示如厕记录)

如厕记录前端界面:

# app.py (Flask 前端展示记录)

from flask import Flask, render\_template

import csv

  

app = Flask(__name__)

CSV_FILE = "records/toilet_log.csv"

  

@app.route('/')

def index():

records = []

try:

with open(CSV_FILE, newline='') as f:

reader = csv.DictReader(f)

for row in reader:

records.append(row)

except FileNotFoundError:

pass
 

return render_template('index.html', records=records)
 

if __name__ == '__main__':
	app.run(debug=True)

✅ Flask 后端展示代码已完成(app.py)。

Flask 后端页面代码:

html_code = """
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>猫咪如厕记录</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; }
        table { width: 100%; border-collapse: collapse; margin-top: 20px; }
        th, td { border: 1px solid #ccc; padding: 8px; text-align: center; }
        th { background-color: #f2f2f2; }
        input[type="text"] { padding: 6px; width: 200px; margin-right: 10px; }
        .thumbnail { height: 80px; cursor: pointer; }
        .modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; 
                 background-color: rgba(0, 0, 0, 0.7); align-items: center; justify-content: center; }
        .modal img { max-width: 80%; max-height: 80%; }
    </style>
</head>
<body>
    <h2>🐱 猫咪如厕记录</h2>

    <input type="text" id="filterInput" placeholder="输入猫咪名字筛选..." onkeyup="filterTable()">

    <table id="recordTable">
        <thead>
            <tr>
                <th>猫咪</th>
                <th>进入时间</th>
                <th>离开时间</th>
                <th>如厕时长 (秒)</th>
                <th>进入图</th>
                <th>离开图</th>
            </tr>
        </thead>
        <tbody>
            {% for r in records %}
            <tr>
                <td>{{ r['Name'] }}</td>
                <td>{{ r['Enter Time'] }}</td>
                <td>{{ r['Exit Time'] }}</td>
                <td>{{ r['Duration(s)'] }}</td>
                <td><img src="{{ '/' + r['Enter Image'] }}" class="thumbnail" onclick="showModal(this.src)"></td>
                <td><img src="{{ '/' + r['Exit Image'] }}" class="thumbnail" onclick="showModal(this.src)"></td>
            </tr>
            {% endfor %}
        </tbody>
    </table>

    <div class="modal" id="imgModal" onclick="hideModal()">
        <img id="modalImg" src="">
    </div>

    <script>
        function filterTable() {
            let input = document.getElementById("filterInput").value.toLowerCase();
            let rows = document.querySelectorAll("#recordTable tbody tr");
            rows.forEach(row => {
                let name = row.cells[0].textContent.toLowerCase();
                row.style.display = name.includes(input) ? "" : "none";
            });
        }

        function showModal(src) {
            document.getElementById("modalImg").src = src;
            document.getElementById("imgModal").style.display = "flex";
        }

        function hideModal() {
            document.getElementById("imgModal").style.display = "none";
        }
    </script>
</body>
</html>
"""

with open("cat_monitor/web/templates/index.html", "w", encoding="utf-8") as f:
    f.write(html_code)

"Flask 页面 HTML 已写入完成,支持筛选、图片预览。"

结果

✅ Flask 页面 index.html 已完成,具备以下功能:

  • 猫咪名字筛选(实时搜索)

  • 如厕记录表格展示(进入时间 / 离开时间 / 时长)

  • 进入图 & 离开图缩略图展示

  • 点击图片放大预览(弹窗模式)


相关文章:

  • 内网邮箱服务器搭建-详解
  • LabVIEW往复式压缩机管路故障诊断系统
  • 消防设施操作员岗位注意事项有哪些?
  • 《基于AI识别的雾炮联动:堆场扬尘治理新利器》
  • DeepSeek使用001:Word中配置DeepSeek AI的V3和R1模型
  • 【Hadoop入门】Hadoop生态之Flume简介
  • Android应用开发指南
  • 在WPS中通过JavaScript宏(JSA)调用DeepSeek官方API自动识别标题级别和目录
  • 在Vue项目的引入meting-js音乐播放器插件
  • K8s 集群网络疑难杂症:解决 CNI 网络接口宕机告警的完整指南
  • 09-设计模式 企业场景 面试题-mk
  • 小刚说C语言刷题——第22讲 二维数组
  • JS【详解】迭代器 Iterator(含可迭代对象、同步迭代器、异步迭代器等)
  • @PKU秋招互联网产品经理求职分享
  • 永磁同步电机控制算法--基于有功功率扰动的频率补偿IF控制
  • 网络1 网络设备
  • opencv-python(图像基础)
  • 解析医疗器械三大文档:DHF、DMR与DHR
  • 蓝桥杯之门牌
  • SQL问题分析与诊断(8)——分析方法1
  • 清空wordpress多媒体/东莞seo优化团队
  • 产品推广介绍/优化网站排名的方法
  • 有哪些网站可以做h5/网站网络推广优化
  • 建个网站公司/seo快速优化文章排名
  • 北京微信网站建设公司/优化网站首页
  • 甜点网站里的新闻资讯怎么做/谷歌seo查询