猫咪如厕检测与分类识别系统系列【五】信息存储数据库改进+添加猫咪页面制作+猫咪躯体匹配算法架构更新

前情提要


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

已完成工作:

猫咪如厕检测与分类识别系统系列【一】 功能需求分析及猫咪分类特征提取

猫咪如厕检测与分类识别系统系列【二】多图上传及猫咪分类特征提取更新

猫咪如厕检测与分类识别系统系列【三】 融合yolov11目标检测

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

计划工作:

✅ 猫咪管理功能:已完成猫咪照片上传与名称登记模块。

✅ 多图上传与分类特征提取:已支持批量上传猫咪图像并自动更新个体特征库。

✅ 目标检测与事件识别集成(YOLOv11):功能开发中,正在实现猫咪行为自动识别。

⏳ 检测区域绘制功能:待开发,计划支持用户自定义如厕检测区域。

🔄 事件行为记录模块:进行中,将实现如厕进出时间、停留时长等事件记录功能。

⏳ 检测结果推流展示:待更新,计划支持算法结果实时推流。

⏳ 整体运行结果推流整合:待更新,计划集成检测图像与系统状态为统一视频流输出。

我们现在进行两项升级:

  1. 将如厕记录 存储到 SQLite 数据库
  • 替代 CSV 存储方式
  • 使用 SQLite 存储字段:猫名、进入时间、离开时间、如厕时长、图片路径等
  1. 前端页面支持 上传猫脸图 & 添加猫
  • 用户可以从 Web 上传图片 + 猫名

  • 自动提特征并写入猫数据库(支持多图上传)


🗂️ 本章节会包括:

模块 内容
toilet_logger.py 改写为使用 SQLite 存储记录
cat_database.db 存储如厕记录表 toilet_logs
Flask 页面上传猫图 上传猫图 + 猫名,调用特征提取器 + 保存
Flask 页面展示 改为从数据库查询展示记录

完成 SQLite 日志存储 + 查询展示(如厕记录页改数据库)

如厕记录系统已升级为使用 SQLite 数据库 存储,文件为:

复制代码
records/toilet_log.db

表结构:toilet_logs(name, enter_time, exit_time, duration, enter_image, exit_image)


更新 Flask 页面,改为从数据库中查询记录并展示到表格中。

python 复制代码
# app.py (使用 SQLite 显示如厕记录)

from flask import Flask, render\_template, request

import sqlite3

import os

  

app \= Flask(\_\_name\_\_, static\_url\_path\='')

DB\_PATH \= "records/toilet\_log.db"

  

@app.route('/')

def index():

query \= request.args.get('q', '').lower()

records \= \[\]

  

if os.path.exists(DB\_PATH):

conn \= sqlite3.connect(DB\_PATH)

cursor \= conn.cursor()

cursor.execute("SELECT name, enter\_time, exit\_time, duration, enter\_image, exit\_image FROM toilet\_logs ORDER BY id DESC")

for row in cursor.fetchall():

if query in row\[0\].lower():

records.append({

'Name': row\[0\],

'Enter Time': row\[1\],

'Exit Time': row\[2\],

'Duration(s)': row\[3\],

'Enter Image': row\[4\],

'Exit Image': row\[5\]

})

conn.close()

  

return render\_template('index.html', records\=records, query\=query)

  

if \_\_name\_\_ \== '\_\_main\_\_':

app.run(debug\=True)

✅ Flask 页面后端已完成更新,现在从 SQLite 数据库读取如厕记录,并支持通过 URL 查询参数 q 进行猫咪名称筛选。


✅ 接下来是 HTML 页面改造:

  • 输入框支持搜索(发送请求到 /?q=猫名

  • 保留图片预览功能

  • 所有记录从数据库加载

python 复制代码
html_updated = """
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>猫咪如厕记录</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; background-color: #f9f9f9; }
        h2 { color: #333; }
        table { width: 100%; border-collapse: collapse; margin-top: 20px; }
        th, td { border: 1px solid #ccc; padding: 10px; text-align: center; }
        th { background-color: #e0e0e0; }
        input[type="text"] { padding: 6px; width: 240px; margin-bottom: 15px; }
        .thumbnail { height: 80px; cursor: pointer; border-radius: 6px; }
        .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%; border-radius: 10px; }
    </style>
</head>
<body>
    <h2>🐱 猫咪如厕记录</h2>

    <form method="get" action="/">
        <input type="text" name="q" value="{{ query }}" placeholder="输入猫咪名字筛选...">
        <button type="submit">搜索</button>
    </form>

    <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 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_updated)

"index.html 页面已更新,支持 SQLite 查询并带搜索功能。"

✅ 前端页面已更新,现在支持:

  • 从 SQLite 查询如厕记录

  • 输入猫名关键词搜索(带刷新保留结果)

  • 缩略图展示 + 点击预览大图


📍访问方式:

bash 复制代码
cd cat_monitor/web
python app.py

浏览器打开: http://127.0.0.1:5000/


图片路径无法访问问题原因分析:

图片无法展示,说明 图片路径不对Flask 无法找到图片文件。当前的记录表中,图片路径是这样的:

python 复制代码
records/cat_name_enter_123456.jpg

但 Flask 默认只能访问 static/ 下的资源。


✅ 解决方案:

✅ 1. 把保存的图片改为放在 web/static/records/ 目录

修改你的 main.py 中这两行保存图片的位置:

python 复制代码
cv2.imwrite("web/static/records/xxx.jpg", frame)

同时,保存路径传给数据库的也要改为相对路径,例如:

python 复制代码
enter_img = f"static/records/{cat_name}_enter_{int(entry_time)}.jpg"

这样 Flask 页面显示时用:

html 复制代码
<img src="/static/records/{{ r['Enter Image'] }}" ...>

✅ 2. 或者:设置 Flask 支持访问 /records/

如果你不想改文件保存位置,也可以在 Flask 中暴露 records 目录:

python 复制代码
app = Flask(__name__, static_url_path='')

# 添加这行让 Flask 能访问 records/ 里的图片
@app.route('/records/<path:filename>')
def serve_record_file(filename):
    from flask import send_from_directory
    return send_from_directory('../records', filename)

然后前端页面这样写:

html 复制代码
<img src="/records/{{ r['Enter Image'].split('/')[-1] }}" class="thumbnail">

✅ 推荐方式(更整洁):

我们规范所有图像都放到:

复制代码
cat_monitor/web/static/records/

并使用 Flask 默认 static 路由 /static/... 展示即可。

🧩 进一步功能增强:

✅ 1. 【猫图上传页面】

  • Web 页面上传猫脸图 + 名字

  • 多图批量上传(改进识别稳定性)

  • 自动提取特征并存入猫数据库


✅ 2. 【统计功能】

  • 每只猫如厕频率统计(柱状图)

  • 如厕时长统计(平均、总和)

  • 趋势图(按日期汇总)


✅ 3. 【记录导出】

  • 记录导出为 CSV / Excel

  • 可按猫名 / 时间筛选后导出



1.猫图上传页面

✅ 之前已经创建了独立路由 /add_cat 支持:

  • 猫名输入

  • 批量上传猫脸图

  • 自动提取特征,保存识别样本

  • 上传成功后提示处理结果


接下来我会写页面模板 add_cat.html,支持:

  • 猫名输入框

  • 多图上传控件

  • 上传进度提示 / 成功信息

下面是其HTML 页面,并把它集成到原 Flask 页面的顶部菜单里作为一个导航入口。

python 复制代码
html_addcat = """
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>添加猫咪</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; }
        h2 { color: #333; }
        form { background: #f9f9f9; padding: 20px; border-radius: 8px; }
        input[type="text"], input[type="file"] {
            padding: 8px; width: 300px; margin-bottom: 10px;
        }
        input[type="submit"] {
            padding: 8px 16px; background: #4CAF50; color: white; border: none; border-radius: 4px;
        }
        .message { margin-top: 15px; color: green; }
        a { display: inline-block; margin-top: 15px; color: #007BFF; text-decoration: none; }
    </style>
</head>
<body>
    <h2>📤 添加猫咪识别样本</h2>

    <form method="POST" enctype="multipart/form-data">
        <label>猫咪名字:</label><br>
        <input type="text" name="name" required><br><br>

        <label>上传猫脸图片(可多选):</label><br>
        <input type="file" name="images" multiple accept="image/*" required><br><br>

        <input type="submit" value="上传并添加">
    </form>

    {% if message %}
    <div class="message">{{ message }}</div>
    {% endif %}

    <a href="/">← 返回如厕记录页</a>
</body>
</html>
"""

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

"已创建上传猫图页面 add_cat.html,可集成入口按钮到主页面。"

✅ 上传猫图页面 add_cat.html 已创建完毕。接下来我们将它集成到主页面(如厕记录页)里,方式如下:


🔧 集成步骤

index.html 顶部添加导航链接,例如放在 <body> 下:

html 复制代码
<a href="/add_cat" style="text-decoration: none; background: #4CAF50; color: white; padding: 8px 12px; border-radius: 4px;">➕ 添加猫咪</a>

我可以立即为你修改 index.html 文件,是否现在执行?你也可以告诉我更偏好的按钮样式或放置位置~


✅ 2. 增加统计图表功能

功能目标:

  • 显示每只猫如厕的 频率统计(柱状图)

  • 显示每只猫的 平均如厕时长(可选)

  • 使用 Chart.js 进行前端可视化

具体实现步骤如下:

  1. 更新后端 SQL 查询逻辑,支持:

    • 按猫名聚合统计频率和平均时长

    • 按日期筛选记录(支持 URL 参数)

  2. 更新 index.html 页面:

    • 增加统计图表容器(Chart.js)

    • 增加时间筛选表单

    • 增加 "导出记录" 按钮


下面柱状图统计(如厕频率)代码,并集成到页面中。主要展示哪种统计图为主:频率、平均时长、趋势。

python 复制代码
chart_html = """
<!-- 追加在 index.html 中统计图部分 -->
<h3>📊 猫咪如厕统计</h3>
<canvas id="chartFreq" height="120"></canvas>
<canvas id="chartDur" height="120" style="margin-top: 30px;"></canvas>

<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
    const freqCtx = document.getElementById('chartFreq');
    const durCtx = document.getElementById('chartDur');

    const freqData = {{ freq_data|tojson }};
    const durData = {{ dur_data|tojson }};

    new Chart(freqCtx, {
        type: 'bar',
        data: {
            labels: freqData.labels,
            datasets: [{
                label: '如厕次数',
                data: freqData.counts,
                borderWidth: 1
            }]
        },
        options: {
            responsive: true,
            plugins: { legend: { display: false }},
            scales: { y: { beginAtZero: true } }
        }
    });

    new Chart(durCtx, {
        type: 'bar',
        data: {
            labels: durData.labels,
            datasets: [{
                label: '平均如厕时长(秒)',
                data: durData.avg_durations,
                backgroundColor: 'rgba(75, 192, 192, 0.6)',
                borderWidth: 1
            }]
        },
        options: {
            responsive: true,
            plugins: { legend: { display: false }},
            scales: { y: { beginAtZero: true } }
        }
    });
</script>
"""

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

"已生成图表统计部分的 HTML,可嵌入主页面 index.html,接下来更新 Flask 后端逻辑支持统计数据。"

🔜 接下来,我将更新 Flask 后端 app.py

  • 查询数据库生成统计数据(频率 + 平均时长)

  • 传递数据给模板渲染 Chart.js 图表

Flask 后端 app.py 支持:

  • 从数据库读取如厕记录

  • 自动生成:

    • 每只猫的如厕次数统计

    • 每只猫的平均如厕时长

  • 将数据传给前端用于 Chart.js 渲染


下一步是将我们之前准备好的图表模块 chart_part.html 嵌入 index.html 页面。是否我现在直接更新页面,让图表显示在记录表下方?

目前存在问题:

分类全是 Unknown 的情况我们可以一步步优化,目前问题大概率出现在 猫脸识别的匹配策略或特征质量 上。


🧠 问题原因分析:

1. 猫图质量不稳定

  • 光照/角度/遮挡较大 → 提取特征不一致

  • 建议上传正面清晰猫脸图,多张样本图增强泛化能力

2. 匹配阈值太高

  • 目前分类用的是最近邻 + 相似度阈值(默认 0.7)

  • 如果猫脸图本身差异大,0.7 可能过严 → 全部被判成 Unknown

✅ 临时建议:先降低阈值到 0.5,观察识别是否有改善:

python 复制代码
# matcher.py 中的 match 方法
def match(self, query_vec, threshold=0.5):

3. 特征提取器泛化能力差

  • 使用的是通用 resnet18,可能对猫脸没有专门训练

  • 若需要长期稳定使用,可考虑:

    • ✅ 使用猫脸识别预训练模型(可提供)

    • ✅ 自定义猫脸数据集做微调(我可以帮你准备 fine-tune 流程)


✅ 测试:

  1. 上传每只猫的 3~5 张角度不同的图

  2. threshold 降低到 0.5 或更低(如 0.45)观察结果

  3. 使用 print 输出匹配得分看是否有接近但未过阈值的情况

例如你可以在 matcher.py 中打印相似度:

python 复制代码
print(f"猫 {names[best_idx]} 相似度: {best_score}")

测试结果:我们不是在做猫脸识别,而是识别每只猫的"整体外观"来区分个体,那么我们可以把"全猫裁剪图"当作识别输入,而不是专注猫脸。


✅ 新策略:猫体图识别个体(视觉外观)

核心改法:

  1. 保持现在的 YOLOv11 检测框不变(整只猫)

  2. 将裁剪下来的整猫图像作为"猫的识别样本"上传(不是脸部)

  3. 使用同样的分类逻辑(特征提取 + 最近邻匹配),但目标变成"全猫识别"


🔧 如何改得更好?

✅ 1. 特征提取器建议使用:

  • 通用图像分类特征模型(如 resnet18, efficientnet-b0

  • 或者我可以给你微调一个 triplet loss 结构(更适合个体识别)


✅ 2. 增强识别稳定性方法:

方法 描述
多图样本 每只猫上传多张(不同角度)
特征聚合 每只猫多个特征向量,识别时取最大相似度
动态阈值 允许你为不同猫设定不同相似度阈值(进阶)

✅ 思路

  1. 重新上传几只猫的"整体图像"样本(清晰的检测框图,非脸)

  2. matcher.py 中暂时将阈值调低到 0.5 以下

  3. 可开启打印相似度,确认是不是识别接近却没达标


因此,替换/优化现在的特征提取器(更适合全猫图)

python 复制代码
# matcher.py - 最近邻匹配猫个体(加入相似度输出 + 降低阈值)

from sklearn.metrics.pairwise import cosine\_similarity

import numpy as np

  

class CatMatcher:

def \_\_init\_\_(self, db):

self.db \= db

  

def match(self, query\_vec, threshold\=0.45): \# 降低默认阈值

embeddings, names \= self.db.get\_all()

if not embeddings:

return "Unknown"

  

sims \= cosine\_similarity(\[query\_vec\], embeddings)\[0\]

best\_idx \= np.argmax(sims)

best\_score \= sims\[best\_idx\]

  

print("--- 猫识别相似度得分 ---")

for i, sim in enumerate(sims):

print(f"{names\[i\]}: {sim:.3f}")

print(f"最相似: {names\[best\_idx\]} → {best\_score:.3f}")

  

if best\_score \> threshold:

return names\[best\_idx\]

return "Unknown"

已更新 matcher.py

  • 默认阈值调为 0.45(提高匹配成功率)

  • 每次识别时会输出所有猫的相似度分数

  • 控制台将显示最相似的猫与相似度,方便调试

相关推荐
巨可爱熊10 分钟前
高并发内存池(定长内存池基础)
linux·运维·服务器·c++·算法
爱数模的小驴2 小时前
2025 年“认证杯”数学中国数学建模网络挑战赛 C题 化工厂生产流程的预测和控制
深度学习·算法·计算机视觉
GOTXX3 小时前
【Qt】Qt Creator开发基础:项目创建、界面解析与核心概念入门
开发语言·数据库·c++·qt·图形渲染·图形化界面·qt新手入门
猿小喵3 小时前
记录一次TDSQL网关夯住故障
运维·数据库·mysql
电商api接口开发3 小时前
如何在C#中使用LINQ对数据库进行查询操作?
数据库·c#·linq
hnsqls3 小时前
Redis 常问知识
数据库·redis·缓存
序属秋秋秋4 小时前
算法基础_数据结构【单链表 + 双链表 + 栈 + 队列 + 单调栈 + 单调队列】
c语言·数据结构·c++·算法
蹦蹦跳跳真可爱5894 小时前
Python----机器学习(基于PyTorch的乳腺癌逻辑回归)
人工智能·pytorch·python·分类·逻辑回归·学习方法
apcipot_rain5 小时前
【密码学——基础理论与应用】李子臣编著 第五章 序列密码 课后习题
算法·密码学
不要不开心了5 小时前
sparkcore编程算子
pytorch·分布式·算法·pygame