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

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


✅ 前情提要


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

已完成工作:

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

计划工作:

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

————————————————


本次将继续制作 实时检测模块
使用 YOLOv11 检测摄像头画面中的猫、判断是否进入指定区域,并调用分类模块识别是哪只猫 🐱📹


✅ 功能目标:

  1. 打开摄像头实时读取画面
  2. 用 YOLOv11 检测猫目标(设定类名为 'cat'
  3. 判断猫是否进入你定义的“如厕区域”(矩形区域)
  4. 如果猫在区域内 → 裁剪猫图 → 提特征 → 分类
  5. 在画面中显示识别结果,并记录状态变化(进入/离开)

🧱 YOLOv11 + 分类实时检测代码(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 ultralytics import YOLO  # 假设你用的是YOLOv8/11格式# 初始化
model = YOLO("yolov11_cat.pt")  # 替换为你的模型路径
embedder = CatEmbedder()
db = CatDatabase()
matcher = CatMatcher(db)# 区域设定(可以做成画图交互)
TOILET_REGION = (100, 100, 400, 400)  # (x1, y1, x2, y2)# 状态跟踪
cat_present = False
entry_time = None# 启动摄像头
cap = cv2.VideoCapture(0)while True:ret, frame = cap.read()if not ret:break# 画如厕区域x1, y1, x2, y2 = TOILET_REGIONcv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 255), 2)# YOLOv11 推理results = model.predict(frame, verbose=False)boxes = results[0].boxesdetected = Falsecat_name = "Unknown"for box in boxes:cls = int(box.cls[0])conf = float(box.conf[0])if cls != 0:  # 类别为猫(根据你的模型调整)continuexmin, ymin, xmax, ymax = map(int, box.xyxy[0])cx, cy = (xmin + xmax) // 2, (ymin + ymax) // 2# 判断猫是否在如厕区域if x1 < cx < x2 and y1 < cy < y2:detected = Truecat_crop = frame[ymin:ymax, xmin:xmax]# 保存临时图片 + 识别猫tmp_path = "tmp.jpg"cv2.imwrite(tmp_path, cat_crop)vec = embedder.extract(tmp_path)cat_name = matcher.match(vec)# 显示识别名cv2.putText(frame, f"{cat_name}", (xmin, ymin - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 200, 0), 2)cv2.rectangle(frame, (xmin, ymin), (xmax, ymax), (0, 255, 0), 2)# 状态变化记录if detected and not cat_present:entry_time = time.time()print(f"🐱 {cat_name} 进入区域")cv2.imwrite(f"records/{cat_name}_enter_{int(entry_time)}.jpg", frame)if not detected and cat_present:exit_time = time.time()duration = round(exit_time - entry_time, 2)print(f"🚪 {cat_name} 离开区域,用时 {duration} 秒")cv2.imwrite(f"records/{cat_name}_leave_{int(exit_time)}.jpg", frame)cat_present = detectedcv2.imshow("Cat Monitor", frame)if cv2.waitKey(1) == 27:  # ESC 退出breakcap.release()
cv2.destroyAllWindows()

📦 依赖库列表:

  • ultralytics (YOLOv8/11)

  • torch, opencv-python, Pillow

  • scikit-learn(用于相似度计算)



✅ 下一步工作:

  1. 用 Flask 做个记录页面,展示:

    • 每次进入/离开的猫咪、时间、如厕时长

    • 保存的截图

  2. 加入状态日志系统(写入 SQLite)


✅ 读取视频流:
可以通过 OpenCV 直接读取 RTSP 流的视频画面,替换掉 cv2.VideoCapture(0) 这一行。


✅ RTSP 摄像头接入方式

假设你的摄像头地址是:

rtsp://192.168.0.102:554/stream1

常见格式有以下几种(具体看你的摄像头厂商手册):

格式类型示例 URL
无用户名密码rtsp://192.168.0.102:554/stream1
有用户名密码rtsp://admin:password@192.168.0.102:554/stream1

如果你不确定 RTSP 路径,可以用 VLC 打开地址测试能否连接。


✅ 替换代码中的摄像头源

# 本地摄像头写法
# cap = cv2.VideoCapture(0)# 替换为 RTSP 摄像头:
cap = cv2.VideoCapture("rtsp://192.168.0.102:554/stream1")

也可以设置超时时间(推荐):

cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)

⚠️ 注意事项:

  1. 防火墙:确保你的电脑和摄像头在同一局域网,且摄像头开放了 RTSP 服务。

  2. 稳定性:RTSP 会有卡顿或断流情况,建议加重连逻辑(稍后我们可以加)。

  3. 帧率延迟:默认 RTSP 有延迟,可尝试减少缓冲提高实时性。


✅ 示例(完整替换一行即可)

cap = cv2.VideoCapture("rtsp://192.168.0.102:554/stream1")

模型使用:

现在没有收集足够多的猫咪图片,就先使用 YOLOv11 COCO 官方权重(基于 YOLOv8 推理架构),但是只想检测 cat 类别(class id = 15)。我们有两个解决方案:


✅ 方案一:在推理结果中筛选 cat 类别

这是最简单的方法,无需重新训练模型,只在代码里过滤掉非猫类目标。

✅ 修改你的检测代码:

results = model.predict(frame, verbose=False)
boxes = results[0].boxesfor box in boxes:cls = int(box.cls[0])conf = float(box.conf[0])if cls != 15:  # COCO 中 cat 是类别15continue# 保留 cat 类的后续逻辑...

你也可以打印类别名验证一下:

from ultralytics.utils import ops
print(ops.ANCHOR_ORDER)  # 也可以用 model.names[cls] 打印类别名

✅ 方案二:导出只含猫的 YOLOv11 模型(可选,后续更新)

如果你未来希望模型体积更小、推理更快:

  1. 用 COCO 数据集中只包含 cat 的部分训练模型(或 fine-tune)。

  2. 自定义 data.yaml:

names: ['cat']
nc: 1
  1. 训练模型:
yolo detect train data=cat.yaml model=yolov11.pt epochs=50 imgsz=640

然后就能得到一个“只识别猫”的轻量化模型了。


网络摄像头检测推理错误

[h264 @ 00000218ddca2b00] error while decoding MB 94 41, bytestream -5

表示 OpenCV(底层用 ffmpeg)在解析 RTSP 摄像头的视频流时,遇到了 H.264 视频帧解码错误。这种问题在使用 RTSP 摄像头时很常见,通常是由以下原因引起的:


❗ 常见原因分析:

1. 网络不稳定 / 丢帧

  • RTSP 是实时流协议,稍有波动就可能导致数据不完整。

  • 解码器(H.264)收到了不完整的数据,无法正确解码宏块(Macroblock)。

2. 摄像头编码质量太低 / 不兼容

  • 某些低端摄像头输出的 RTSP H.264 数据流存在兼容问题。

3. 缓冲区设置不当(OpenCV 默认大延迟)

  • OpenCV 默认有较大的缓冲,容易产生过时帧或卡顿,进而出错。

✅ 解决方案


✅ 方法 1:设置 OpenCV 缓冲区为 1(强烈推荐及采用)

cap = cv2.VideoCapture("rtsp://192.168.0.102:554/stream1")
cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)

✅ 方法 2:改用 ffmpeg 直接拉流更稳定(通过 subprocessimageio

如果 OpenCV 解码不稳定,可以尝试用 ffmpeg 拉流 + pipe 给 Python 处理。


✅ 方法 3:尝试切换 RTSP 子码流(sub stream)

大多数摄像头有主码流(1080p)和子码流(D1 / CIF):

  • 主码流可能过大、丢帧严重

  • 可尝试地址类似:

    rtsp://192.168.0.102:554/sub
    rtsp://192.168.0.102:554/live/ch0_1  ← 子码流
    

✅ 方法 4:尝试加参数或禁用 HW 加速(ffmpeg flags)

可通过设置更强容错的方式读取(但这需要更底层控制)。


🧪 调试策略

import cv2rtsp_url = "rtsp://192.168.0.102:554/stream1"
cap = cv2.VideoCapture(rtsp_url)
cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)if not cap.isOpened():print("❌ 无法连接摄像头")exit()while True:ret, frame = cap.read()if not ret:print("❌ 帧读取失败,跳过")continuecv2.imshow("RTSP", frame)if cv2.waitKey(1) == 27:break

✅ 总结建议:

方式说明
set(CAP_PROP_BUFFERSIZE, 1)✅ 首选,缓解延迟和丢帧问题
检查 RTSP 子码流地址可大幅提升兼容性
尝试更稳定解码方式(如 GStreamer)高级稳定需求下可选

cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
可以先加上上述代码试试是否缓解问题。如果问题仍然频繁,我们可以换 ffmpegGStreamer 拉流方式,我也可以帮你整合好。

窗口尺寸调整:

好的,如果用 OpenCVcv2.imshow() 来显示摄像头窗口,可以通过 缩放帧的尺寸 来控制窗口大小。


✅ 方法:缩放图像再显示

在你显示前加一行缩放代码,比如缩放为 640x480:

# 假设 frame 是读取的图像
resized_frame = cv2.resize(frame, (640, 480))  # 你也可以用 (960, 720) 或其他分辨率
cv2.imshow("Cat Monitor", resized_frame)

✅ 推荐方式(根据原图比例缩小)

如果你想“等比例缩放”,比如缩小为原来的 0.5 倍:

scale = 0.5
h, w = frame.shape[:2]
resized_frame = cv2.resize(frame, (int(w * scale), int(h * scale)))
cv2.imshow("Cat Monitor", resized_frame)

✅ 如果你想让窗口是“可拉伸的”

还可以配合 cv2.namedWindow 控制窗口样式:

cv2.namedWindow("Cat Monitor", cv2.WINDOW_NORMAL)
cv2.resizeWindow("Cat Monitor", 640, 480)

这允许你手动调整窗口大小。


✅ 已完成模块回顾

模块状态说明
猫咪录入支持多张猫脸图批量上传、特征提取和保存
猫咪识别最近邻相似度匹配分类
YOLOv11 + 摄像头实时检测猫是否进入区域并识别是哪只猫
区域判断判断猫是否进入指定如厕区域
RTSP 支持已支持 RTSP 摄像头接入(192.168.0.102)
窗口缩放图像缩放显示已支持

✅ 运行说明

cd cat_monitor/web
python app.py
  1. 浏览器访问:
http://127.0.0.1:5000/

✅ 已完成模块回顾

模块状态说明
猫咪录入支持多张猫脸图批量上传、特征提取和保存
猫咪识别最近邻相似度匹配分类
YOLOv11 + 摄像头实时检测猫是否进入区域并识别是哪只猫
区域判断判断猫是否进入指定如厕区域
RTSP 支持已支持 RTSP 摄像头接入(192.168.0.102)
窗口缩放图像缩放显示已支持

相关文章:

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

✅ 前情提要 家里养了三只猫咪&#xff0c;其中一只布偶猫经常出入厕所。但因为平时忙于学业&#xff0c;没法时刻关注牠的行为。我知道猫咪的如厕频率和时长与健康状况密切相关&#xff0c;频繁如厕可能是泌尿问题&#xff0c;停留过久也可能是便秘或不适。为了更科学地了解牠…...

sql server 字段逗号分割取后面的值

在 SQL Server 中&#xff0c;如果你有一个字段&#xff08;字段类型通常是字符串&#xff09;&#xff0c;其中包含用逗号分隔的值&#xff0c;并且你想提取这些值中逗号后面的特定部分&#xff0c;你可以使用多种方法来实现这一点。这里我将介绍几种常见的方法&#xff1a; …...

FPGA 37 ,FPGA千兆以太网设计实战:RGMII接口时序实现全解析( RGMII接口时序设计,RGMII~GMII,GMII~RGMII 接口转换 )

目录 前言 一、设计流程 1.1 需求理解 1.2 模块划分 1.3 测试验证 二、模块分工 2.1 RGMII→GMII&#xff08;接收方向&#xff0c;rgmii_rx 模块&#xff09; 2.2 GMII→RGMII&#xff08;发送方向&#xff0c;rgmii_tx 模块&#xff09; 三、代码实现 3.1 顶层模块 …...

上篇:《排序算法的奇妙世界:如何让数据井然有序?》

个人主页&#xff1a;strive-debug 排序算法精讲&#xff1a;从理论到实践 一、排序概念及应用 1.1 基本概念 **排序**&#xff1a;将一组记录按照特定关键字&#xff08;如数值大小&#xff09;进行递增或递减排列的操作。 1.2 常见排序算法分类 - **简单低效型**&#xff…...

红宝书第三十四讲:零基础学会单元测试框架:Jest、Mocha、QUnit

红宝书第三十四讲&#xff1a;零基础学会单元测试框架&#xff1a;Jest、Mocha、QUnit 资料取自《JavaScript高级程序设计&#xff08;第5版&#xff09;》。 查看总目录&#xff1a;红宝书学习大纲 一、单元测试是什么&#xff1f; 就像给代码做“体检”&#xff0c;帮你检查…...

【JDBC-54.1】MySQL JDBC连接字符串常用参数详解

在Java应用程序中连接MySQL数据库时&#xff0c;JDBC连接字符串是建立连接的关键。一个配置得当的连接字符串不仅能确保连接成功&#xff0c;还能优化性能、增强安全性并处理各种连接场景。本文将深入探讨MySQL JDBC连接字符串的常用参数及其最佳实践。 1. 基本连接字符串格式…...

swagger 注释说明

一、接口注释核心字段 在 Go 的路由处理函数&#xff08;Handler&#xff09;上方添加注释&#xff0c;支持以下常用注解&#xff1a; 注解名称用途说明示例格式Summary接口简要描述Summary 创建用户Description接口详细说明Description 通过用户名和邮箱创建新用户Tags接口分…...

CST1019.基于Spring Boot+Vue智能洗车管理系统

计算机/JAVA毕业设计 【CST1019.基于Spring BootVue智能洗车管理系统】 【项目介绍】 智能洗车管理系统&#xff0c;基于 Spring Boot Vue 实现&#xff0c;功能丰富、界面精美 【业务模块】 系统共有三类用户&#xff0c;分别是&#xff1a;管理员用户、普通用户、工人用户&…...

【前端网络请求】XHR封装,支持文件上传、进度监控、混合字段传输

网络请求介绍 XMLHttpRequest(XHR)是前端开发中用于发起网络请求的基础技术。虽然现代开发中常用fetch或axios,但掌握XHR的封装技巧仍能让你更灵活地应对复杂需求。本文将通过一个可复用、功能全面的XHR封装工具,教你实现以下功能: 📤 文件上传(单个/多个文件)📊 实…...

# Shell脚本参数设计规范(DeepSeek指导)

Shell脚本参数设计规范&#xff08;DeepSeek指导&#xff09; 文章目录 Shell脚本参数设计规范&#xff08;DeepSeek指导&#xff09;A 我问&#xff1a;Q DeepSeek回答&#xff1a;**命令行参数表示规范****标准化表示示例**情况1&#xff1a;必选选项参数值情况2&#xff1a;…...

学习SqlSugar的跨库查询基本用法

使用SqlSugar操作数据库通常都是单库操作&#xff0c;跨库查询的情况要么是单个系统数据不完整&#xff0c;需要其它系统的关联业务数据支撑&#xff0c;要么就是需要整合汇总多个系统的数据进行数据数据分析、处理、展示。遇到上述情况&#xff0c;可以要求另外的系统提供查询…...

HTTP:五.WEB服务器

web服务器 定义:实现提供资源或应答的提供者都可以谓之为服务器!web服务器工作内容 接受建立连接请求 接受请求 处理请求 访问报文中指定的资源 构建响应 发送响应 记录事务处理过程 Web应用开发用到的一般技术元素 静态元素:html, img,js,Css,SWF,MP4 动态元素:PHP,…...

5.3 GitHub订阅系统核心架构解密:高并发设计与SQLite优化实战

GitHub Sentinel 分析报告功能实现:订阅管理核心逻辑解析 关键词:GitHub API 订阅管理, SQLite 数据库设计, RESTful API 开发, 原子操作封装, 异常处理机制 1. 订阅管理功能架构设计 订阅管理模块采用分层架构设计,通过清晰的接口隔离实现高内聚低耦合: #mermaid-svg-bW…...

CSI-PVController-volumeWorker

volumeWorker() 与claim worker流程一样&#xff0c;从volumeQueue中取数据&#xff0c;也就是取出的都是PV&#xff0c;如果informer中有这个pv&#xff0c;就进入update流程。 定义workFunc&#xff1a;首先&#xff0c;定义了一个匿名函数workFunc&#xff0c;这个函数是实…...

0基础 | 硬件滤波 C、RC、LC、π型

一、滤波概念 &#xff08;一&#xff09;滤波定义 滤波是将信号中特定波段频率滤除的操作&#xff0c;是抑制和防止干扰的重要措施。通过滤波器实现对特定频率成分的筛选&#xff0c;确保目标信号的纯净度&#xff0c;提升系统稳定性。 &#xff08;二&#xff09;滤波器分…...

图论基础理论

在我看来&#xff0c;想要掌握图的基础应用&#xff0c;仅需要三步走。 什么是图&#xff08;基本概念&#xff09;、图的构造&#xff08;打地基&#xff09;、图的遍历方式&#xff08;应用的基础&#xff09; 只要能OK的掌握这三步、就算图论入门了&#xff01;&#xff0…...

leaflet 之 获取中国某个行政区的经纬度边界(latLngBounds)

思路 在json文件中获取下面的四个点 组成东北,西南两组 { “southwest”: { “lat”: 35.950, “lng”: 120.000 },//西南方 “northeast”: { “lat”: 36.200, “lng”: 120.300 }//东北方 } 最西点经度&#xff08;minLng&#xff09; 最东点经度&#xff08;maxLng&#x…...

企业级低代码平台的架构范式转型研究

在快速迭代的数字时代&#xff0c;低代码平台如同一股清流&#xff0c;悄然成为开发者们的新宠。 它利用直观易用的拖拽式界面和丰富的预制组件&#xff0c;将应用程序的开发过程简化到了前所未有的程度。通过封装复杂的编程逻辑和提供强大的集成能力&#xff0c;低代码平台让…...

怎么免费下载GLTF/GLB格式模型文件,还可以在线编辑修改

​ 现在非常流行glb格式模型&#xff0c;和gltf格式文件&#xff0c;可是之类模型网站非常非常少 1&#xff0c;咱们先直接打开http://glbxz.com 官方glb下载网站 glbxz.com 2 可以搜索&#xff0c;自己想要的模型关键词 3&#xff0c;到自己想下载素材页面 4&#xff0c;…...

MyBatis 中 Mapper 传递参数的多种方法

# MyBatis Mapper 传递参数的多种方法及其优势 在使用 MyBatis 进行数据库操作时&#xff0c;Mapper 接口的参数传递是一个非常基础但又十分重要的部分。不同的参数传递方式适用于不同的场景&#xff0c;合理选择可以大大提高代码的可读性和维护性。本文将详细介绍几种常见的 …...

大模型到底是怎么产生的?一文揭秘大模型诞生全过程

前言 大模型到底是怎么产生的呢? 本文将从最基础的概念开始,逐步深入,用通俗易懂的语言为大家揭开大模型的神秘面纱。 大家好,我是大 F,深耕AI算法十余年,互联网大厂核心技术岗。 知行合一,不写水文,喜欢可关注,分享AI算法干货、技术心得。 【专栏介绍】: 欢迎关注《…...

2025年3月 Scratch图形化三级 真题解析 中国电子学会全国青少年软件编程等级考试

2025年3月Scratch图形化编程等级考试三级真题试卷 一、选择题 第 1 题 默认小猫角色&#xff0c;scratch运行程序后&#xff0c;下列说法正确的是&#xff1f;&#xff08; &#xff09; A.小猫的颜色、位置在一直变化 B.小猫在舞台中的位置在一直变化&#xff0c;颜色…...

判断两个 IP 地址是否在同一子网 C

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> // 将点分十进制的 IP 地址转换为 32 位无符号整数 unsigned int ip_to_uint(const char *ip) { struct in_addr addr; if (inet_pton(AF_INET, ip, &am…...

DHCP中继

前言&#xff1a; DHCP Relay即DHCP中继&#xff0c;它是为解决DHCP服务器和DHCP客户端不在同一个广播域而提出的 DHCP中继 DHCP协议依赖广播通信&#xff08;如客户端发送DHCP Discover报文&#xff09;&#xff0c;但广播报文无法跨越子网&#xff0c;因为&#xff1a; 路由…...

02 - spring security基于配置文件及内存的账号密码

spring security基于配置的账号密码 文档 00 - spring security框架使用01 - spring security自定义登录页面 yml文件中配置账号密码 spring:security:user:name: adminpassword: 123456yml文件中配置账号密码后&#xff0c;控制台将不再输出临时密码 基于内存的账号密码 …...

【贪心之摆动序列】

题目&#xff1a; 分析&#xff1a; 这里我们使用题目中给的第二个实例来进行分析 题目中要求我们序列当中有多少个摆动序列&#xff0c;摆动序列满足一上一下&#xff0c;一下一上&#xff0c;这样是摆动序列&#xff0c;并且要输出摆动序列的最长长度 通过上面的图我们可以…...

Spring Boot 中应用的设计模式

Spring Boot 中应用的设计模式详解 Spring Boot 作为 Spring 框架的扩展&#xff0c;广泛使用了多种经典设计模式。以下是主要设计模式及其在 Spring Boot 中的具体应用&#xff1a; 一、创建型模式 1. 工厂模式 (Factory Pattern) 应用场景&#xff1a; BeanFactory 和 Ap…...

0x25广度优先搜索+0x26广搜变形

1.一般bfs AcWing 172. 立体推箱子 #include<bits/stdc.h> using namespace std; int n,m; char s[505][505]; int vis[3][505][505]; int df[3][4]{{1,1, 2,2},{0,0,1,1}, {0,0,2,2}}; int dx[3][4]{{0,0,1,-2},{0,0,1,-1},{2,-1,0,0}}; int dy[3][4]{{1,-2,0,0},{2,…...

java面向对象02:回顾方法

回顾方法及加深 定义方法 修饰符 返回类型 break&#xff1a;跳出switch和return的区别 方法名 参数列表 package com.oop.demo01;//Demo01类 public class Demo01 {//main方法public static void main(String[] args) {}/*修饰符 返回值类型 方法名(...){//方法体return…...

数据结构day05

一 栈的应用&#xff08;括号匹配&#xff09; 各位同学大家好&#xff0c;在之前的小结中&#xff0c;我们学习了栈和队列这两种数据结构&#xff0c;那从这个小节开始&#xff0c;我们要学习几种栈和队列的典型应用。这个小节中&#xff0c;我们来看一下括号匹配问题&#xf…...