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

无人机实战系列(三)本地摄像头+远程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

在这里插入图片描述

相关文章:

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

这篇文章将结合之前写的两篇文章 无人机实战系列(一)在局域网内传输数据 和 无人机实战系列(二)本地摄像头 Depth-Anything V2 实现了以下功能: 本地笔记本摄像头发布图像 远程GPU实时处理(无回传&#…...

七.智慧城市数据治理平台架构

一、整体架构概览 智慧城市数据治理平台架构描绘了一个全面的智慧城市数据治理平台,旨在实现城市数据的统一管理、共享和应用,为城市运行、管理和决策提供数据支撑。整体架构呈现出分层、模块化、集约化的特点,并强调数据安全和标准规范。 智…...

UE5从入门到精通之多人游戏编程常用函数

文章目录 前言一、权限与身份判断函数1. 服务器/客户端判断2. 网络角色判断二、网络同步与复制函数1. 变量同步2. RPC调用三、连接与会话管理函数1. 玩家连接控制2. 网络模式判断四、实用工具函数前言 UE5给我们提供了非常强大的多人网路系统,让我们可以很方便的开发多人游戏…...

RK3399 Android7 Ethernet Tether功能实现

在Android机顶盒产品,对于以太网与WiFi间的关系有如下: 1、以太网与WiFi STA均可连接路由器访问外网; 2、WiFi AP功能可以共享以太网访问外网。 而本文档是对于2的变动,实现通过以太网共享WiFi STA访问外网,并在此基础上可以共享4G/5G网络(设备支持情况下),下面是相应…...

【论文学习】基于规模化Transformer模型的低比特率高质量语音编码

以下文章基于所提供的文档内容撰写,旨在对该论文“Scaling Transformers for Low-Bitrate High-Quality Speech Coding”进行较为系统和深入的分析与总结。 论文地址:https://arxiv.org/pdf/2411.19842 一、研究背景与动机 自20世纪70年代以来&#xff…...

Pretraining Language Models with Text-Attributed Heterogeneous Graphs

Pretraining Language Models with Text-Attributed Heterogeneous Graphs EMNLP 推荐指数:#paper/⭐⭐#​ 贡献: 我们研究了在更复杂的数据结构上预训练LM的问题,即,TAHG。与大多数只能从每个节点的文本描述中学习的PLM不同&…...

什么是将应用放在边缘服务器上创建?应用不是在用户手机上吗?边缘计算究竟如何优化?通过两个问题来辨析

元宇宙应用虽然可以在用户的手机等终端设备上运行,但大部分的计算和数据处理任务并不是完全在手机上完成的。元宇宙的运行需要庞大的计算资源和大量的数据交互,而这些是手机等终端设备难以独自承担的。因此,元宇宙应用需要借助边缘数据中心等…...

uni-app 系统学习,从入门到实战(二)—— 项目结构解析

全篇大概 2000 字(含代码),建议阅读时间 10min 一、UniApp 目录结构详解 UniApp 基于 Vue.js 开发,其目录结构遵循约定大于配置的原则,以下是一个标准项目的核心目录结构: pages # 页面目录(核…...

滴水逆向_引用_友元函数_运算符重载

作业: 运算符号重载实现。 struct Person { public:int x;int y; public:Person(){this->x 10;this->y 20;}Person(int x, int y){this->x x;this->y y;}//申明友元函数void Printf(const Person& p){printf("%d %d",p.x,p.y);}/…...

java医院多维度综合绩效考核源码,医院绩效管理系统,支持一键核算和批量操作,设有审核机制,允许数据修正

医院绩效考核管理系统,java医院绩效核算系统源码,采用多维度综合绩效考核的形式,针对院内实际情况分别对工作量、KPI指标、科研、教学、管理等进行全面考核。医院可结合实际需求,对考核方案中各维度进行灵活配置,对各维…...

科普:HTTP端口80和HTTPS端口443

你会发现,有的网址不带端口号,怎么回事? HTTP协议默认端口:HTTP协议的默认端口是80。当用户在浏览器中输入一个没有指定端口的以http://开头的网址时,浏览器会自动使用80端口与服务器建立连接,进行超文本数…...

uniapp打包生产证书上架IOS全流程

第一步:生成生产证书 上传CSR文件,windows系统电脑无法上传csr文件可以参考这个: windows下创建ios打包证书的详细流程_香蕉云编 下载生产证书 下载下来的cer生产证书在香蕉云编cer文件上传栏上传,然后生成p12文件 生成p12文件…...

山东大学软件学院nosql实验一环境配置

环境:前端vue后端springboot 软件环境: MongoDB MongoDBCompass 实验步骤与内容: 在官网下载安装包(最新版) 配置环境环境变量 在“高级系统设置-环境变量”中,可以将MongoDB添加到环境变量Path中(D:\…...

【2024 CSDN博客之星】大学四年,我如何在CSDN实现学业与事业的“双逆袭”?

前言: Hello大家好,我是Dream。不知不觉2024年已经过去,自己也马上迈入23岁,感慨时间飞快,从19岁刚入大学加入CSDN,到现在大学毕业已经整整四年了。CSDN陪伴我走过了最青涩的四年大学时光,在这里…...

【Windows 同时安装 MySQL5 和 MySQL8 - 详细图文教程】

目录 建议 8.0的版本用图形化工具安装 0.下载 1.安装 2.配置环境变量 1. 下载 mysql8.0 和 mysql5.7的压缩包 2. 解压到本地 3. 安装MySQL8.xx.xx 第一步 配置环境变量 第二步 新建配置文件 第三步 MySQL 数据库初始化 第四步 临时密码 第五步 安装并开启mysql80服…...

[Python学习日记-83] 操作系统的介绍

[Python学习日记-83] 操作系统的介绍 简介 操作系统介绍 简介 本篇开始我们要学习网络编程的进阶知识,即并发编程(多进程编程),从字面意思可以看出,进程就是正在执行的一个过程,也就是说进程是对正在运行…...

软考——WWW与HTTP

1.万维网(world wide web) 是一个规模巨大的、可以资源互联的资料空间。由URL进行定位,通过HTTP协议传送给使用者,又由HTML来进行文件的展现。 它的主要组成部分是:URL、HTTP、HTML。 (1)URL…...

算法-数据结构-图-邻接表构建

邻接表的基本概念 顶点(Vertex): 图中的每个顶点用一个节点表示。 每个顶点存储一个链表或数组,用于记录与该顶点直接相连的其他顶点。 边(Edge): 如果顶点 A 和顶点 B 之间有一条边&#xf…...

Docker(Nginx)部署Vue

简介:目标使用docker将vue生成的dist文件,结合nginx生成镜像,然后运行; 1、首选确保vue项目正确运行,并能正确打包dist文件; 2、查看已经生成的dist文件 3、将dist文件打包为rar文件或者zip文件&#xf…...

ubuntu22.04的docker容器中安装ssh服务

ubuntu22.04的docker容器中安装ssh服务,以便外部可以连接到容器中操作。 rootnode15:~# cat /etc/issue Ubuntu 22.04.5 LTS \n \l rootnode15:~# docker ps|grep qwen 7d3c36c37d36 vllm/vllm-openai:v0.7.3 "python3 -m …...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来

一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...

线程与协程

1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现

摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序&#xff0c;以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务&#xff0c;提供稳定高效的数据处理与业务逻辑支持&#xff1b;利用 uniapp 实现跨平台前…...

css3笔记 (1) 自用

outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size&#xff1a;0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格&#xff…...

vue3+vite项目中使用.env文件环境变量方法

vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量&#xff0c;这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图&#xff0c;该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序&#xff0c;确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数&#xff0c;分别表示n 和 e 的值&#xff08;1…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)

前言&#xff1a; 在Java编程中&#xff0c;类的生命周期是指类从被加载到内存中开始&#xff0c;到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期&#xff0c;让读者对此有深刻印象。 目录 ​…...

[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】&#xff0c;分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...