【第二十五周】:DeepPose:通过深度神经网络实现人体姿态估计

news2025/3/4 2:02:08

DeepPose

  • 摘要
  • Abstract
  • 文章信息
  • 引言
  • DeepPose
    • 归一化
    • 网络结构
    • 初始网络(粗略估计所有关节点位置)
    • 精细化级联网络(分别修正每个关节点的位置)
  • 疑问与解决
  • 代码实践
  • 总结

摘要

这篇博客介绍了DeepPose,这是首个基于深度神经网络(DNN)的人体姿态估计框架,其核心思想是通过端到端回归直接预测人体关节坐标,摒弃了传统方法依赖手工特征和图形模型的局限性。针对传统算法在遮挡、复杂背景和小关节定位中的不足,DeepPose提出级联回归的方法:初始阶段利用全局低分辨率图像预测粗略关节点位置,后续级联阶段通过高分辨率局部图像块逐步修正误差,实现从粗到细的优化。为消除尺度差异,DeepPose对输入图像使用了归一化,且对级联网络进行独立训练,每个阶段参数分离以适配不同的输入尺度。该方法在LSP、FLIC等数据集上较传统方法定位误差降低20%-30%,尤其在遮挡场景下鲁棒性显著提升。但级联结构计算成本较高,且依赖初始预测的准确性。未来改进方向可结合热力图回归与级联优化,或引入轻量化网络提升实时性。

Abstract

This blog introduces DeepPose, the first deep neural network (DNN)-based framework for human pose estimation. Its core innovation lies in directly predicting joint coordinates through end-to-end regression, eliminating the reliance on handcrafted features and graphical models inherent in traditional methods. To address the limitations of conventional algorithms in handling occlusions, complex backgrounds, and small joint localization, DeepPose proposes a cascaded regression approach: the initial stage predicts rough joint positions using global low-resolution images, while subsequent cascaded stages iteratively refine errors via high-resolution local image patches, achieving coarse-to-fine optimization. To mitigate scale variance, DeepPose employs input normalization and independently trains cascaded networks with separated parameters to adapt to different input scales. Evaluations on datasets like LSP and FLIC demonstrate a 20%-30% reduction in localization errors compared to traditional methods, with marked robustness improvements in occlusion scenarios. However, the cascaded structure incurs higher computational costs and heavily depends on the accuracy of initial predictions. Future improvements may integrate heatmap regression with cascaded refinement or adopt lightweight networks for real-time performance. This work pioneers a regression-based paradigm for pose estimation, bridging the gap between global context awareness and local precision.


文章信息

Title:DeepPose: Human Pose Estimation via Deep Neural Networks
Author: Alexander Toshev, Christian Szegedy
Source:https://arxiv.org/abs/1312.4659


引言

人体姿态估计问题,被定义为人体关节定位问题。其难点在于人体关节的灵活性、某些关节小而模糊及遮挡问题。如下图,许多关节不可见,而我们可以通过看到的人物姿势和其余可见关节预测不可见的关节,并预测人体姿态。这也说明了全局推理的必要性。
在这里插入图片描述
早期的研究基本是基于部件模型(如Pictorial Structures)仅能建模身体局部关系,无法全局推理整体姿态 。例如,遮挡的关节位置需通过其他可见部位推测,但传统模型缺乏这种整体关联能力。为保持推理效率,一些模型采用树状结构拓扑,仅建模相邻关节的约束关系,忽视远距离关节的相互作用(如头与脚的关联)。另外,传统方法多将姿态估计视为分类问题,生成离散的姿态类别,难以实现连续空间中的高精度定位。
2012年AlexNet在ImageNet上的成功验证了深度神经网络(DNN)在图像分类任务中的潜力 。此后,DNN逐步扩展至目标检测(如R-CNN)和定位任务,但姿态估计尚未被充分探索 。
作者利用深度神经网络来进行人体姿态评估,将姿态估计视为一个联合回归问题。通过全卷积网络(如AlexNet)提取整图特征,可隐式学习关节间的空间依赖关系。另外,作者提出级联的方法来对关节点位置进行多次修正以提高精准率。

DeepPose

归一化

人体在图像中的尺度差异(如近景全身像与远景小尺寸人像)会导致关节点绝对坐标的数值范围差异巨大。通过边界框归一化,将关节点坐标转换为相对于人体边界框中心的比例值,可统一不同尺度下的坐标分布,使模型无需适应绝对像素值的变化,专注于学习姿态的空间关系。直接回归关节点绝对坐标需要模型同时学习空间位置和尺度变换,而归一化将问题简化为相对位置回归,归一化后的坐标仅需预测相对偏移量,模型更易收敛。另外,归一化后的数据分布更均匀,梯度下降过程中参数的更新方向更稳定,可有避免止训练时梯度爆炸问题。
用边框b对于图像进行归一化:
在这里插入图片描述
其中, y i {\mathbf{y}}_{i} yi 表示第 i i i 个关节在图像中的绝对坐标,具体为 ( x i , y i ) (x_i,y_i) (xi,yi);
b b b 是边框信息,定义为 b = ( b c , b w , b h ) b=(b_c,b_w,b_h) b=(bc,bw,bh), b c b_c bc 是边界框的中心坐标 ( b c x , b c y ) (b_{cx},b_{cy}) (bcx,bcy), b w b_w bw b h b_h bh 是边框的宽和高。

按照上面的公式可以将关节点的坐标转化为相对坐标,相对坐标在[-0.5,0.5]范围内,实现中也可加上0.5,归一化到[0,1]。

网络结构

作者将姿态估计视为回归问题,并用深度神经网络来预测关节点位置。
在这里插入图片描述
上图展示了DeepPose的总体结构:左边是初始阶段,粗略预测全局所有的关节点位置,其中蓝色是卷积层,绿色是全连接层,池化层和归一层没有需要学习的参数,图中没有展示。图中右边是精细化级联网络,其结构与初始阶段的网络完全一致,但每一级的网络参数是独立的,精细化级联网络对上一级预测的关节点位置进行修正,得到更准确的位置。
在初始阶段(Initial Stage),模型通过归一化人体边界框坐标构建尺度不变的输入,利用卷积网络直接回归所有关节点的坐标;在后续级联阶段(Cascade),模型基于初始预测结果对局部图像区域进行精细化裁剪,通过多层级联DNN逐步修正关节点位移量,最终输出精确的关节点位置。
下面分别介绍初始网络和精细化计量网络的具体细节:

初始网络(粗略估计所有关节点位置)

用 C 表示卷积层,用LRN表示局部响应标准化层,用P 表示池化层,用 F 表示全连接层。只有C 层和F 层包含可学习的参数,而其余的是无参数的。
在这里插入图片描述

对于 C 层,尺寸定义为宽度×高度×深度,其中前两个维度具有空间意义,而深度定义了滤波器的数量。如果我们将每层的大小写在括号中,那么网络可以简洁地描述为 C ( 55 × 55 × 96 ) − L R N − P − C ( 27 × 27 × 256 ) − L R N − P − C ( 13 × 13 × 384 ) − C ( 13 × 13 × 384 ) − C ( 13 × 13 × 256 ) − P − F ( 4096 ) − F ( 4096 ) C\left( {{55} \times {55} \times {96}}\right) - {LRN} - P - C\left( {{27} \times {27} \times {256}}\right) -{LRN} - P - C\left( {{13} \times {13} \times {384}}\right) - C\left( {{13} \times {13} \times {384}}\right) -C\left( {{13} \times {13} \times {256}}\right) - P - F\left( {4096}\right) - F\left( {4096}\right) C(55×55×96)LRNPC(27×27×256)LRNPC(13×13×384)C(13×13×384)C(13×13×256)PF(4096)F(4096)
前两个C层的滤波器大小为 11 × 11 11\times 11 11×11 5 × 5 5\times 5 5×5,其余三个层的大小为 3 × 3 3\times 3 3×3
池化操作在三层之后应用,尽管分辨率降低,但有助于提高性能。
网络的输入是 220 × 220 220\times 220 220×220的图像,通过步幅为4的方式输入网络,记人体关键点个数为 k k k,则初始网络的输出为 2 k 2k 2k 维向量。
网络的结构可以替换成其他网络,文章用的是AlexNet,还可替换成resent等其他网络。

损失函数
不想AlexNet那样使用分类损失,而是在最后一层网络层上训练线性回归,通过最小化预测值与真实姿态向量之间的 L 2 L_2 L2 距离来预测姿态向量。
先将训练集 D D D 进行归一化:
在这里插入图片描述
最优网络参数的 L 2 L_2 L2 损失函数为:
在这里插入图片描述
为了清晰起见,公式写出对各个关节的优化。需要注意的是,即使某些图像中并非所有关节都被标注(存在遮挡或缺失时),上述目标函数仍然可以使用,只是求和中的相应项将被省略。

精细化级联网络(分别修正每个关节点的位置)

上一小节的初始网络是以整个图像作为输入,要预测图像中所有的关节点(单人)。但此网络在观察细节方面的能力有限——它学习的是在粗尺度上捕捉姿态属性的滤波器,这些滤波器不足以精确定位人体关节。为了实现更高的精度,作者提出级级联的姿态回归器。
在这里插入图片描述
在第一阶段,级联从估计初始姿态开始,如上一节所述。在后续阶段,额外的深度神经网络(DNN)回归器被训练来预测关节位置从前一阶段到真实位置的位移。因此,每个后续阶段可以被视为对当前预测姿态的细化。

每个后续阶段都以上一阶段预测出或修正后的关节位置为中心从原始高分辨率图像中裁剪出子图像,并在此子图像上应用该关节的姿态位移回归器。通过这种方式,后续的姿态回归器可以看到更高分辨率的图像,从而学习到更精细尺度的特征,最终实现更高的精度。

级联的所有阶段的网络结构都完全相同,但学习的参数不同。
对于总共 S S S个级联阶段(包括初始阶段)中的第 s ∈ { 1 , … , S } s \in \{ 1,\ldots ,S\} s{1,,S}阶段,用 θ s {\theta }_{s} θs表示学习到的网络参数。姿态位移回归器读取 ψ ( x ; θ s ) \psi \left( {x;{\theta }_{s}}\right) ψ(x;θs)。为了细化给定的关节位置 y i {\mathbf{y}}_{i} yi ,考虑一个关节边界框 b i {b}_{i} bi,该边界框捕获围绕 y i : b i ( y ; σ ) = ( y i , σ diam ⁡ ( y ) , σ diam ⁡ ( y ) ) {\mathbf{y}}_{i} : {b}_{i}\left( {\mathbf{y};\sigma }\right) = \left( {{\mathbf{y}}_{i},\sigma \operatorname{diam}\left( \mathbf{y}\right) ,\sigma \operatorname{diam}\left( \mathbf{y}\right) }\right) yi:bi(y;σ)=(yi,σdiam(y),σdiam(y))的子图像,其中心为第 i i i个关节,尺寸为姿态直径按 σ \sigma σ缩放。姿态的直径 diam ⁡ ( y ) \operatorname{diam}\left( \mathbf{y}\right) diam(y)定义为人体躯干上相对关节之间的距离,例如左肩和右髋,具体取决于具体的姿态定义和数据集。

那么,在阶段 s = 1 s = 1 s=1中,从边界框 b 0 {b}^{0} b0开始,该边界框要么包围整个图像,要么是通过人体检测器获得的,则初始姿态为:
在这里插入图片描述
在每个后续阶段 s ≥ 2 s \geq 2 s2中,对于所有关节 i ∈ { 1 , … , k } i \in \{ 1,\ldots ,k\} i{1,,k},首先通过在前一阶段(s - 1)定义的子图像 b i ( s − 1 ) {b}_{i}^{\left( s - 1\right) } bi(s1)上应用回归器,回归到一个细化位移 y i s − y i ( s − 1 ) {\mathbf{y}}_{i}^{s} -{\mathbf{y}}_{i}^{\left( s - 1\right) } yisyi(s1)。然后,估计新的关节框 b i s {b}_{i}^{s} bis
在这里插入图片描述
s ≥ 2 s \geq 2 s2 阶段中,训练方式与初始阶段基本相同,只是每个关节点使用不同的边界框来进行归一化。

疑问与解决

Q:初始阶段是对所有关节点进行粗略的预测,输出是 2 k 2k 2k维向量,而后续的级联精细化阶段只需要 2 2 2维向量表示对关节点的修正信息,那为什么初始阶段和后续级联阶段的网络结构完全一致?
A:初始阶段和后续级联阶段所需的输出的维度不一样,级联阶段网络仍输出 2 k 2k 2k维向量,但仅使用当前处理的关节点的修正量(Δx, Δy),其他维度被忽略。这种设计通过动态选择输出通道实现功能适配。例如,处理右肘关节点,级联阶段仅提取输出向量中对应右肘的Δx和Δy,其余维度不参与计算。训练时,每个级联阶段仅对当前处理的关键点的两个输出维度(Δx, Δy)计算损失,其他维度在损失函数中被赋予权重0,从而避免无关维度的干扰

代码实践

在实现中,骨干网络是利用图像分类网络,如AlexNet、ResNet等,下面是以ResNet为骨干网络进行实现的DeepPose:

  • 骨干网络:ResNet,最后一层全连接层改动,使其输出 2 k 2k 2k维向量
def create_deep_pose_model(num_keypoints: int) -> nn.Module:
    # 加载预训练的ResNet-50模型,使用ImageNet数据集上的预训练权重
    res50 = resnet50(weights=ResNet50_Weights.IMAGENET1K_V2)
    # 获取原始ResNet-50模型中全连接层的输入特征数
    in_features = res50.fc.in_features
    # 替换原有的全连接层为一个新的线性层,输出大小为num_keypoints*2,
    # 因为每个关键点需要两个坐标值(x,y)
    res50.fc = nn.Linear(in_features=in_features, out_features=num_keypoints * 2)

    return res50  # 返回修改后的模型

  • 训练
import os  

import torch  
import torch.amp  
from torch.utils.data import DataLoader  # 数据加载器
from torch.utils.tensorboard import SummaryWriter  # TensorBoard写入器,用于记录训练过程

import transforms  # 自定义的数据变换模块
from model import create_deep_pose_model  # 自定义函数,用于创建DeepPose模型
from datasets import WFLWDataset  # 自定义数据集类
from train_utils.train_eval_utils import train_one_epoch, evaluate  # 训练和评估的实用函数


# 定义获取命令行参数的解析器函数
def get_args_parser(add_help=True):
    import argparse  # 命令行选项、参数和子命令解析器

    parser = argparse.ArgumentParser(description="PyTorch DeepPose Training", add_help=add_help)  # 创建解析器实例
    parser.add_argument("--dataset_dir", type=str, default="/home/wz/datasets/WFLW", help="WFLW dataset directory")  # 数据集目录
    parser.add_argument("--device", type=str, default="cuda:0", help="training device, e.g. cpu, cuda:0")  # 训练设备
    parser.add_argument("--save_weights_dir", type=str, default="./weights", help="save dir for model weights")  # 模型权重保存目录
    parser.add_argument("--save_freq", type=int, default=10, help="save frequency for weights and generated imgs")  # 权重保存频率
    parser.add_argument("--eval_freq", type=int, default=5, help="evaluate frequency")  # 评估频率
    parser.add_argument('--img_hw', default=[256, 256], nargs='+', type=int, help='training image size[h, w]')  # 训练图像尺寸
    parser.add_argument("--epochs", type=int, default=210, help="number of epochs of training")  # 训练周期数
    parser.add_argument("--batch_size", type=int, default=32, help="size of the batches")  # 批次大小
    parser.add_argument("--num_workers", type=int, default=8, help="number of workers, default: 8")  # 数据加载线程数
    parser.add_argument("--num_keypoints", type=int, default=98, help="number of keypoints")  # 关键点数量
    parser.add_argument("--lr", type=float, default=5e-4, help="Adam: learning rate")  # 学习率
    parser.add_argument('--lr_steps', default=[170, 200], nargs='+', type=int, help='decrease lr every step-size epochs')  # 学习率衰减步骤
    parser.add_argument("--warmup_epoch", type=int, default=10, help="number of warmup epoch for training")  # 预热轮数
    parser.add_argument('--resume', default='', type=str, help='resume from checkpoint')  # 从检查点恢复训练
    parser.add_argument('--test_only', action="store_true", help='Only test the model')  # 仅测试模式

    return parser


# 主函数
def main(args):
    torch.manual_seed(1234)  # 固定随机种子以确保结果可复现
    dataset_dir = args.dataset_dir  # 数据集目录
    save_weights_dir = args.save_weights_dir  # 权重保存目录
    save_freq = args.save_freq  # 权重保存频率
    eval_freq = args.eval_freq  # 评估频率
    num_keypoints = args.num_keypoints  # 关键点数量
    num_workers = args.num_workers  # 数据加载线程数
    epochs = args.epochs  # 训练周期数
    bs = args.batch_size  # 批次大小
    start_epoch = 0  # 初始训练轮次
    img_hw = args.img_hw  # 图像尺寸
    os.makedirs(save_weights_dir, exist_ok=True)  # 创建保存权重的目录

    if "cuda" in args.device and not torch.cuda.is_available():  # 如果指定使用GPU但不可用,则回退到CPU
        device = torch.device("cpu")
    else:
        device = torch.device(args.device)
    print(f"using device: {device} for training.")  # 打印使用的设备信息

    # tensorboard writer,用于记录训练过程中的信息
    tb_writer = SummaryWriter()

    # 创建DeepPose模型实例,并将其移动到指定设备
    model = create_deep_pose_model(num_keypoints)
    model.to(device)

    # 配置数据集和数据加载器
    data_transform = {
        "train": transforms.Compose([  # 训练数据变换
            transforms.AffineTransform(scale_factor=(0.65, 1.35), rotate=45, shift_factor=0.15, fixed_size=img_hw),
            transforms.RandomHorizontalFlip(0.5),
            transforms.ToTensor(),
            transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
        ]),
        "val": transforms.Compose([  # 验证数据变换
            transforms.AffineTransform(scale_prob=0., rotate_prob=0., shift_prob=0., fixed_size=img_hw),
            transforms.ToTensor(),
            transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
        ])
    }
    train_dataset = WFLWDataset(root=dataset_dir, train=True, transforms=data_transform["train"])  # 创建训练数据集
    val_dataset = WFLWDataset(root=dataset_dir, train=False, transforms=data_transform["val"])  # 创建验证数据集

    train_loader = DataLoader(train_dataset, batch_size=bs, shuffle=True, pin_memory=True, num_workers=num_workers, collate_fn=WFLWDataset.collate_fn, persistent_workers=True)  # 创建训练数据加载器
    val_loader = DataLoader(val_dataset, batch_size=bs, shuffle=False, pin_memory=True, num_workers=num_workers, collate_fn=WFLWDataset.collate_fn, persistent_workers=True)  # 创建验证数据加载器

    # 定义优化器
    optimizer = torch.optim.Adam(model.parameters(), lr=args.lr)

    # 定义学习率调度器
    warmup_scheduler = torch.optim.lr_scheduler.LinearLR(optimizer=optimizer, start_factor=0.01, end_factor=1.0, total_iters=len(train_loader) * args.warmup_epoch)
    multi_step_scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer=optimizer, milestones=[len(train_loader) * i for i in args.lr_steps], gamma=0.1)
    lr_scheduler = torch.optim.lr_scheduler.ChainedScheduler([warmup_scheduler, multi_step_scheduler])

    if args.resume:  # 如果有恢复训练的检查点
        assert os.path.exists(args.resume)
        checkpoint = torch.load(args.resume, map_location='cpu')
        model.load_state_dict(checkpoint['model'])
        optimizer.load_state_dict(checkpoint['optimizer'])
        lr_scheduler.load_state_dict(checkpoint['lr_scheduler'])
        start_epoch = checkpoint['epoch'] + 1
        print("the training process from epoch{}...".format(start_epoch))

    if args.test_only:  # 如果仅进行测试
        evaluate(model=model, epoch=start_epoch, val_loader=val_loader, device=device, tb_writer=tb_writer, affine_points_torch_func=transforms.affine_points_torch, num_keypoints=num_keypoints, img_hw=img_hw)
        return

    for epoch in range(start_epoch, epochs):  # 开始训练循环
        # 训练一个周期
        train_one_epoch(model=model, epoch=epoch, train_loader=train_loader, device=device, optimizer=optimizer, lr_scheduler=lr_scheduler, tb_writer=tb_writer, num_keypoints=num_keypoints, img_hw=img_hw)

        # 每隔一定周期进行评估
        if epoch % eval_freq == 0 or epoch == args.epochs - 1:
            evaluate(model=model, epoch=epoch, val_loader=val_loader, device=device, tb_writer=tb_writer, affine_points_torch_func=transforms.affine_points_torch, num_keypoints=num_keypoints, img_hw=img_hw)

        # 按照设定的频率保存模型权重
        if epoch % save_freq == 0 or epoch == args.epochs - 1:
            save_files = {'model': model.state_dict(), 'optimizer': optimizer.state_dict(), 'lr_scheduler': lr_scheduler.state_dict(), 'epoch': epoch}
            torch.save(save_files, os.path.join(save_weights_dir, f"model_weights_{epoch}.pth"))


if __name__ == '__main__':
    args = get_args_parser().parse_args()  # 解析命令行参数
    main(args)  # 调用主函数

测试人脸检测:
在这里插入图片描述
预测结果:
在这里插入图片描述

总结

DeepPose作为首个将深度神经网络引入人体姿态估计的经典框架,通过级联回归结构实现了单人关键点的高效检测。其核心流程分为两个阶段:在初始阶段(Initial Stage),模型通过归一化人体边界框坐标构建尺度不变的输入,利用卷积网络直接回归输入图像中所有关节点的位置;在后续级联阶段(Cascade),模型基于上一阶段预测结果对局部图像区域进行精细化裁剪,通过多层级联DNN逐步修正关节点偏移量,最终输出精确的关节点位置。这种端到端的回归方法简化了传统流程,但存在对局部上下文细节捕捉不足的局限性,且依赖高分辨率输入导致计算成本较高。未来研究可结合多尺度特征融合提升遮挡场景下的鲁棒性,或引入轻量化设计优化实时性,同时探索与多模态数据(如骨骼几何关系)的协同建模以突破单帧图像的空间约束。

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

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

相关文章

ARM Linux LCD上实时预览摄像头画面

文章目录 1、前言2、环境介绍3、步骤4、应用程序编写4.1、lcd初始化4.2、摄像头初始化4.3、jpeg解码4.4、开启摄像头4.5、完整的程序如下 5、测试5.1、编译应用程序5.2、运行应用程序 6、总结 1、前言 本次应用程序主要针对支持MJPEG格式输出的UVC摄像头。 2、环境介绍 rk35…

MacOS本地部署Deepseek,不联网也可以使用AI,保护隐私

苹果笔记本本地部署deepseek主要用到Ollama与open-webui 1. 安装Ollama “Ollama” 是一个轻量级的 AI 模型运行时环境(runtime),旨在简化在本地部署和使用大语言模型(LLM)的过程。它由 Vicarious 公司开发&#xff…

Sqlserver安全篇之_启用TLS即配置SQL Server 数据库引擎以加密连接

官方文档 https://learn.microsoft.com/zh-cn/sql/database-engine/configure-windows/configure-sql-server-encryption?viewsql-server-ver16 https://learn.microsoft.com/zh-cn/sql/database-engine/configure-windows/manage-certificates?viewsql-server-ver15&pre…

创建一个MCP服务器,并在Cline中使用,增强自定义功能。

MCP介绍 MCP 是一个开放协议,它标准化了应用程序如何向LLMs提供上下文。可以将 MCP 视为 AI 应用程序的 USB-C 端口。正如 USB-C 提供了一种标准化的方法来将您的设备连接到各种外围设备和配件一样,MCP 提供了一种标准化的方法来将 AI 模型连接到不同的…

游戏引擎学习第131天

仓库:https://gitee.com/mrxiao_com/2d_game_3 运行游戏并识别我们的小问题 今天的工作重点是对游戏引擎进行架构优化,特别是针对渲染和多线程的部分。目前,我们的目标是让地面块在独立线程上进行渲染,以提高性能。在此过程中,我…

人大金仓国产数据库与PostgreSQL

一、简介 在前面项目中,我们使用若依前后端分离整合人大金仓,在后续开发过程中,我们经常因为各种”不适配“问题,但可以感觉得到大部分问题,将人大金仓视为postgreSQL就能去解决大部分问题。据了解,Kingba…

MacBook Pro使用FFmpeg捕获摄像头与麦克风推流音视频

FFmpeg查看macos系统音视频设备列表 ffmpeg -f avfoundation -list_devices true -i "" 使用摄像头及麦克风同时推送音频及视频流: ffmpeg -f avfoundation -pixel_format yuyv422 -framerate 30 -i "0:1" -c:v libx264 -preset ultrafast -b:v 1000k -…

APISIX Dashboard上的配置操作

文章目录 登录配置路由配置消费者创建后端服务项目配置上游再创建一个路由测试 登录 http://192.168.10.101:9000/user/login?redirect%2Fdashboard 根据docker 容器里的指定端口: 配置路由 通过apisix 的API管理接口来创建(此路由,直接…

计算机毕业设计SpringBoot+Vue.js人力资源管理系统(源码+文档+PPT+讲解)

温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…

腾讯云扩容记录

腾讯云扩容: sudo yum install -y cloud-utils-growpart 安装扩容工具 sudo file -s /dev/vda1 有数据 sudo LC_ALLen_US.UTF-8 growpart /dev/vda 1 sudo resize2fs /dev/vda1 df -Th 完毕 以下是对执行的命令的详细解释以及背后的原理: 1. 安装 cloud…

Cherry Studio + 火山引擎 构建个人AI智能知识库

🍉在信息化时代,个人知识库的构建对于提高工作效率、知识管理和信息提取尤为重要。尤其是当这些知识库能结合人工智能来智能化地整理、分类和管理数据时,效果更为显著。我最近尝试通过 Cherry Studio 和 火山引擎 来搭建个人智能知识库&#…

完美解锁便捷版!

视频文件的种类繁多,包括常见的格式如MP4、AVI、MOV、MKV等。随着视频技术的发展,新的编码格式如HEVC(H.265)和AV1也逐渐被广泛应用;视频文件通常会经过压缩,并且每种格式都有其独特的编码方式和特性&#…

JAVA SE 包装类和泛型

文章目录 📕1. 包装类✏️1.1 基本数据类型和对应的包装类✏️1.2 装箱和拆箱✏️1.3 自动装箱和自动拆箱 📕2. 泛型✏️2.1 泛型的语法✏️2.2 泛型类的使用✏️2.3 裸类型(Raw Type)✏️2.4 擦除机制✏️2.5 泛型的上界✏️2.6 泛型方法✏️2.7 通配符…

人工智能AI在汽车设计领域的应用探索

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 简单,单纯,喜欢独处,独来独往,不易合同频过着接地气的生活…

Vue3国际化开发实战:i18n-Ally + vue-i18n@next高效配置教程,项目中文显示

本文详解 Vue3 国际化开发全流程:从安装 vue-i18nnext 到配置多语言文件(JSON/YAML),结合 i18n-Ally 插件实现高效翻译管理。重点涵盖: 工程配置:创建 i18n 实例、模块化语言文件结构(支持命名…

深入理解Spring @Async:异步编程的利器与实战指南

一、为什么需要异步编程? 在现代高并发系统中,同步阻塞式编程会带来两大核心问题: // 同步处理示例 public void processOrder(Order order) {// 1. 保存订单(耗时50ms)orderRepository.save(order); // 2. 发送短信…

java后端开发day25--阶段项目(二)

(以下内容全部来自上述课程) 1.美化界面 private void initImage() {//路径分两种://1.绝对路径:从盘符开始写的路径 D:\\aaa\\bbb\\ccc.jpg//2.相对路径:从当前项目开始写的路径 aaa\\bbb\\ccc.jpg//添加图片的时…

【 开发知识点 一 】 随机数生成器 /dev/urandom 和 /dev/random

文章目录 一、随机数生成器 是什么 ?二、为什么 需要 随机数生成器 ?三、随机数生成器 基本原理四、随机数生成器 三个输出接口五、随机生成器 应用1、简单应用2、项目应用一、随机数生成器 是什么 ? /dev/random 和 /dev/urandom 是 Linux 上的字符设备文件,它们是随机数…

(动态规划 最长递增的子序列)leetcode 300

这道题我第一眼反应就是暴力,但是暴力的话就是n*n-1*n-2*...n-(n-1) 也就是O(n^n)dfs做绝对超时 贪心也不行,这里是子序列,要考虑在ni的范围内考虑多种路线取最优,所以用动态规划 如何用动态规划呢? 答:…

小皮网站搭建

前提:小皮的安装下载 1、在www目录下创建一个新的文件夹,用来存放网站源码; 2、安装数据库管理工具phpMyadmin 3、新建数据表 添加字段 4、创建网站 5、前端的登录代码 注册 后端php 网页展示 登录成功跳转welcome.php