
1. 项目概述当门铃遇上机器学习最近在捣鼓智能家居总想着怎么让家里的设备更“聪明”一点。传统的智能门铃能推送个“有人按铃”的通知但也就到此为止了。我在想能不能更进一步比如门外站的是快递员、邻居还是家人能不能根据这个信息自动触发不同的后续动作比如是快递员就发条短信到手机是家人就自动开门锁是陌生人就持续录像并发出本地警报。这个想法让我开始研究如何构建一个机器学习驱动的门铃通知器。这个项目的核心就是给普通的门铃摄像头或门铃按钮装上“大脑”。它不再仅仅是一个被动的传感器而是一个能理解“谁在门外”的智能终端。实现路径很清晰通过摄像头捕捉图像或视频流利用一个训练好的机器学习模型进行实时分析识别出访客的身份或类型最后通过一个灵活的通知系统将结构化的信息而不仅仅是“有动静”推送到你的手机或其他智能设备上。整个过程从图像采集、模型推理到消息推送可以完全运行在树莓派这类低成本硬件上打造一个完全私有的、不依赖云服务的智能门铃系统。听起来有点复杂别担心我会把整个搭建过程掰开揉碎从硬件选型、软件环境配置、模型选择与优化到最终的集成与部署一步步带你走完。无论你是机器学习的新手还是有一定嵌入式开发经验的爱好者都能跟着这个指南亲手打造一个属于自己的、真正智能的“看门人”。2. 项目整体设计与思路拆解在动手写代码和接线之前我们需要把整个系统的蓝图规划清楚。一个健壮的ML门铃通知器绝不是简单地把几个开源库拼在一起其背后的设计思路决定了系统的可靠性、实时性和可维护性。2.1 核心架构与数据流整个系统遵循“边缘计算”的理念尽可能在设备端完成所有计算这既能保护隐私视频数据不出家门又能降低对网络延迟的依赖。我设计的核心数据流如下触发与采集门铃按钮被按下或运动传感器检测到门前有人这个事件作为系统启动的触发器。摄像头随即捕获一张高清图片或一段短视频。这里有个关键选择是拍照片还是录视频对于身份识别一张高质量的静态图片通常足够且处理速度更快、计算资源占用更少。因此我推荐使用“单次高质量抓拍”模式。预处理与推理抓拍到的原始图像会经过一系列预处理如调整尺寸以匹配模型输入、归一化像素值、可能还需要进行人脸检测与对齐如果专注于识别人。处理后的图像被送入预先加载的机器学习模型。模型输出可能是一个标签如“快递员”、“朋友”、“陌生人”也可能是一组置信度分数。决策与通知系统根据模型的输出结果做出决策。例如如果识别为“快递员”且置信度高于90%则执行“快递员流程”向手机发送一条包含识别结果的推送通知并可能附带抓拍图片。同时可以触发家庭自动化平台如Home Assistant的“快递已送达”场景自动点亮门口灯。如果识别为“陌生人”且置信度较高则可能触发更高级别的警报流程。日志与反馈所有事件、识别结果和图片都应被安全地存储在本地设备如接入的USB硬盘或家庭服务器上形成一个可查询的访问日志。一个高级功能是加入反馈循环如果系统识别错误你可以通过一个简单的界面如网页按钮进行纠正这个纠正后的数据可以用来在未来进一步微调模型让它越来越准。这个架构的优势在于模块化。每个环节采集、推理、通知都可以独立升级或替换。比如今天你用YOLO做目标检测明天可以换更快的模型今天用Telegram Bot发通知明天可以集成到企业微信。2.2 硬件选型背后的考量硬件是项目的基石选型不当会直接导致项目失败。以下是经过实际踩坑后总结的选型清单与理由主控板大脑首选树莓派 4B (4GB/8GB RAM) 或 树莓派 5。理由社区支持极其强大有完善的CSI摄像头接口性能足够运行轻量级ML模型功耗低7x24小时运行稳定。树莓派5的GPU和NPU更强对于模型推理有显著加速。备选英伟达 Jetson Nano。理由GPU性能更强专为边缘AI设计运行复杂的视觉模型更有优势。但成本更高功耗和发热也更大社区资源相对树莓派少一些。避坑提示绝对不要用树莓派Zero或3B以下型号它们的算力难以胜任实时图像推理你会被漫长的处理时间逼疯。摄像头眼睛首选树莓派官方CSI摄像头模块如Camera Module 3。理由通过CSI总线直接连接延迟极低图像质量好由树莓派基金会直接驱动支持最稳定可靠。Camera Module 3还带自动对焦和HDR适应不同光线条件。备选兼容树莓派的USB摄像头。理由选择多可能带有夜视功能。但需注意选择免驱的UVC协议摄像头并且USB传输和压缩会引入微小延迟并占用CPU资源。关键参数分辨率至少1080p帧率在抓拍模式下不重要但要有较好的低光性能。广角镜头能覆盖更大的门前区域。门铃触发器启动开关方案A智能无线门铃按钮。购买一个支持射频或Wi-Fi的无线门铃按钮将其信号接收器与树莓派的GPIO引脚连接。当按钮被按下接收器输出高/低电平树莓派通过监听GPIO状态变化来触发程序。这是对现有门铃最无缝的改造。方案B运动传感器PIR。将HC-SR501这类人体红外传感器安装在门侧当检测到运动时触发。缺点是容易误报比如宠物、晃动的树枝。方案C纯视觉触发。使用一个非常轻量级的模型如MobileNet SSD持续分析低分辨率视频流只检测“人”是否出现出现后再触发高清抓拍和详细识别。这最智能但对算力有持续要求。我的选择我采用了方案A方案C结合。无线门铃按钮作为主触发确保每次按铃都能捕获同时在非按铃时段以低功耗模式运行一个微型运动检测模型用于记录门前异常徘徊等安全事件。其他一张高速MicroSD卡用于系统、一个稳定的5V/3A电源、一个散热外壳长期运行必备、可能还需要一个继电器模块如果你打算用树莓派直接控制传统的“叮咚”门铃响器。3. 软件环境搭建与核心工具链硬件准备就绪后我们需要为其安装“灵魂”——软件。这一部分我会详细说明操作系统、编程环境、关键库的安装与配置其中包含大量命令行操作请一步步跟随。3.1 操作系统与基础环境我强烈推荐使用Raspberry Pi OS (64-bit) Lite版本。它没有图形界面资源占用极低所有操作通过SSH进行非常适合跑长期服务。如果你不熟悉命令行可以先从桌面版开始但最终部署时建议换到Lite版。刷写系统使用Raspberry Pi Imager工具刷写系统到SD卡。在刷写前Imager工具允许你进行高级设置预配Wi-Fi、开启SSH、设置主机名和密码。务必在此处完成这些设置这能让你在无显示器、无键盘的情况下启动并连接树莓派。首次启动与更新插入SD卡上电。通过路由器管理界面找到树莓派的IP地址使用SSH客户端如PuTTY或终端连接。ssh pi你的树莓派IP登录后第一件事就是更新系统sudo apt update sudo apt upgrade -y sudo apt install -y git vim python3-pip python3-venv创建Python虚拟环境这是一个好习惯可以避免包依赖冲突。mkdir ~/doorbell_project cd ~/doorbell_project python3 -m venv venv source venv/bin/activate # 看到命令行提示符前出现 (venv) 即表示激活成功3.2 机器学习框架与视觉库选型这是项目的核心。我们需要一个既能高效运行在边缘设备上又易于使用的ML框架。TensorFlow Lite / PyTorch Mobile它们是移动和嵌入式设备的首选。TFLite的模型生态和部署工具链非常成熟。PyTorch Mobile则更受研究社区欢迎。我选择TensorFlow Lite因为其运行时更小对树莓派的官方支持更好并且有大量预训练好的、适用于边缘设备的视觉模型如MobileNet, EfficientNet-Lite。OpenCV计算机视觉的“瑞士军刀”用于图像捕获、预处理缩放、裁剪、色彩转换、显示和简单的人脸检测。必不可少。具体安装命令在虚拟环境中# 安装OpenCV。树莓派上从源码编译OpenCV极其耗时推荐使用预编译的wheel包。 # 访问 https://github.com/opencv/opencv-python 找到适合你Python版本和系统的预编译版本链接。 # 例如对于64位系统 pip install opencv-python-headless # headless版本不含GUI库更节省空间 # 安装TensorFlow Lite运行时和解释器 pip install tflite-runtime # 如果你需要用到一些TensorFlow工具来转换模型也可以安装完整的tensorflow-cpu但较重 # pip install tensorflow-cpu2.13.0 # 请确认版本兼容性 # 安装其他工具库 pip install pillow requests numpy注意在树莓派上直接pip install tensorflow会尝试安装完整的TensorFlow其中包含大量不兼容的依赖极易失败。tflite-runtime是一个精简的、仅用于推理的包是官方推荐的在边缘设备上使用TFLite的方式。3.3 模型获取与部署从通用到专属我们不可能从头训练一个识别“快递员”的模型。正确的方法是迁移学习使用一个在大规模数据集如ImageNet上预训练好的、能识别上千种物体的通用模型然后针对我们的特定任务识别几类访客进行微调。选择预训练模型对于树莓派我们需要“轻量级”模型。谷歌的MobileNetV2或EfficientNet-Lite系列是绝佳选择。它们专为移动和边缘设备设计在精度和速度之间取得了很好的平衡。你可以从TensorFlow官方模型库TensorFlow Hub或TFLite模型库下载预训练的.tflite文件。微调Fine-tuning你自己的模型进阶数据收集这是最耗时但最关键的一步。你需要收集数百张包含“快递员”、“邻居”、“家人”、“陌生人”可泛指其他等类别的门前照片。确保在不同时间、不同光线、不同角度下拍摄并且人物穿着不同服装。务必注意隐私只能使用你自己有权使用的照片或从公开数据集中获取。使用Google Colab进行训练在Colab的免费GPU环境下我们可以快速进行微调。流程是下载预训练模型不含顶层分类层添加新的、适合你类别数量的顶层然后用你的数据集训练这个新顶层。模型转换与量化训练完成后将模型转换为TFLite格式。最关键的一步是量化Quantization。它将模型权重从32位浮点数转换为8位整数模型大小会缩小至1/4推理速度提升2-3倍而精度损失通常很小1%。使用TFLite转换器可以轻松完成。# 这是一个在Colab中转换和量化的简化示例 import tensorflow as tf # 加载你的已训练Keras模型 model tf.keras.models.load_model(my_fine_tuned_model.h5) # 创建转换器 converter tf.lite.TFLiteConverter.from_keras_model(model) # 启用默认优化包含量化等 converter.optimizations [tf.lite.Optimize.DEFAULT] # 转换模型 tflite_model converter.convert() # 保存 with open(doorbell_model_quantized.tflite, wb) as f: f.write(tflite_model)将模型部署到树莓派将生成的.tflite文件通过SCP传输到树莓派的项目目录下。同时你需要一个包含标签的文本文件如labels.txt内容像这样0 快递员 1 邻居 2 家人 3 陌生人4. 核心代码实现与系统集成有了模型和硬件现在我们来编写让一切运转起来的“胶水”代码。我将分模块讲解并提供可直接使用的代码片段。4.1 图像捕获与预处理模块这个模块负责在触发事件发生时拍下一张清晰可用的照片。# capture.py import cv2 import time from datetime import datetime import os class DoorbellCamera: def __init__(self, camera_index0, resolution(1920, 1080)): # 对于CSI摄像头可能需要指定GStreamer管道这里用简单模式 self.cap cv2.VideoCapture(camera_index) if not self.cap.isOpened(): raise RuntimeError(无法打开摄像头) self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, resolution[0]) self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, resolution[1]) # 让摄像头稳定一下 time.sleep(2) self.image_save_path ./captured_images def capture_image(self): 捕获一张图片并保存 ret, frame self.cap.read() if not ret: print(捕获图像失败) return None # 生成文件名 timestamp datetime.now().strftime(%Y%m%d_%H%M%S) filename f{self.image_save_path}/doorbell_{timestamp}.jpg os.makedirs(self.image_save_path, exist_okTrue) # 保存原始图片 cv2.imwrite(filename, frame) print(f图像已保存: {filename}) # 返回图像供后续处理 return frame def preprocess_for_model(self, image, target_size(224, 224)): 将图像预处理为模型输入格式 # 调整大小 img_resized cv2.resize(image, target_size) # 从BGR转换为RGB (OpenCV默认是BGR模型通常需要RGB) img_rgb cv2.cvtColor(img_resized, cv2.COLOR_BGR2RGB) # 归一化到 [0, 1] 或模型要求的范围这里假设模型需要[0,1] img_normalized img_rgb / 255.0 # 添加批次维度 (从 H,W,C 变为 1,H,W,C) img_input img_normalized.reshape(1, target_size[1], target_size[0], 3) # 转换为float32 img_input img_input.astype(float32) return img_input def cleanup(self): self.cap.release()实操心得cv2.VideoCapture在树莓派上有时打开很慢或失败。对于CSI摄像头一个更稳定的方法是使用picamera2库如果使用旧的Bullseye系统则是picamera。但picamera2的API与OpenCV略有不同。我建议先尝试OpenCV如果遇到问题再切换到picamera2。4.2 模型推理模块这个模块加载TFLite模型并对预处理后的图像进行推理。# inference.py import numpy as np import tflite_runtime.interpreter as tflite class DoorbellModel: def __init__(self, model_path./models/doorbell_model_quantized.tflite, label_path./models/labels.txt): # 加载TFLite模型并分配张量 self.interpreter tflite.Interpreter(model_pathmodel_path) self.interpreter.allocate_tensors() # 获取输入输出详情 self.input_details self.interpreter.get_input_details() self.output_details self.interpreter.get_output_details() # 通常输入是 [1, height, width, 3] self.input_shape self.input_details[0][shape] self.height, self.width self.input_shape[1], self.input_shape[2] # 加载标签 with open(label_path, r) as f: self.labels [line.strip().split( , 1)[1] for line in f.readlines()] def predict(self, preprocessed_image): 对预处理后的图像进行预测 # 设置输入张量 self.interpreter.set_tensor(self.input_details[0][index], preprocessed_image) # 运行推理 self.interpreter.invoke() # 获取输出 output_data self.interpreter.get_tensor(self.output_details[0][index]) # output_data 形状通常是 [1, num_classes] predictions output_data[0] # 获取最高置信度的类别和分数 predicted_class_idx np.argmax(predictions) confidence predictions[predicted_class_idx] predicted_label self.labels[predicted_class_idx] return predicted_label, confidence, predictions4.3 通知与动作触发模块识别出结果后我们需要通知用户并触发智能家居动作。这里以发送Telegram消息和调用Home Assistant的Webhook为例。# notifier.py import requests import json from datetime import datetime class Notifier: def __init__(self, config): self.telegram_bot_token config.get(telegram_bot_token) self.telegram_chat_id config.get(telegram_chat_id) self.home_assistant_url config.get(home_assistant_url) self.home_assistant_token config.get(home_assistant_token) def send_telegram(self, message, image_pathNone): 发送Telegram通知 if not self.telegram_bot_token: return False if image_path: # 发送带图片的消息 url fhttps://api.telegram.org/bot{self.telegram_bot_token}/sendPhoto files {photo: open(image_path, rb)} data {chat_id: self.telegram_chat_id, caption: message} resp requests.post(url, filesfiles, datadata) else: # 发送纯文本消息 url fhttps://api.telegram.org/bot{self.telegram_bot_token}/sendMessage data {chat_id: self.telegram_chat_id, text: message} resp requests.post(url, datadata) return resp.status_code 200 def trigger_home_assistant(self, event_type, dataNone): 触发Home Assistant自动化 if not self.home_assistant_url or not self.home_assistant_token: return False url f{self.home_assistant_url}/api/events/{event_type} headers { Authorization: fBearer {self.home_assistant_token}, Content-Type: application/json } payload data or {} resp requests.post(url, headersheaders, jsonpayload) return resp.status_code 200 def notify(self, label, confidence, image_path): 根据识别结果发送通知 timestamp datetime.now().strftime(%H:%M:%S) message f 门铃通知 {timestamp}\n识别结果: **{label}**\n置信度: {confidence:.2%} # 基础通知 self.send_telegram(message, image_path) # 基于标签的智能联动 if label 快递员 and confidence 0.85: self.send_telegram( 检测到快递员已触发‘快递到家’场景。, image_path) self.trigger_home_assistant(doorbell_delivery, {visitor: courier}) elif label 陌生人 and confidence 0.7: self.send_telegram(⚠️ 检测到陌生人请注意, image_path) self.trigger_home_assistant(doorbell_stranger, {visitor: stranger}) elif label 家人: self.trigger_home_assistant(doorbell_family, {visitor: family}) # 可以不开手机通知或者只发一个安静的通知4.4 主循环与事件监听最后我们需要一个主程序来把所有模块串联起来并监听门铃触发事件。# main.py import time import RPi.GPIO as GPIO from capture import DoorbellCamera from inference import DoorbellModel from notifier import Notifier import config # 一个单独的配置文件存放token、路径等 def setup_gpio(): 设置GPIO监听门铃按钮信号 GPIO.setmode(GPIO.BCM) BUTTON_PIN 17 # 假设无线门铃接收器输出接在GPIO17 GPIO.setup(BUTTON_PIN, GPIO.IN, pull_up_downGPIO.PUD_UP) # 启用内部上拉电阻 def button_callback(channel): print(门铃被按响) # 这里不能直接进行耗时操作可以设置一个事件标志 global doorbell_pressed doorbell_pressed True GPIO.add_event_detect(BUTTON_PIN, GPIO.FALLING, callbackbutton_callback, bouncetime300) return BUTTON_PIN def main(): print(启动智能门铃系统...) # 初始化组件 camera DoorbellCamera() model DoorbellModel() notifier Notifier(config.NOTIFIER_CONFIG) # 设置GPIO setup_gpio() global doorbell_pressed doorbell_pressed False print(系统就绪等待门铃触发...) try: while True: if doorbell_pressed: print(处理门铃事件...) # 1. 捕获图像 original_image camera.capture_image() if original_image is None: time.sleep(1) doorbell_pressed False continue # 2. 预处理 processed_image camera.preprocess_for_model(original_image) # 3. 推理 label, confidence, _ model.predict(processed_image) print(f识别结果: {label} (置信度: {confidence:.2%})) # 4. 通知 (这里需要传递图片路径capture_image方法需返回路径) image_path f./captured_images/doorbell_{int(time.time())}.jpg cv2.imwrite(image_path, original_image) # 临时保存 notifier.notify(label, confidence, image_path) # 5. 重置标志 doorbell_pressed False print(事件处理完毕。) time.sleep(0.1) # 短暂休眠降低CPU占用 except KeyboardInterrupt: print(程序被用户中断) finally: GPIO.cleanup() camera.cleanup() print(系统已清理退出。) if __name__ __main__: main()5. 部署、优化与问题排查代码写好了但让它在树莓派上稳定、高效地7x24小时运行又是另一回事。5.1 系统服务化与开机自启我们不能总在SSH终端里运行python main.py。我们需要将其变为一个系统服务。创建服务文件sudo vim /etc/systemd/system/smart-doorbell.service写入以下内容根据你的实际路径修改[Unit] DescriptionSmart ML Doorbell Notifier Afternetwork.target [Service] Typesimple Userpi WorkingDirectory/home/pi/doorbell_project EnvironmentPATH/home/pi/doorbell_project/venv/bin ExecStart/home/pi/doorbell_project/venv/bin/python /home/pi/doorbell_project/main.py Restartalways RestartSec10 StandardOutputsyslog StandardErrorsyslog SyslogIdentifiersmart-doorbell [Install] WantedBymulti-user.target启用并启动服务sudo systemctl daemon-reload sudo systemctl enable smart-doorbell.service sudo systemctl start smart-doorbell.service查看服务状态和日志sudo systemctl status smart-doorbell.service sudo journalctl -u smart-doorbell.service -f5.2 性能优化与功耗管理树莓派资源有限优化至关重要。模型优化是根本务必使用量化后的INT8 TFLite模型。与FP32模型相比速度提升是质的飞跃。使用硬件加速树莓派4/5的GPU和NPU可以加速模型推理。TFLite支持使用Edge TPU需要Google Coral USB加速棒或通过ARM NN库利用GPU。配置稍复杂但能极大提升速度。对于EfficientNet-Lite这类模型使用Edge TPU可以将推理时间从几百毫秒降到几十毫秒。优化OpenCV编译OpenCV时启用NEON和VFPV3硬件加速。但使用预编译的opencv-python-headless通常已包含基础优化。降低CPU频率如果系统负载不高可以适当降低CPU频率以减少发热和功耗。sudo raspi-config-Performance Options-Overclock中设置。关闭不需要的服务如蓝牙、桌面环境如果用Lite版则没有、HDMI输出等。5.3 常见问题与排查实录以下是我在开发和部署过程中踩过的坑和解决方案问题现象可能原因排查与解决摄像头无法打开1. CSI摄像头排线松动。2. 摄像头被其他进程占用。3.OpenCV默认驱动不支持CSI摄像头。1. 检查排线连接。2. 运行sudo systemctl stop smart-doorbell后用libcamera-hello测试摄像头。3. 改用picamera2库或为cv2.VideoCapture指定libcam后端在/boot/config.txt中启用camera_auto_detect1并重启。模型推理速度极慢5秒1. 使用了未量化的浮点模型。2. CPU频率被限制或过热降频。3. 同时运行了太多其他程序。1.确认模型是.tflite且经过量化。2. 安装vcgencmd工具运行vcgencmd measure_temp和vcgencmd measure_clock arm查看温度和频率。3. 使用htop查看CPU占用关闭无关进程。Telegram通知发送失败1. 网络不通。2. Bot Token或Chat ID错误。3. 消息内容格式问题。1.ping api.telegram.org测试连通性。2. 用curl命令手动测试APIcurl -X POST https://api.telegram.org/botYOUR_TOKEN/getMe。3. 检查消息字符串中是否有特殊字符导致JSON解析错误。GPIO触发无反应1. GPIO引脚号设置错误BCM vs BOARD模式。2. 内部上拉/下拉电阻配置错误。3. 信号抖动Bounce。1. 确认使用的是GPIO.BCM编号即引脚名如GPIO17。2. 用万用表测量触发时引脚电压是否从高变低。3.add_event_detect中的bouncetime参数单位毫秒可以防抖适当调大。系统运行几天后卡死1. 内存泄漏。2. SD卡因频繁读写损坏。3. 电源不稳定。1. 检查代码确保在循环中及时释放大对象如图像数组。使用logging记录内存使用。2. 将频繁读写的目录如captured_images挂载到USB硬盘或RAM磁盘tmpfs。3. 使用官方或足额3A电源确保电压稳定。识别准确率低1. 训练数据不足或质量差。2. 图像预处理与训练时不一致。3. 现场光线条件与训练数据差异大。1. 收集更多样化的真实门前数据重新微调模型。2. 确保推理时的缩放、裁剪、归一化方式与训练时完全一致。3. 考虑增加补光灯或使用带有宽动态范围WDR的摄像头。一个关键的调试技巧在代码中大量使用日志logging模块将关键步骤如“开始捕获”、“推理完成”、“发送通知”和信息如置信度、耗时记录到文件。当出现问题时查看日志文件是定位问题最快的方法。6. 扩展思路与未来玩法一个基础的系统搭建完成后你可以根据自己的需求和创意进行无限扩展多模态识别不止是图像。可以加一个麦克风在按门铃时录制一段短音频使用一个轻量级的语音模型识别访客的语音内容比如“送快递的”与视觉识别结果融合做出更准确的判断。本地语音交互在门口安装一个小喇叭和麦克风当识别为“快递员”时自动通过TTS文本转语音播放“请将包裹放在门口谢谢”。这需要集成像pyttsx3或edge-tts这样的库。云端备份与远程查看虽然我们强调隐私但你可以选择性地将重要的识别事件和图片加密后备份到私有云如Nextcloud、Synology Drive方便在任何地方查看历史记录。与更广泛的智能家居集成除了Home Assistant还可以通过MQTT协议接入Node-RED创建更复杂的自动化流程。例如识别到“家人”回家不仅开门锁还可以提前打开空调、点亮玄关灯。模型持续学习建立一个简单的Web界面展示识别错误的图片让你手动纠正标签。定期比如每周用这些新标注的数据对模型进行一次微调让你的门铃越来越“认识”你的社交圈。这个项目最吸引人的地方在于它完美地结合了硬件、软件和人工智能从一个简单的想法出发最终打造出一个真正实用、能融入日常生活的智能产品。整个过程会遇到无数挑战从环境配置的琐碎到模型调优的挫败但每一次问题的解决都会带来巨大的成就感。当你第一次收到那条“识别结果快递员”的精准通知时你会觉得所有的折腾都是值得的。