无人机实战系列(三)本地摄像头+远程GPU转换深度图

这篇文章将结合之前写的两篇文章 无人机实战系列(一)在局域网内传输数据 和 无人机实战系列(二)本地摄像头 + Depth-Anything V2 实现了以下功能:

  • 本地笔记本摄像头发布图像 + 远程GPU实时处理(无回传);
  • 【异步】本地笔记本摄像头发布图像 + 远程GPU实时处理(回传至笔记本并展示);
  • 【同步】本地笔记本摄像头发布图像 + 远程GPU实时处理(回传至笔记本并展示);

建议在运行这个demo之前先查看先前的两篇文章以熟悉 zmq 库与 Depth-Anything V2 这个模型;

这里之所以提供两个在是否回传上的demo是因为你需要根据自己的实际状况进行选择,尽管回传并显示深度图能够更加直观查看计算结果但你仍然需要平衡以下两个方面:

  • 深度本身体积较大,回传会占用通讯带宽;
  • 回传的图像本地显示会占用本地算力;

【注意】:这篇文章的代码需要在 无人机实战系列(二)本地摄像头 + Depth-Anything V2 中的文件夹下运行,否则会报错找不到对应的文件与模型。


本地笔记本摄像头发布图像 + 远程GPU实时处理(无回传)

这个demo实现了本地笔记本打开摄像头后将图像发布出去,远程GPU服务器接受到图像后使用 Depth-Anything V2 处理图像并展示。

本地笔记本发布摄像头图像

在下面的代码中有以下几点需要注意:

  1. 设置发布频率 send_fps,较低的发布频率可以让减少GPU端的压力;
  2. 设置发布队列大小 socket.setsockopt(zmq.SNDHWM, 1),让发布队列始终仅有当前帧画面,降低带宽压力;
  3. 设置仅保存最新消息 socket.setsockopt(zmq.CONFLATE, 1),让发布队列仅存储最新的画面,降低接受端的画面延迟;
import zmq
import cv2
import timecontext = zmq.Context()
socket = context.socket(zmq.PUB)
socket.bind("tcp://*:5555")  # 本地绑定端口socket.setsockopt(zmq.SNDHWM, 1)        # 发送队列大小为1
socket.setsockopt(zmq.CONFLATE, 1)      # 仅保存最新消息cap = cv2.VideoCapture(0)  # 读取摄像头send_fps = 30       # 限制传输的fps,降低接受方的处理压力while True:start_time = time.time()ret, frame = cap.read()if not ret:continue_, buffer = cv2.imencode('.jpg', frame)  # 编码成JPEG格式socket.send(buffer.tobytes())  # 发送图像数据cv2.imshow("Origin image", frame)if cv2.waitKey(1) & 0xFF == ord('q'):breaktime.sleep(max(1/send_fps - (time.time() - start_time), 0))

运行:

$ python camera_pub.py

在这里插入图片描述

GPU 服务器接受端

在下面的代码中有以下几点需要注意:

  1. 绑定发布端地址 socket.connect("tcp://192.168.75.201:5555"),根据你笔记本的地址进行修改;
  2. 仅接受最新消息 socket.setsockopt(zmq.CONFLATE, 1)
  3. 清空旧数据帧 socket.setsockopt(zmq.RCVHWM, 1) && socket.poll(1)
import argparse
import cv2
import numpy as np
import torch
import time
import zmqfrom depth_anything_v2.dpt import DepthAnythingV2context = zmq.Context()
socket = context.socket(zmq.SUB)
socket.connect("tcp://192.168.75.201:5555")		# 远程发布端地址
socket.setsockopt(zmq.SUBSCRIBE, b"")
socket.setsockopt(zmq.CONFLATE, 1)      # 仅接受最新消息
socket.setsockopt(zmq.RCVHWM, 1)        # 清空旧数据帧if __name__ == '__main__':parser = argparse.ArgumentParser(description='Depth Anything V2')parser.add_argument('--input-size', type=int, default=518)parser.add_argument('--encoder', type=str, default='vits', choices=['vits', 'vitb', 'vitl', 'vitg'])parser.add_argument('--pred-only', action='store_true', help='only display the prediction')parser.add_argument('--grayscale', action='store_true', help='do not apply colorful palette')args = parser.parse_args()DEVICE = 'cuda' if torch.cuda.is_available() else 'cpu'model_configs = {'vits': {'encoder': 'vits', 'features': 64, 'out_channels': [48, 96, 192, 384]},'vitb': {'encoder': 'vitb', 'features': 128, 'out_channels': [96, 192, 384, 768]},'vitl': {'encoder': 'vitl', 'features': 256, 'out_channels': [256, 512, 1024, 1024]},'vitg': {'encoder': 'vitg', 'features': 384, 'out_channels': [1536, 1536, 1536, 1536]}}depth_anything = DepthAnythingV2(**model_configs[args.encoder])depth_anything.load_state_dict(torch.load(f'./models/depth_anything_v2_{args.encoder}.pth', map_location='cpu'))depth_anything = depth_anything.to(DEVICE).eval()margin_width = 50while True:start_time = time.time()# **优化 1: ZMQ 数据接收**try:while socket.poll(1):  # 尝试不断读取新数据,丢弃旧数据msg = socket.recv(zmq.NOBLOCK)zmq_time = time.time()# **优化 2: OpenCV 解码**raw_frame = cv2.imdecode(np.frombuffer(msg, dtype=np.uint8), 1)decode_time = time.time()# **优化 3: 模型推理**with torch.no_grad():depth = depth_anything.infer_image(raw_frame, args.input_size)infer_time = time.time()# **优化 4: 归一化 + OpenCV 伪彩色映射**depth = ((depth - depth.min()) / (depth.max() - depth.min()) * 255).astype(np.uint8)if args.grayscale:depth = np.repeat(depth[..., np.newaxis], 3, axis=-1)else:depth = cv2.applyColorMap(depth, cv2.COLORMAP_JET)process_time = time.time()# **优化 5: 合并图像**split_region = np.ones((raw_frame.shape[0], margin_width, 3), dtype=np.uint8) * 255combined_frame = cv2.hconcat([raw_frame, split_region, depth])cv2.imshow('Raw Frame and Depth Prediction', combined_frame)if cv2.waitKey(1) & 0xFF == ord('q'):breakprint(f"[{args.encoder}] Frame cost time: {time.time() - start_time:.4f} s")print(f"  ZMQ receive:  {zmq_time - start_time:.4f} s")print(f"  Decode:       {decode_time - zmq_time:.4f} s")print(f"  Inference:    {infer_time - decode_time:.4f} s")print(f"  Processing:   {process_time - infer_time:.4f} s")except zmq.Again:print("No msg received, skip...")continue  # 没有消息就跳过cv2.destroyAllWindows()

运行:

$ python camera_recv.py

在这里插入图片描述


【异步】本地笔记本摄像头发布图像 + 远程GPU实时处理(回传至笔记本并展示)

和上面的代码基本一致,只不过在发送与接收端都增加了一个收发对象,通常情况下使用异步方式处理收发因为可以避免一端服务来不及处理而导致另一端持续等待。

本地笔记本发布摄像头图像

import zmq
import cv2
import numpy as np
import timecontext = zmq.Context()# 发布原始数据
pub_socket = context.socket(zmq.PUB)
pub_socket.bind("tcp://*:5555")  # 发布数据# 接收处理结果
pull_socket = context.socket(zmq.PULL)
pull_socket.bind("tcp://*:5556")  # 监听处理方返回数据send_fps = 30cap = cv2.VideoCapture(0)while True:start_time = time.time()ret, frame = cap.read()if not ret:continue# [可选] 图像降采样frame = cv2.pyrDown(frame)frame = cv2.pyrDown(frame)_, buffer = cv2.imencode('.jpg', frame)  # 压缩图像pub_socket.send(buffer.tobytes())  # 发布数据# 非阻塞接收处理结果try:processed_data = pull_socket.recv(zmq.NOBLOCK)processed_frame = cv2.imdecode(np.frombuffer(processed_data, dtype=np.uint8), 1)except zmq.Again:print("No image received, continue...")continuecv2.imshow("Processed Frame", processed_frame)if cv2.waitKey(1) & 0xFF == ord('q'):breaktime.sleep(max(1/send_fps - (time.time() - start_time), 0))cv2.destroyAllWindows()

运行:

$ python camera_pub_async.py

在这里插入图片描述

GPU 服务器接受端(异步)

import argparse
import cv2
import numpy as np
import torch
import time
import zmqfrom depth_anything_v2.dpt import DepthAnythingV2context = zmq.Context()
sub_socket = context.socket(zmq.SUB)
sub_socket.connect("tcp://192.168.75.201:5555")
sub_socket.setsockopt(zmq.SUBSCRIBE, b"")
sub_socket.setsockopt(zmq.CONFLATE, 1)      # 仅接受最新消息
sub_socket.setsockopt(zmq.RCVHWM, 1)        # 清空旧数据帧# 发送处理结果
push_socket = context.socket(zmq.PUSH)
push_socket.connect("tcp://192.168.75.201:5556")if __name__ == '__main__':parser = argparse.ArgumentParser(description='Depth Anything V2')parser.add_argument('--input-size', type=int, default=518)parser.add_argument('--encoder', type=str, default='vits', choices=['vits', 'vitb', 'vitl', 'vitg'])parser.add_argument('--pred-only', action='store_true', help='only display the prediction')parser.add_argument('--grayscale', action='store_true', help='do not apply colorful palette')args = parser.parse_args()DEVICE = 'cuda' if torch.cuda.is_available() else 'cpu'model_configs = {'vits': {'encoder': 'vits', 'features': 64, 'out_channels': [48, 96, 192, 384]},'vitb': {'encoder': 'vitb', 'features': 128, 'out_channels': [96, 192, 384, 768]},'vitl': {'encoder': 'vitl', 'features': 256, 'out_channels': [256, 512, 1024, 1024]},'vitg': {'encoder': 'vitg', 'features': 384, 'out_channels': [1536, 1536, 1536, 1536]}}depth_anything = DepthAnythingV2(**model_configs[args.encoder])depth_anything.load_state_dict(torch.load(f'./models/depth_anything_v2_{args.encoder}.pth', map_location='cpu'))depth_anything = depth_anything.to(DEVICE).eval()margin_width = 50while True:start_time = time.time()# **优化 1: ZMQ 数据接收**try:while sub_socket.poll(1):  # 尝试不断读取新数据,丢弃旧数据msg = sub_socket.recv(zmq.NOBLOCK)msg = sub_socket.recv()zmq_time = time.time()# **优化 2: OpenCV 解码**raw_frame = cv2.imdecode(np.frombuffer(msg, dtype=np.uint8), 1)decode_time = time.time()# **优化 3: 模型推理**with torch.no_grad():depth = depth_anything.infer_image(raw_frame, args.input_size)infer_time = time.time()# **优化 4: 归一化 + OpenCV 伪彩色映射**depth = ((depth - depth.min()) / (depth.max() - depth.min()) * 255).astype(np.uint8)if args.grayscale:depth = np.repeat(depth[..., np.newaxis], 3, axis=-1)else:depth = cv2.applyColorMap(depth, cv2.COLORMAP_JET)process_time = time.time()# **优化 5: 合并图像**split_region = np.ones((raw_frame.shape[0], margin_width, 3), dtype=np.uint8) * 255combined_frame = cv2.hconcat([raw_frame, split_region, depth])cv2.imshow('Raw Frame and Depth Prediction', combined_frame)if cv2.waitKey(1) & 0xFF == ord('q'):breakprint(f"[{args.encoder}] Frame cost time: {time.time() - start_time:.4f} s")print(f"  ZMQ receive:  {zmq_time - start_time:.4f} s")print(f"  Decode:       {decode_time - zmq_time:.4f} s")print(f"  Inference:    {infer_time - decode_time:.4f} s")print(f"  Processing:   {process_time - infer_time:.4f} s")_, buffer = cv2.imencode('.jpg', combined_frame)push_socket.send(buffer.tobytes())  # 发送回处理结果except zmq.Again:print("No msg received, skip...")continue  # 没有消息就跳过cv2.destroyAllWindows()

运行:

$ python camera_recv_async.py

在这里插入图片描述


【同步】本地笔记本摄像头发布图像 + 远程GPU实时处理(回传至笔记本并展示)

通常情况下这种视频流的传递不会考虑同步方式,因为这需要发布方与接收端保持一致,对网络稳定性有较高的要求。

本地笔记本发布摄像头图像

这个demo需要注意以下几点:

  1. 设置发送端为请求响应模式 context.socket(zmq.REQ)
  2. 阻塞等待服务器回传数据 pub_socket.recv()
import zmq
import cv2
import numpy as np
import timecontext = zmq.Context()# 发布原始数据
pub_socket = context.socket(zmq.REQ)        # 使用请求响应模式
pub_socket.bind("tcp://*:5555")  # 发布数据send_fps = 30
cap = cv2.VideoCapture(0)while True:start_time = time.time()ret, frame = cap.read()if not ret:continue# [可选] 图像降采样frame = cv2.pyrDown(frame)frame = cv2.pyrDown(frame)try:_, buffer = cv2.imencode('.jpg', frame)  # 压缩图像pub_socket.send(buffer.tobytes())  # 发布数据print("Waitting for server processed.")processed_data = pub_socket.recv()processed_frame = cv2.imdecode(np.frombuffer(processed_data, dtype=np.uint8), 1)except zmq.Again:print("No image received, continue...")continuecv2.imshow("Processed Frame", processed_frame)if cv2.waitKey(1) & 0xFF == ord('q'):breaktime.sleep(max(1/send_fps - (time.time() - start_time), 0))cv2.destroyAllWindows()

运行:

$ python camera_pub_sync.py

在这里插入图片描述

GPU 服务器接受端

这个demo需要注意以下几点:

  1. 设置接受端为请求响应模式 context.socket(zmq.REP)
  2. 阻塞接受发布端数据 sub_socket.recv()
  3. 将处理好的数据进行同步回传 sub_socket.send(buffer.tobytes())
import argparse
import cv2
import numpy as np
import torch
import time
import zmqfrom depth_anything_v2.dpt import DepthAnythingV2context = zmq.Context()
sub_socket = context.socket(zmq.REP)
sub_socket.connect("tcp://192.168.75.201:5555")if __name__ == '__main__':parser = argparse.ArgumentParser(description='Depth Anything V2')parser.add_argument('--input-size', type=int, default=518)parser.add_argument('--encoder', type=str, default='vits', choices=['vits', 'vitb', 'vitl', 'vitg'])parser.add_argument('--pred-only', action='store_true', help='only display the prediction')parser.add_argument('--grayscale', action='store_true', help='do not apply colorful palette')args = parser.parse_args()DEVICE = 'cuda' if torch.cuda.is_available() else 'cpu'model_configs = {'vits': {'encoder': 'vits', 'features': 64, 'out_channels': [48, 96, 192, 384]},'vitb': {'encoder': 'vitb', 'features': 128, 'out_channels': [96, 192, 384, 768]},'vitl': {'encoder': 'vitl', 'features': 256, 'out_channels': [256, 512, 1024, 1024]},'vitg': {'encoder': 'vitg', 'features': 384, 'out_channels': [1536, 1536, 1536, 1536]}}depth_anything = DepthAnythingV2(**model_configs[args.encoder])depth_anything.load_state_dict(torch.load(f'./models/depth_anything_v2_{args.encoder}.pth', map_location='cpu'))depth_anything = depth_anything.to(DEVICE).eval()margin_width = 50while True:start_time = time.time()# **优化 1: ZMQ 数据接收**try:msg = sub_socket.recv()zmq_time = time.time()# **优化 2: OpenCV 解码**raw_frame = cv2.imdecode(np.frombuffer(msg, dtype=np.uint8), 1)decode_time = time.time()# **优化 3: 模型推理**with torch.no_grad():depth = depth_anything.infer_image(raw_frame, args.input_size)infer_time = time.time()# **优化 4: 归一化 + OpenCV 伪彩色映射**depth = ((depth - depth.min()) / (depth.max() - depth.min()) * 255).astype(np.uint8)if args.grayscale:depth = np.repeat(depth[..., np.newaxis], 3, axis=-1)else:depth = cv2.applyColorMap(depth, cv2.COLORMAP_JET)process_time = time.time()# **优化 5: 合并图像**split_region = np.ones((raw_frame.shape[0], margin_width, 3), dtype=np.uint8) * 255combined_frame = cv2.hconcat([raw_frame, split_region, depth])cv2.imshow('Raw Frame and Depth Prediction', combined_frame)if cv2.waitKey(1) & 0xFF == ord('q'):breakprint(f"[{args.encoder}] Frame cost time: {time.time() - start_time:.4f} s")print(f"  ZMQ receive:  {zmq_time - start_time:.4f} s")print(f"  Decode:       {decode_time - zmq_time:.4f} s")print(f"  Inference:    {infer_time - decode_time:.4f} s")print(f"  Processing:   {process_time - infer_time:.4f} s")_, buffer = cv2.imencode('.jpg', combined_frame)sub_socket.send(buffer.tobytes())  # 发送回处理结果except zmq.Again:print("No msg received, skip...")continue  # 没有消息就跳过cv2.destroyAllWindows()

运行:

$ python camera_recv_sync.py

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/70579.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

读取罗克韦尔AllenBradley Micro-Logix1400 罗克韦尔 CIP PCCC通信协议

通信协议实例下载 <-----实例下载 MicroLogix 1400的通信能力 MicroLogix 1400支持多种通信协议&#xff0c;包括CIP&#xff08;通过EtherNet/IP实现&#xff09;、Modbus RTU/TCP、DF1等4812。其硬件集成以太网端口&#xff0c;便于通过EtherNet/IP进行CIP通信15。 CIP…

Python游戏编程之赛车游戏6-5

1 碰撞检测 在显示了玩家汽车和“敌人”汽车之后&#xff0c;接下来就要实现玩家与“敌人”的碰撞检测了。 代码如图1所示。 图1 碰撞检测代码 第72行代码通过pygame.sprite.spritecollideany()函数判断P1和enemies是否发生了碰撞&#xff0c;如果发生碰撞&#xff0c;该函数…

【QT 网络编程】HTTP协议(二)

文章目录 &#x1f31f;1.概述&#x1f31f;2.代码结构概览&#x1f31f;3.代码解析&#x1f338;Http_Api_Manager - API管理类&#x1f338;Http_Request_Manager- HTTP请求管理类&#x1f338;ThreadPool - 线程池&#x1f338;TestWindow- 测试类 &#x1f31f;4.运行效果&…

保姆级! 本地部署DeepSeek-R1大模型 安装Ollama Api 后,Postman本地调用 deepseek

要在Postman中访问Ollama API并调用DeepSeek模型,你需要遵循以下步骤。首先,确保你有一个有效的Ollama服务器实例运行中,并且DeepSeek模型已经被加载。 可以参考我的这篇博客 保姆级!使用Ollama本地部署DeepSeek-R1大模型 并java通过api 调用 具体的代码实现参考我这个博…

在PHP Web开发中,实现异步处理有几种常见方式的优缺点,以及最佳实践推荐方法

1. 消息队列 使用消息队列&#xff08;如RabbitMQ、Beanstalkd、Redis&#xff09;将任务放入队列&#xff0c;由后台进程异步处理。 优点&#xff1a; 任务持久化&#xff0c;系统崩溃后任务不丢失。 支持分布式处理&#xff0c;扩展性强。 实现步骤&#xff1a; 安装消息…

算法15--BFS

BFS 原理经典例题解决FloodFill 算法[733. 图像渲染](https://leetcode.cn/problems/flood-fill/description/)[200. 岛屿数量](https://leetcode.cn/problems/number-of-islands/description/)[695. 岛屿的最大面积](https://leetcode.cn/problems/max-area-of-island/descrip…

网络空间安全(2)应用程序安全

前言 应用程序安全&#xff08;Application Security&#xff0c;简称AppSec&#xff09;是一个综合性的概念&#xff0c;它涵盖了应用程序从开发到部署&#xff0c;再到后续维护的整个过程中的安全措施。 一、定义与重要性 定义&#xff1a;应用程序安全是指识别和修复应用程序…

Plantsimulation中机器人怎么通过阻塞角度设置旋转135°

创建一个这样的简单模型。 检查PickAndPlace的角度表。源位于180的角位置&#xff0c;而物料终结位于90的角位置。“返回默认位置”选项未被勾选。源每分钟生成一个零件。启动模拟时&#xff0c;Plant Simulation会选择两个位置之间的最短路径。示例中的机器人无法绕135的角位…

Fisher信息矩阵(Fisher Information Matrix, FIM)与自然梯度下降:机器学习中的优化利器

Fisher信息矩阵与自然梯度下降&#xff1a;机器学习中的优化利器 在机器学习尤其是深度学习中&#xff0c;优化模型参数是一个核心任务。我们通常依赖梯度下降&#xff08;Gradient Descent&#xff09;来调整参数&#xff0c;但普通的梯度下降有时会显得“笨拙”&#xff0c;…

Spring Boot集成Swagger API文档:傻瓜式零基础教程

Springfox Swagger 是一个用于构建基于 Spring Boot 的 RESTful API 文档的开源工具。它通过使用注解来描述 API 端点&#xff0c;自动生成易于阅读和理解的 API 文档。Springfox 通过在运行时检查应用程序&#xff0c;基于 Spring 配置、类结构和各种编译时 Java 注释来推断 A…

接口测试基础 --- 什么是接口测试及其测试流程?

接口测试是软件测试中的一个重要部分&#xff0c;它主要用于验证和评估不同软件组件之间的通信和交互。接口测试的目标是确保不同的系统、模块或组件能够相互连接并正常工作。 接口测试流程可以分为以下几个步骤&#xff1a; 1.需求分析&#xff1a;首先&#xff0c;需要仔细…

kafka-集群缩容

一. 简述&#xff1a; 当业务增加时&#xff0c;服务瓶颈&#xff0c;我们需要进行扩容。当业务量下降时&#xff0c;为成本考虑。自然也会涉及到缩容。假设集群有 15 台机器&#xff0c;预计缩到 10 台机器&#xff0c;那么需要做 5 次缩容操作&#xff0c;每次将一个节点下线…

Spring Boot 概要(官网文档解读)

Spring Boot 概述 Spring Boot 是一个高效构建 Spring 生产级应用的脚手架工具&#xff0c;它简化了基于 Spring 框架的开发过程。 Spring Boot 也是一个“构件组装门户”&#xff0c;何为构件组装门户呢&#xff1f;所谓的“构件组装门户”指的是一个对外提供的Web平台&#x…

Linux 命令大全完整版(12)

Linux 命令大全 5. 文件管理命令 ln(link) 功能说明&#xff1a;连接文件或目录。语  法&#xff1a;ln [-bdfinsv][-S <字尾备份字符串>][-V <备份方式>][--help][--version][源文件或目录][目标文件或目录] 或 ln [-bdfinsv][-S <字尾备份字符串>][-V…

遗传算法初探

组成要素 编码 分为二进制编码、实数编码和顺序编码 初始种群的产生 分为随机方法、基于反向学习优化的种群产生。 基于反向学习优化的种群其思想是先随机生成一个种群P(N)&#xff0c;然后按照反向学习方法生成新的种群OP(N),合并两个种群&#xff0c;得到一个新的种群S(N…

【算法】堆

堆 heap&#xff0c;一棵完全二叉树&#xff0c;使用数组实现的&#xff0c;但具备完全二叉树的一些性质。一般总是满足以下性质&#xff1a; 堆中某个节点的值总是不大于或不小于其父节点的值&#xff1b;堆总是一棵完全二叉树。&#xff08;即除了最底层&#xff0c;其他层…

C/C++高性能Web开发框架全解析:2025技术选型指南

一、工业级框架深度解析&#xff08;附性能实测&#xff09; 1. Drogon v2.1&#xff1a;异步框架性能王者 核心架构&#xff1a; Reactor 非阻塞I/O线程池&#xff08;参考Nginx模型&#xff09; 协程实现&#xff1a;基于Boost.Coroutine2&#xff08;兼容C11&#xff09;…

使用PHP接入纯真IP库:实现IP地址地理位置查询

引言 在日常开发中,我们经常需要根据用户的IP地址获取其地理位置信息,例如国家、省份、城市等。纯真IP库(QQWry)是一个常用的IP地址数据库,提供了丰富的IP地址与地理位置的映射关系。本文将介绍如何使用PHP接入纯真IP库,并通过一个完整的案例演示如何实现IP地址的地理位…

Django ORM 的常用字段类型、外键关联的跨表引用技巧,以及 `_` 和 `__` 的使用场景

一、Django ORM 常用字段类型 1. 基础字段类型 字段类型说明示例CharField字符串字段&#xff0c;必须指定 max_lengthname models.CharField(max_length50)IntegerField整数字段age models.IntegerField()BooleanField布尔值字段is_active models.BooleanField()DateFiel…

java递归求自然数列的前n项和

概述 实现 /*** 数列 1 2 3 ... n ...* 递归求数列的前n项和* param n* return*/private static long calSum(long n){if (n1) return 1;else {return ncalSum(n-1); // 前n项的和 即第n项的值前n-1项的和}}测试用例 public static void main(String[] args) {long res1 cal…