猫咪如厕检测与分类识别系统系列【六】分类模型训练+混合检测分类+未知目标自动更新

前情提要


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

已完成工作:

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

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

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

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

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

计划工作:

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

🔄 多图上传与分类特征提取:已支持批量上传猫咪图像并自动更新个体特征库。优化中,更新特征提取器逻辑及代码

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

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

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

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

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

我们现在进行下面任务:

1.分类模型训练

2.matcher+目标检测混合检测分类

3.未知目标自动更新

分类模型训练

如果你已经将猫图按如下结构存放:

复制代码
finetune_dataset/
├── Mimi/
│   ├── mimi_1.jpg
│   ├── mimi_2.jpg
├── Kaka/
│   ├── kaka1.jpg
│   └── kaka2.jpg
...

已经拥有一个标准的 分类数据集结构,我们可以直接用它训练一个猫个体识别模型 ✅


✅ 下一步:训练专属识别模型

我们将创建一个 PyTorch 训练脚本,功能包括:

🎯 训练目标:

  • 模型结构:ResNet18(轻量、好用)

  • 分类数:你的猫的数量(由文件夹个数自动决定)

  • 输入图像:自动从 finetune_dataset/ 加载

  • 输出模型:.pt 文件(后续可以接入系统)


python 复制代码
# train_cat_classifier.py - 猫个体识别模型训练脚本(PyTorch)
import os
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms, models
from torch.utils.data import DataLoader, random_split

# 配置
DATA_DIR = r"C:\Users\Administrator\Desktop\cat"
BATCH_SIZE = 16
EPOCHS = 20
LR = 1e-4
MODEL_SAVE = "cat_classifier.pt"
IMG_SIZE = 224

# 数据增强与预处理
data_transforms = transforms.Compose([
    transforms.Resize((IMG_SIZE, IMG_SIZE)),
    transforms.RandomHorizontalFlip(),
    transforms.ToTensor(),
])

# 加载数据
full_dataset = datasets.ImageFolder(DATA_DIR, transform=data_transforms)
class_names = full_dataset.classes
num_classes = len(class_names)
print(f"📦 识别 {num_classes} 个猫个体: {class_names}")

# 划分训练/验证集
val_size = int(0.2 * len(full_dataset))
train_size = len(full_dataset) - val_size
train_dataset, val_dataset = random_split(full_dataset, [train_size, val_size])

train_loader = DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True)
val_loader = DataLoader(val_dataset, batch_size=BATCH_SIZE)

# 加载预训练 ResNet18 模型
model = models.resnet18(pretrained=True)
model.fc = nn.Linear(model.fc.in_features, num_classes)

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = model.to(device)

criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=LR)

# 训练循环
def train():
    best_acc = 0.0
    for epoch in range(EPOCHS):
        model.train()
        total_loss = 0.0
        for inputs, labels in train_loader:
            inputs, labels = inputs.to(device), labels.to(device)
            optimizer.zero_grad()
            outputs = model(inputs)
            loss = criterion(outputs, labels)
            loss.backward()
            optimizer.step()
            total_loss += loss.item()

        model.eval()
        correct, total = 0, 0
        with torch.no_grad():
            for inputs, labels in val_loader:
                inputs, labels = inputs.to(device), labels.to(device)
                outputs = model(inputs)
                _, preds = torch.max(outputs, 1)
                correct += (preds == labels).sum().item()
                total += labels.size(0)

        acc = correct / total
        print(f"[Epoch {epoch+1}/{EPOCHS}] Loss: {total_loss:.3f}, Val Acc: {acc:.3f}")

        # 保存最佳模型
        if acc > best_acc:
            best_acc = acc
            torch.save(model.state_dict(), MODEL_SAVE)
            print("保存最优模型")

if __name__ == '__main__':
    train()
    print(f 训练完成,模型保存为 {MODEL_SAVE}")

训练过程图:

🧠 功能亮点:

功能 说明
自动划分训练/验证集 80% 训练 + 20% 验证
使用 ResNet18 可识别多只猫个体
数据增强 随机水平翻转等
自动保存最优模型 保存为 cat_classifier.pt
输出训练日志 每轮 loss + 验证准确率

🚀 运行方式:

bash 复制代码
cd cat_monitor
python train_cat_classifier.py

训练完成后,可以用这个模型来替换现在的特征提取+匹配方式,直接做分类。接下来我们将其集成到现有猫咪如厕系统中:


✅ 集成目标:

  1. 加载分类模型ResNet18

  2. 对每只检测到的猫图裁剪图像进行分类

  3. 替换原来的特征提取 + 最近邻匹配逻辑

  4. 返回类别名(即猫名)


🔧 集成方式:

我们将创建一个新模块:

复制代码
recognizer/classifier.py

用于封装分类推理逻辑,支持:

  • 加载 .pt 模型

  • 输入图像(BGR/路径/PIL)

  • 输出预测猫名


但是现在存在一个问题,「当有新猫咪加入时,分类模型如何处理?」


❗问题本质:

当前训练的是一个 固定类别分类模型ResNet18,比如识别 3 只猫:guorong、guoqing、guoqiang)

🐾 如果你添加新猫,比如 guodong,这个模型无法识别 guodong,因为 guodong 没有出现在训练集中。


✅ 应对方案:

✅ 方案 A:继续使用 最近邻特征匹配方式

  • 新猫加入时,只需添加新图 → 提特征 → 加入库

  • 优点:支持 动态扩展,无需重训

  • 缺点:识别准确率依赖于特征提取器 + 距离匹配

💡 推荐将 分类器作为主识别方式,最近邻匹配作为兜底 fallback


✅ 方案 B:训练时保留 旧数据,增量训练/微调

  • 重新运行 prepare_dataset.py,把新猫的图也加进去

  • 再跑一次 train_cat_classifier.py

  • 注意设置 num_workers=0 / seed 保证 reproducibility


✅ 方案 C(推荐组合):

识别方式 适合场景
分类器(准确) 已知猫咪、数据稳定,主力识别
匹配器(灵活) 新猫加入后立即可用,不中断使用
→ 组合:优先分类器,分类失败再 fallback 到最近邻匹配

🧠 总结推荐结构:

python 复制代码
def recognize_cat(img_crop):
    pred = classifier.predict(img_crop)
    if pred == "Unknown":
        pred = matcher.match(embedder.extract(img_crop))
    return pred

构建这种「双识别策略」模块,并判断识别置信度决定是否 fallback。

接下来工作:

  • ✅ 实现 classifier 模块

  • ✅ 在 main.py 中接入 fallback 策略

只需上传新猫图即可自动加入特征库,无需重训,非常实用 🐱✨

✅ 分类器模块 classifier.py 已完成,具备以下功能:


🧠 功能说明:

  • 加载你训练好的 cat_classifier.pt

  • 支持图像分类识别猫个体(支持 PIL 或图像路径)

  • 低于置信度阈值(默认 0.6)则输出 "Unknown"

  • 可作为你系统中的主识别器


✅ 下一步我们将:

  • main.py 中整合:

    • 加载 classifier 模块

    • 优先调用 classifier 识别猫

    • 若识别为 "Unknown",则 fallback 到 matcher(最近邻匹配)

🧠 识别策略:

  1. 分类器优先识别 (使用 cat_classifier.pt 模型)

  2. 分类结果低于置信度阈值 → 自动 fallback 到最近邻匹配(matcher

  3. 整体流程稳定灵活,支持动态添加新猫



测试存在问题:

  1. name_map 报错问题:

    我们现在自动从 data/embeddings/ 文件夹名中提取猫名作为分类器的类名,不再依赖 db.name_map

  2. 图片路径问题

    之前错误原因是你传给 embedder.extract() 的是 PIL.Image,但它内部使用 Image.open(),应该接收的是图像路径 。现在我们已经更新为直接传入 PIL.Image 对象,不再走 Image.open(),因此你可以安全使用从视频中裁剪出的猫图进行识别了。

3.未知猫咪

当识别结果为 Unknown 且通过最近邻匹配出猫时:会自动将该猫的特征添加到数据库中(db.add_cat(cat_name, vec))。因此,无需手动上传图像,只要猫在摄像头中被成功识别过一次,系统就会记住它,并在下次更容易识别


python 复制代码
\# main.py(集成分类器 + 匹配器双策略识别 + 日志与失败保存)

import cv2

import time

import numpy as np

from PIL import Image

from recognizer.embedder import CatEmbedder

from recognizer.database import CatDatabase

from recognizer.matcher import CatMatcher

from recognizer.classifier import CatClassifier

from toilet\_logger import ToiletLogger

from ultralytics import YOLO

import os

  

\# 初始化

model \= YOLO("yolov11.pt")

embedder \= CatEmbedder()

db \= CatDatabase()

matcher \= CatMatcher(db)

logger \= ToiletLogger()

  

\# 加载分类器(从 embeddings 文件夹获取类别名)

embedding\_dir \= "data/embeddings"

class\_names \= sorted({name.split("\_", 1)\[1\] for name in os.listdir(embedding\_dir) if os.path.isdir(os.path.join(embedding\_dir, name))})

classifier \= CatClassifier(model\_path\="cat\_classifier.pt", class\_names\=class\_names)

  

\# 摄像头设置

rtsp\_url \= "rtsp://192.168.0.102:554/stream1"

cap \= cv2.VideoCapture(rtsp\_url)

cap.set(cv2.CAP\_PROP\_BUFFERSIZE, 1)

  

\# 如厕区域

TOILET\_REGION \= (100, 100, 400, 400)

cat\_present \= False

entry\_time \= None

cat\_name \= "Unknown"

enter\_img \= ""

✅ 系统现在支持以下功能:


🧠 推理日志保存

  • 每次识别都会写入 recognition_log.txt,包含时间、识别猫名、使用的是分类器 or 匹配器。

📸 识别失败截图保存

  • 当分类器输出为 "Unknown",将截图保存到 web/static/fails/ 目录。

🏷️ 识别来源标记

  • 在画面上显示识别来源(如 Mimi (classifier)Mimi (matcher)

你现在可以查看:

  • recognition_log.txt 查看历史记录

  • web/static/fails/ 看匹配器兜底识别的截图

  • 画面上看到猫名+来源的标注


相关推荐
DragonnAi6 分钟前
基于项目管理的轻量级目标检测自动标注系统【基于 YOLOV8】
人工智能·yolo·目标检测
狗蛋不是狗16 分钟前
Python 实现的运筹优化系统数学建模详解(多目标规划模型)
python·数学建模·优化算法·狗蛋不是狗·多目标规划模型
AI绘画咪酱19 分钟前
【CSDN首发】Stable Diffusion从零到精通学习路线分享
人工智能·学习·macos·ai作画·stable diffusion·aigc
DeepSeek+NAS25 分钟前
耘想WinNAS:以聊天交互重构NAS生态,开启AI时代的存储革命
人工智能·重构·nas·winnas·安卓nas·windows nas
2201_7549184141 分钟前
OpenCv--换脸
人工智能·opencv·计算机视觉
ocr_sinosecu142 分钟前
OCR进化史:从传统到深度学习,解锁文字识别新境界
人工智能·深度学习·ocr
Python私教1 小时前
Java手写链表全攻略:从单链表到双向链表的底层实现艺术
java·python·链表
Stara05111 小时前
YOLO11改进——融合BAM注意力机制增强图像分类与目标检测能力
人工智能·python·深度学习·目标检测·计算机视觉·yolov11
movigo7_dou1 小时前
关于深度学习局部视野与全局视野的一些思考
人工智能·深度学习
itwangyang5201 小时前
AIDD-人工智能药物设计-大语言模型在医学领域的革命性应用
人工智能·语言模型·自然语言处理