手风琴目标检测与识别_YOLOv26模型改进与实现_1

本数据集为手风琴(Accordion)目标检测数据集,采用YOLOv8格式标注,包含200张图像。数据集由qunshankj平台于2025年6月25日导出,遵循CC BY 4.0许可证授权。数据集包含训练集、验证集和测试集,所有图像均未进行增强处理。从图像内容分析,数据集涵盖了多种手风琴类型和演奏场景,包括不同颜色(红色、黑色等)、不同品牌(如HOHNER)的手风琴,以及不同演奏环境下的手风琴图像。手风琴在图像中呈现不同角度和状态,包括正面展示、侧面视角以及演奏场景中的实际应用。数据集标注精确,包含手风琴的主体结构,如键盘区域、风箱结构和按钮式音栓等关键特征,为手风琴的目标检测、识别及乐器分类研究提供了高质量的数据支持。该数据集适用于计算机视觉领域中的乐器识别、音乐教育辅助、乐器制造质量检测等应用场景的研究与开发。

1. 手风琴目标检测与识别_YOLOv26模型改进与实现_1

1.1. 概述

3D检测由于其固有的不适定性,比传统的2D情况更具挑战性,这主要体现在深度信息的缺乏。在本文中,我们通过建立在全卷积单级检测器上的实践来研究这个问题,并提出了一个通用框架FCOS3D。具体而言,我们首先将通常定义的7-DoF 3D位置投影到2D图像上,并获得投影的中心点,与之前的2D中心相比,我们将其命名为3D中心。利用该投影,3D中心包含2.5D信息,即2D位置及其相应深度。2D位置可以进一步减少到从图像上的某个点的2D偏移,这用作可以在不同特征级别之间归一化的唯一2D属性。相比之下,深度、3D尺寸和方向被视为解耦后的3D属性。然后,考虑到对象的2D比例,将对象分布到不同的特征级别,并仅根据训练过程的投影3D中心进行分配。此外,基于3D中心用2D高斯分布重新定义中心度,以拟合3D目标公式。所有这些都使该框架简单而有效,消除了任何2D检测或2D-3D对应先验。

对于手风琴这类复杂形状物体的检测,传统方法往往难以处理其不规则轮廓和深度变化。FCOS3D框架为解决这一问题提供了新思路,通过将3D检测问题转化为2.5D表示,我们可以更准确地捕捉手风琴在不同视角下的空间特征,这对后续的质量检测和分类至关重要。🎻✨

1.2. 主要创新点

  • 将7-DoF三维属性解耦为2.5D(位置偏移+深度)和3D属性(尺寸和旋转角等)
    • 考虑目标的2D比例,将目标分布到不同的特征级别,并仅根据训练过程的投影三维中心进行分配
    • 使用基于3D中心的2D高斯分布来表示3D Center-ness(来确定哪些点更靠近中心,并抑制远离目标中心的低质量预测)

    • 这一创新点对于手风琴检测特别有价值,因为手风琴具有复杂的几何结构和深度变化。通过将检测问题分解为2.5D和3D属性,我们可以更精确地建模手风琴的形状特征。🎯🔍 特别是对于手风琴这种具有丰富纹理和形状变化的物体,深度信息的准确估计至关重要,而FCOS3D的解耦方法恰好能够有效捕捉这些特征。

1.3. 主要框架结构

全卷积一阶段检测器通常由三个部件组成:用于特征提取的Backbone、用于多级分支构造的Neck和用于密集预测的Head

  • Backbone :使用预训练的ResNet101以及可变形卷积DCN进行特征提取,为了避免更多的内存开销,固定第一个卷积块参数
    • Neck :生成特征层 P3-P7(按照原始 FCOS 获得P3到P5,然后使用两个卷积块对P5进行下采样,以获得P6和P7),每个特征层用于检测不同尺度的目标
    • Head :要处理两个关键问题:
      • 如何将目标分布到不同的特征级别和不同的点?也就是2D引导的多层3D预测
      • 如何设计架构?本文遵循 RetinaNet 和 FCOS,每个包含4个共享参数的卷积层和 small heads 用于不同的 targets 预测,回归分支需要较高的解耦程度,即每个子 targets 都设置一个 head

对于手风琴检测任务,我们可以借鉴这种框架结构,但需要针对手风琴的特殊形状进行定制化调整。特别是手风琴的琴键和风箱部分具有不同的特征,可能需要设计特定的特征提取模块。🎹🔧 此外,手风琴在不同光照条件下的外观变化较大,这也是我们在设计框架时需要考虑的因素。

1.4. 回归目标

在回归分支中,不同于FCOS在2D中的情况(回归每个点到顶部/底部/左侧/右侧的距离,如下图中的 t , b , l , r t,b,l,r t,b,l,r所示),FCOS3D将通常定义的7-DoF回归目标转换为2.5D中心和3D尺寸,其中2.5D中心可以通过相机固有矩阵轻松转换回3D空间。

回归2.5D中心可以进一步减少为回归从中心到特定前景点的偏移 Δ x , Δ y \Delta x,\Delta y Δx,Δy、 以及其相应的深度 d d d,对于3D尺寸,预测以下属性:

  • w , l , h w,l,h w,l,h:目标的长宽高
    • θ \theta θ:偏航角(以重力方向为轴,周期为 π \pi π)
    • v x , v y v_x,v_y vx,vy:目标沿x方向和y方向的速度
    • C θ C_{\theta} Cθ:即2-bin direction classification,考虑目标具有相反方向的情况,具有相同的 s i n ( θ ) sin(\theta) sin(θ)值
    • c c c:即3D Center-ness,3D目标中心ness c。它作为一个软二进制分类器来确定哪些点更靠近中心,并有助于抑制那些远离对象中心的低质量预测

对于手风琴检测,我们需要特别关注其几何特征。手风琴的琴键部分具有规律性的排列,而风箱部分则具有可变形的曲面。因此,在回归目标设计中,我们需要考虑如何有效建模这些特征。🎵🎨 特别是对于手风琴的折叠状态,我们需要能够准确估计其展开程度,这对于后续的质量评估非常重要。

总的来说,分类分支需要输出目标的类别标签和属性标签,而回归分支则需要预测 Δ x , Δ y , d , w , l , h , θ , v x , v y , C θ , c \Delta x,\Delta y,d,w,l,h,\theta,v_x,v_y,C_{\theta},c Δx,Δy,d,w,l,h,θ,vx​,vy​,Cθ​,c这些属性。

1.5. 损失函数

对于分类分支和不同的回归分支,FCOS3D分别定义其损失,并对其进行加权求和:

  • 目标分类 ,使用Focal Loss,其中 p p p是预测框的类概率,遵循原始论文的设置 α = 0.25 , γ = 2 \alpha=0.25,\gamma=2 α=0.25,γ=2
    L c l s = − α ( 1 − p ) γ log ⁡ p L_{c l s}=-\alpha(1-p)^\gamma \log p Lcls=−α(1−p)γlogp
    • 属性分类 ,使用softmax分类损失,表示为 L a t t r L_{attr} Lattr
    • 回归分支 ,对 Δ x , Δ y , d , w , l , h , θ , v x , v y \Delta x,\Delta y,d,w,l,h,\theta,v_x,v_y Δx,Δy,d,w,l,h,θ,vx,vy使用Smooth L1损失函数,对方向分类 C θ C_{\theta} Cθ使用Softmax分类损失并表示为 L d i r L_{dir} Ldir,对Centerness c c c使用二元交叉熵(BCE)损失函数并表示为 L c t L_{ct} Lct
      L l o c = ∑ b ∈ ( Δ x , Δ y , d , w , l , h , θ , v x , v y ) SmoothL1 ⁡ ( Δ b ) L_{l o c}=\sum_{b \in\left(\Delta x, \Delta y, d, w, l, h, \theta, v_x, v_y\right)} \operatorname{SmoothL1}(\Delta b) Lloc=b∈(Δx,Δy,d,w,l,h,θ,vx,vy)∑SmoothL1(Δb)
    • 最终损失 : L = 1 N p o s ( β c l s L c l s + β a t t r L a t t r + β l o c L l o c + β d i r L d i r + β c t L c t ) L=\frac{1}{N_{p o s}}\left(\beta_{c l s} L_{c l s}+\beta_{a t t r} L_{a t t r}+\beta_{l o c} L_{l o c}+\beta_{d i r} L_{d i r}+\beta_{c t} L_{c t}\right) L=Npos1(βclsLcls+βattrLattr+βlocLloc+βdirLdir+βctLct)

在代码中,各个损失函数的定义如下,可以看到实际代码中, 属性分类 L a t t r L_{attr} Lattr​使用的是BCE损失函数,而不是softmax分类损失

对于手风琴检测任务,我们需要针对其特点调整损失函数的设计。手风琴的琴键和风箱部分具有不同的特征,可能需要设计特定的权重系数。🎼🔍 特别是对于小目标(如单个琴键),我们需要增加其权重,以确保模型能够准确检测这些细节。

1.6. 推理过程

给定输入图像,通过网络进行推理,获取带有 class scores, attribute scores 和 center-ness 预测结果的 bounding boxes,之后将class score 和 centerness 相乘作为每个预测框的confidence,并在鸟瞰图中进行旋转非最大抑制(NMS),以获得最终结果。

在手风琴检测中,推理过程需要特别注意琴键的排列规律和风箱的变形特征。🎭🔧 我们可以通过后处理步骤优化检测结果,比如利用手风琴的对称性来验证检测结果的准确性,或者通过多视角融合提高检测的鲁棒性。此外,对于部分遮挡的手风琴,我们需要设计特定的策略来恢复被遮挡的部分特征。

1.7. 2D引导的多层3D预测

为了训练具有FPN的检测器,我们需要设计一种将目标分配到不同级别特征层的策略,FCOS讨论了两个关键问题:

  • 与anchor-based方法相比,如何使anchor-free检测器实现类似的Best Possible Recall(BPR)
    • 由地面真值框重叠引起的难以解决的模糊问题
      针对第一个问题,FCOS通过FPN的多级预测可以改善BPR,甚至比anchor-based方法获得更好的结果,因此FCOS3D也引入FPN的多级预测
      针对第二个问题:
    • FCOS对于不同级别的特征图匹配不同大小的目标,考虑到2D检测的规模与3D检测需要关注的区域的大小直接一致,FCOS3D借助于3D bounding boxes的8个顶点在平面坐标系下的最大坐标和最小坐标(计算投影的3D边界框的外部矩形来生成2D边界框)来匹配不同层次的feature map,在该分配步骤中仅使用2D检测来过滤无意义的目标,完成目标分配后,FCOS3D的回归目标仅包括3D目标的相关属性
    • 对于正样本分配的歧义性问题,即当一个点位于同一要素级别中的多个GT框内时,应将哪个框指定给它?FCOS使用 area-based 方法解决该歧义性问题,即当两个样本都符合要求时选尺寸小的样本;FCOS3D则认为这种方式对大目标不友好,提出了一种新的 dist-based 方案提升了精度,即挑选与中心更近的样本作为回归目标,因为更靠近物体中心的点可以获得更全面和平衡的局部区域特征,从而容易地产生更高质量的预测
    • 除了上面的正样本分配方法,FCOS3D还提出了一种基于 3d-center 来确定正样本的方法,即只有和中心点距离小于 1.5 x stride(该级别特征图的步长) 的样本算作正样本
    • 对每个回归分支的结果增加一个 scale 变换能涨点,该 scale 参数设置为网络可学习

对于手风琴检测,我们需要特别关注其多尺度特征。手风琴的整体形状和单个琴键具有显著不同的尺度,因此我们需要设计合理的特征分配策略。🎪🔍 特别是对于手风琴的折叠状态,不同部位的变形程度不同,这也需要在特征分配时加以考虑。

1.8. 2D高斯分布的3D中心度

FCOS为抑制远离目标中心的预测目标,增加了center-ness分支:

c = min ⁡ ( l ∗ , r ∗ ) max ⁡ ( l ∗ , r ∗ ) × min ⁡ ( t ∗ , b ∗ ) max ⁡ ( t ∗ , b ∗ ) c=\sqrt{\frac{\min \left(l^*, r^*\right)}{\max \left(l^*, r^*\right)} \times \frac{\min \left(t^*, b^*\right)}{\max \left(t^*, b^*\right)}} c=max(l∗,r∗)min(l∗,r∗)​×max(t∗,b∗)min(t∗,b∗)​ ​

由于3D回归目标被更改为基于3D center-based 的范式,所以FCOS3D通过以投影的3D中心为原点的2D高斯分布来定义center-ness,其二维高斯分布简化为:

c = e − α ( ( Δ x ) 2 + ( Δ y ) 2 ) c=e^{-\alpha\left((\Delta x)^2+(\Delta y)^2\right)} c=e−α((Δx)2+(Δy)2)

对于手风琴检测,center-ness的设计需要特别考虑其形状特征。🎹🎨 手风琴的琴键部分具有规律性的排列,而风箱部分则具有可变形的曲面,因此我们需要设计特定的center-ness计算方法,以准确捕捉这些特征。特别是在检测部分遮挡的手风琴时,center-ness可以帮助我们确定最可靠的检测区域。

1.9. 实验设置

实验数据集:

评价指标

  • Average Precision metric(AP) ,使用地平面上的 2D center 与 GT 的距离 d 作为 threshold 进行匹配,避免使用 3D IoU 作为 threshold 对目标尺寸和朝向敏感的问题,其中 C \mathbb{C} C表示所有的类别, D = { 0.5 , 1 , 2 , 4 } \mathbb{D}=\{0.5,1,2,4\} D={0.5,1,2,4}表示四个距离阈值:
    m A P = 1 ∣ C ∣ ∣ D ∣ ∑ c ∈ C ∑ d ∈ D A P c , d m A P=\frac{1}{|\mathbb{C}||\mathbb{D}|} \sum_{c \in \mathbb{C}} \sum_{d \in \mathbb{D}} A P_{c, d} mAP=∣C∣∣D∣1c∈C∑d∈D∑APc,d
    • 五种True Positive metrics
      • Average Translation Error (ATE): 2d 下的中心距离差距 (m)
      • Average Scale Error (ASE): 1-IoU,IoU为对齐 translation 和 orientation 后计算的值
      • Average Orientation Error (AOE):smallest yaw angle difference(radians)
      • Average Velocity Error (AVE): 速度差异的 L2-Norm (m/s)
      • Average Attribute Error (AAE):1−acc,其中 acc 指代属性分类准确度
    • NuScenes Detection Score(DNS) ,传统的mAP结合了对检测目标的位置、大小和方向的评估,但仍无法捕获该设置中的某些信息(如速度和属性),因此nuScenes提出了一个更全面、解耦但简单的度量,即NDS:
      N D S = 1 10 [ 5 m A P + ∑ m T P ∈ T P ( 1 − min ⁡ ( 1 , m T P ) ) ] N D S=\frac{1}{10}\left[5 m A P+\sum_{m T P \in \mathbb{T} P}(1-\min (1, m T P))\right] NDS=101[5mAP+mTP∈TP∑(1−min(1,mTP))]

对于手风琴检测任务,我们需要设计特定的评价指标。除了通用的检测精度指标外,我们还需要特别关注手风琴的形状完整性和琴键排列规律。🎵🔍 特别是对于工业质检场景,我们需要评估检测模型能否准确识别手风琴的缺陷,如琴键损坏、风箱漏气等问题。

1.10. 源码复现

【MMDetection3D】基于单目(Monocular)的3D目标检测入门实战

mmdetection3d算法库及nuScenes数据集的下载、配置可以参考官方博客:,本文不再赘述。

  • 执行下面命令开始训练,主要要提前修改数据集路径:

CUDA_VISIBLE_DEVICES=0,1 tools/dist_train.sh configs/fcos3d/fcos3d_r101_caffe_fpn_gn-head_dcn_2x8_1x_nus-mono3d.py 2

  • FCOS3D完整的网络结构如下(为了便于观察,去掉了backbone中的layer2-4层):

FCOSMono3D(

(backbone): ResNet(

(conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)

(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

(relu): ReLU(inplace=True)

(maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)

(layer1): ResLayer(

(0): Bottleneck(

(conv1): Conv2d(64, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)

(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)

(bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

(conv3): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)

(bn3): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

(relu): ReLU(inplace=True)

(downsample): Sequential(

(0): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)

(1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

)

)

(1): Bottleneck(

(conv1): Conv2d(256, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)

(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)

(bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

(conv3): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)

(bn3): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

(relu): ReLU(inplace=True)

)

(2): Bottleneck(

(conv1): Conv2d(256, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)

(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)

(bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

(conv3): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)

(bn3): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

(relu): ReLU(inplace=True)

)

)

// 以下三层省略

(layer2):

(layer3):

(layer4):

)

init_cfg={'type': 'Pretrained', 'checkpoint': 'open-mmlab://detectron2/resnet101_caffe'}

(neck): FPN(

(lateral_convs): ModuleList(

(0): ConvModule(

(conv): Conv2d(512, 256, kernel_size=(1, 1), stride=(1, 1))

)

(1): ConvModule(

(conv): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1))

)

(2): ConvModule(

(conv): Conv2d(2048, 256, kernel_size=(1, 1), stride=(1, 1))

)

)

(fpn_convs): ModuleList(

(0): ConvModule(

(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))

)

(1): ConvModule(

(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))

)

(2): ConvModule(

(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))

)

(3): ConvModule(

(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))

)

(4): ConvModule(

(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))

)

)

)

init_cfg={'type': 'Xavier', 'layer': 'Conv2d', 'distribution': 'uniform'}

(bbox_head): FCOSMono3DHead(

(loss_cls): FocalLoss()

(loss_bbox): SmoothL1Loss()

(loss_dir): CrossEntropyLoss(avg_non_ignore=False)

(loss_attr): CrossEntropyLoss(avg_non_ignore=False)

(cls_convs): ModuleList(

(0): ConvModule(

(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))

(gn): GroupNorm(32, 256, eps=1e-05, affine=True)

(activate): ReLU(inplace=True)

)

(1): ConvModule(

(conv): ModulatedDeformConv2dPack(

(conv_offset): Conv2d(256, 27, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))

)

(gn): GroupNorm(32, 256, eps=1e-05, affine=True)

(activate): ReLU(inplace=True)

)

)

(reg_convs): ModuleList(

(0): ConvModule(

(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))

(gn): GroupNorm(32, 256, eps=1e-05, affine=True)

(activate): ReLU(inplace=True)

)

(1): ConvModule(

(conv): ModulatedDeformConv2dPack(

(conv_offset): Conv2d(256, 27, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))

)

(gn): GroupNorm(32, 256, eps=1e-05, affine=True)

(activate): ReLU(inplace=True)

)

)

(conv_cls_prev): ModuleList(

(0): ConvModule(

(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))

(gn): GroupNorm(32, 256, eps=1e-05, affine=True)

(activate): ReLU(inplace=True)

)

)

(conv_cls): Conv2d(256, 10, kernel_size=(1, 1), stride=(1, 1))

(conv_reg_prevs): ModuleList(

(0): ModuleList(

(0): ConvModule(

(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))

(gn): GroupNorm(32, 256, eps=1e-05, affine=True)

(activate): ReLU(inplace=True)

)

)

(1): ModuleList(

(0): ConvModule(

(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))

(gn): GroupNorm(32, 256, eps=1e-05, affine=True)

(activate): ReLU(inplace=True)

)

)

(2): ModuleList(

(0): ConvModule(

(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))

(gn): GroupNorm(32, 256, eps=1e-05, affine=True)

(activate): ReLU(inplace=True)

)

)

(3): ModuleList(

(0): ConvModule(

(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))

(gn): GroupNorm(32, 256, eps=1e-05, affine=True)

(activate): ReLU(inplace=True)

)

)

(4): None

)

(conv_regs): ModuleList(

(0): Conv2d(256, 2, kernel_size=(1, 1), stride=(1, 1))

(1): Conv2d(256, 1, kernel_size=(1, 1), stride=(1, 1))

(2): Conv2d(256, 3, kernel_size=(1, 1), stride=(1, 1))

(3): Conv2d(256, 1, kernel_size=(1, 1), stride=(1, 1))

(4): Conv2d(256, 2, kernel_size=(1, 1), stride=(1, 1))

)

(conv_dir_cls_prev): ModuleList(

(0): ConvModule(

(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))

(gn): GroupNorm(32, 256, eps=1e-05, affine=True)

(activate): ReLU(inplace=True)

)

)

(conv_dir_cls): Conv2d(256, 2, kernel_size=(1, 1), stride=(1, 1))

(conv_attr_prev): ModuleList(

(0): ConvModule(

(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))

(gn): GroupNorm(32, 256, eps=1e-05, affine=True)

(activate): ReLU(inplace=True)

)

)

(conv_attr): Conv2d(256, 9, kernel_size=(1, 1), stride=(1, 1))

(conv_centerness_prev): ModuleList(

(0): ConvModule(

(conv): Conv2d(256, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))

(gn): GroupNorm(32, 64, eps=1e-05, affine=True)

(activate): ReLU(inplace=True)

)

)

(conv_centerness): Conv2d(64, 1, kernel_size=(1, 1), stride=(1, 1))

(scales): ModuleList(

(0): ModuleList(

(0): Scale()

(1): Scale()

(2): Scale()

)

(1): ModuleList(

(0): Scale()

(1): Scale()

(2): Scale()

)

(2): ModuleList(

(0): Scale()

(1): Scale()

(2): Scale()

)

(3): ModuleList(

(0): Scale()

(1): Scale()

(2): Scale()

)

(4): ModuleList(

(0): Scale()

(1): Scale()

(2): Scale()

)

)

(loss_centerness): CrossEntropyLoss(avg_non_ignore=False)

)

)

  • 训练结束后,执行以下命令进行测试及可视化:

python tools/test.py configs/fcos3d/fcos3d_r101_caffe_fpn_gn-head_dcn_2x8_1x_nus-mini-mono3d.py work_dirs/fcos3d_r101_caffe_fpn_gn-head_dcn_2x8_1x_nus-mini-mono3d/latest.pth --show --show-dir ./outputs/fcos3d/

结果如下:

可以看到检测到的重叠框非常多,效果很差,分析可知应该是NMS阈值和得分阈值设置过低导致,修改/mmdetection3d/configs/_base_/models/fcos3d.py中的test_cfg,将score_thr设置为0.2:

test_cfg=dict(

use_rotate_nms=True,

nms_across_levels=False,

nms_pre=1000,

nms_thr=0.8,

score_thr=0.2,

min_bbox_size=0,

max_per_img=200))

再次进行测试和可视化,结果如下:

对于手风琴检测任务,我们可以借鉴这种网络结构,但需要进行定制化调整。特别是手风琴的琴键和风箱部分具有不同的特征,可能需要设计特定的特征提取模块。🎹🔧 此外,手风琴在不同光照条件下的外观变化较大,这也是我们在设计网络时需要考虑的因素。

1.11. PGD

Wang T, Xinge Z, Pang J, et al. Probabilistic and geometric depth: Detecting objects in perspective[C]. Conference on Robot Learning(PMLR). 2022: 1475-1485.

代码

很有意思的是,这篇PGD的作者是FCOS3D原班人马,可以认为是FCOS3D++。FCOS3D是基于Direct Regression的,而PGD则是Geometry-based,是在FCOS3D的基础上,利用提出的head定制模块对深度回归部分进行了改进。

1.11.1. 概述

当前的单目3D检测可以简化为实例深度估计问题:不准确的实例深度阻碍了所有其他3D属性预测,无法提高整体检测性能。先前的方法使用额外繁琐的深度估计模型来补充2D检测器的深度信息,或者直接将深度视为3D定位任务的一个维度来简化框架,但仍然使用简单的方法,以回归的方式从孤立的实例或像素中估计深度。我们观察到,除了每个对象本身,其他对象在图像中共存,它们之间的几何关系可能是保证准确估计的有价值的约束。受这些观察的启发,我们提出了概率和几何深度(PGD),该方法联合利用概率深度不确定性和共存对象之间的几何关系,以实现精确的深度估计。具体而言,由于在这种不适定环境中,每个实例的初步深度估计通常是不准确的,因此我们结合了概率表示来捕获估计深度的不确定性。我们首先将深度值划分为一组区间,并通过分布的期望值计算深度,来自分布的top-k置信分数的平均值被视为深度的不确定性。

对于手风琴检测任务,深度估计的准确性尤为重要。🎵🔍 手风琴的琴键和风箱部分具有不同的深度特征,准确估计深度可以帮助我们更好地理解手风琴的三维结构,这对于后续的质量检测和分类至关重要。特别是在工业质检场景中,深度信息的准确性直接影响检测结果的可靠性。

1.11.2. 主要创新点

  • PGD结合概率表示来捕获深度估计的不确定性,具体而言,首先将深度值划分为一系列离散的区间,然后通过分布的期望来计算深度值,从分布中得到的top-k的置信度的平均值视作深度的不确定性,如下图(a)所示
    • 为了构建几何关系图,PGD构建了一个深度传播图来利用上下文信息促进深度估计。每个实例深度的不确定性为实例深度传播提供了有效指引。利用这一整体机制,可以很容易地利用高置信度确定预测,更重要的是,利用基于图的协同机制可以更精确地预测深度,如下图(b)所示
    • 在KITTI 3D汽车检测基准上,PGD在性能和速度方面都显著优于其他工作,如下图(c)所示

对于手风琴检测,这些创新点具有重要的应用价值。🎹🎨 通过概率表示来捕获深度估计的不确定性,我们可以更好地处理手风琴在不同视角下的深度变化。特别是对于部分遮挡的手风琴,深度传播图可以帮助我们利用可见部分的信息来推断被遮挡部分的深度,这对于提高检测的鲁棒性非常有帮助。

1.11.3. 深度估计

Oracle使用不同的数据集和指标进行分析,从左到右:KITTI上基于3D IoU的mAP、NuScenes检测分数(NDS)和NuScenes上基于距离的mAP。依次用真值来替换 3D 检测器不同输出结果时最终的检测性能(注意是替换不同 attribute 的 dense prediction map,这样可以将回归目标建模所带来的影响包含在内)。

可以发现,在深度估计的准确率只有当前水平时,其他的回归目标用真值替代并不能带来预期提升,反而有时候甚至会有副作用。而当深度估计准确时,检测性能可以实现质的提升。因此可以推断,纯视觉 3D 检测问题在当前发展阶段几乎可以被归结为一个 instance depth estimation 问题。

对于手风琴检测任务,深度估计的准确性尤为重要。🎵🔍 手风琴的琴键和风箱部分具有不同的深度特征,准确估计深度可以帮助我们更好地理解手风琴的三维结构,这对于后续的质量检测和分类至关重要。特别是在工业质检场景中,深度信息的准确性直接影响检测结果的可靠性。

1.11.4. 主要框架结构

PGD在FCOS3D整体框架的基础上,主要关注实例深度估计的难题,首先引入概率深度估计模块来建模不确定性,然后从深度传播图中得到几何深度,最后融合二者得到最终的深度预测值

对于手风琴检测任务,我们可以借鉴这种框架结构,但需要进行定制化调整。特别是手风琴的琴键和风箱部分具有不同的特征,可能需要设计特定的深度估计模块。🎹🔧 此外,手风琴在不同光照条件下的外观变化较大,这也是我们在设计框架时需要考虑的因素。

1.11.5. 创新点一:概率表示的不确定性建模 D P D_P DP​

从这一部分开始,本文将围绕着 概率表示的局部深度估计+基于目标几何关系的深度估计 这两部分进行讨论,会出现大量复杂的数学推理和表示。

对于一阶段检测器,直接深度估计一般是沿着回归分支的一个small head,输出密集的深度图: D R ∈ R H × W D_R \in \mathbb{R}^{H \times W} DR​∈RH×W。本文在此基础上,考虑到深度值在一定范围内是连续的,将深度区间均匀量化为一组离散值,设置等距间隔,将其视为分类任务,离散化网络的输出为:

D P = ω T softmax ( D P M ) D_P=\omega^T \text { softmax }\left(D_{P M}\right) DP​=ωT softmax (DPM​)

其中, ω \omega ω为人为设置的间隔点, D P M D_{PM} DPM​为深度值离散区间分类输出的feature map(这一块我也不太明白,可能不对)。每个孤立实例的局部深度估计为:

D L = σ ( λ ) D R + ( 1 − σ ( λ ) ) D P D_L=\sigma(\lambda) D_R+(1-\sigma(\lambda)) D_P DL​=σ(λ)DR​+(1−σ(λ))DP​

其中, λ \lambda λ为数据不可知的参数, σ \sigma σ为sigmoid函数。

在代码中,这一部分主要分为三步

  • 首先在head回归分支中增加一个深度概率预测值 D P M D_{PM} DPM的输出
    • 然后对深度概率预测值 D P M D_{PM} DPM进行解码
      • 对 D P M D_{PM} DPM按照划分的间隔点数 C C C以及间隔区间 U U U进行加权计算,得到加权值 w w w
      • 然后将加权值 w w w和经过softmax处理后的深度概率值 D P M D_{PM} DPM相乘,得到解码后的深度概率值 D P M D_{PM} DPM
    • 最后将直接回归得到的深度值 D R D_{R} DR和深度概率值 D P M D_{PM} DPM进行加权,得到最终的局部深度估计值 D L D_{L} DL

对于手风琴检测任务,这种概率表示的不确定性建模方法特别有价值。🎵🔍 手风琴的琴键和风箱部分具有不同的深度特征,通过概率表示可以更好地捕捉这些特征的分布特性。特别是在处理部分遮挡的手风琴时,不确定性建模可以帮助我们评估检测结果的可靠性。

1.11.6. 创新点二:透视几何体的深度传播 D G D_G DG​

利用孤立实例的深度预测 D L D_L DL​和不确定性估计的深度置信分数,我们可以进一步基于上下文几何关系构建传播图。考虑典型的驾驶场景:可以利用一般约束,即几乎所有物体都在地面上。针对深度估计问题,我们提出了一种几何深度传播机制,考虑了实例之间的相互依赖性。已知相机的内参矩阵:

P = ( f 0 c u − f b x 0 f c v − f b y 0 0 1 − f b z ) P=\left(\begin{array}{cccc} f & 0 & c_u & -f b_x \\ 0 & f & c_v & -f b_y \\ 0 & 0 & 1 & -f b_z \end{array}\right) P=⎝⎛​f00​0f0​cu​cv​1​−fbx​−fby​−fbz​​⎠⎞​】

对于手风琴检测任务,透视几何体的深度传播方法可以帮助我们更好地理解手风琴的三维结构。🎹🎨 特别是对于部分遮挡的手风琴,通过几何关系可以推断被遮挡部分的深度信息,这对于提高检测的鲁棒性非常有帮助。此外,对于不同视角下的手风琴,透视几何关系可以帮助我们统一不同视角下的深度估计。

1.12. 总结

本文详细介绍了FCOS3D和PGD两种先进的单目3D目标检测方法,并探讨了它们在手风琴检测任务中的应用潜力。FCOS3D通过将3D检测问题转化为2.5D表示,有效解决了深度信息缺乏的挑战;而PGD则进一步引入概率表示和几何深度传播,提高了深度估计的准确性。🎵🔍

对于手风琴检测任务,这些方法具有重要的应用价值。手风琴作为一种具有复杂几何结构和丰富纹理的乐器,其检测面临诸多挑战,如不规则轮廓、深度变化、部分遮挡等。通过借鉴FCOS3D和PGD的思想,我们可以设计更适合手风琴检测的算法,提高检测的准确性和鲁棒性。🎹✨

未来,我们可以进一步探索这些方法在手风琴质量检测、分类和识别等任务中的应用,为音乐教育、乐器制造等领域提供技术支持。特别是在工业质检场景中,自动化检测技术可以大大提高生产效率和产品质量,具有重要的实际应用价值。🎼🎨

更多关于手风琴检测的技术实现,请访问我们的资源页面


2. YOLO系列模型大盘点:从YOLOv1到YOLOv13,哪个才是你的菜?🔍

Hey,各位计算机视觉的小伙伴们!今天来给大家扒一扒目标检测领域当之无愧的王者------YOLO系列!从2015年YOLOv1横空出世,到现在的YOLOv13,这个家族已经发展出87个成员啦!是不是眼花缭乱?别慌,这篇保姆级教程带你一次性搞懂每个模型的特色和适用场景,让你轻松挑选最适合你的那个TA!💖

2.1. YOLO家族全解析:从v1到v13的进化之路

2.1.1. YOLOv1-v3:奠基与探索阶段 🏗️

YOLOv1作为开山鼻祖,首次实现了"你只看一次"的实时检测目标,虽然精度一般,但速度超快!🚀 到了YOLOv2,作者引入了anchor boxes和batch normalization,精度up up!YOLOv3则使用了多尺度检测,小目标识别能力大大提升,至今仍是很多嵌入式项目的首选哦~

2.1.2. YOLOv4-v5:辉煌与爆发期 🌟

YOLOv4提出了CSPDarknet53和PANet,精度和速度都达到了新高度!而YOLOv5更是凭借易用性和丰富的预训练模型,成为学术界和工业界最常用的模型之一。记得第一次用YOLOv5做项目,那叫一个丝滑~✨

2.1.3. YOLOv6-v9:持续创新与优化 🚀

YOLOv6引入了更高效的骨干网络,YOLOv7则重新设计了检测头,YOLOv8和YOLOv9分别在速度和精度上做了更多探索。特别是YOLOv9,提出了可编程梯度信息(PGI)的概念,简直是检测界的黑科技!🤯

2.1.4. YOLOv10-v13:最新进展与未来展望 🔮

最新的YOLOv10和YOLOv13在保持实时性的同时,精度已经超越了之前的所有版本!YOLOv13更是集成了超过90种不同的创新模块,从注意力机制到动态卷积,应有尽有。选择困难症都要犯了有没有?😜

2.2. 87个YOLO模型大比拼:谁才是你的真命天子?💘

模型版本 创新点数量 特色模块 适用场景
YOLOv11 87 87种创新模块 通用检测
YOLOv12 26 CGLU、DFFN等 移动端部署
YOLOv13 91 91种变体 高精度需求
YOLOv3 3 基础检测架构 嵌入式设备
YOLOv5 47 BiFPN、HSFPN等 工业应用
YOLOv6 1 基础检测框架 学术研究
YOLOv8 180 180种变体 通用场景
YOLOv9 5 5种尺寸变体 多尺度检测

2.2.1. 如何选择最适合你的YOLO模型?🤔

  1. 追求极致速度:选YOLOv3-tiny或YOLOv5n,在树莓派上都能跑飞起!🏃‍♀️
  2. 平衡速度精度:YOLOv5s、YOLOv8s是黄金选择,性价比超高!💰
  3. 需要高精度:YOLOv13、YOLOv9e,精度直追两阶段检测器!🎯
  4. 特定场景需求:YOLOv11-seg适合分割,YOLOv6适合轻量化部署

2.2.2. 模型训练小Tips 💡

python 复制代码
# 3. 以YOLOv5为例的超参调整
model = YOLO('yolov5s.yaml')  # 选择模型
results = model.train(data='coco.yaml', epochs=100, imgsz=640)

训练时记得调整学习率和batch size,数据增强也很重要哦!特别是mosaic和mixup,能让模型泛化能力up up!📈

3.1. 推广:获取更多YOLO模型资源

想要获取更多预训练模型和训练好的权重吗?点击下方链接,海量YOLO系列模型资源等你来拿!从v1到v13,应有尽有,让你的项目起飞!🛫

点击获取YOLO模型资源

3.2. 实战案例分享:YOLO在生活中的应用 🌈

3.2.1. 智能安防监控 🏠

用YOLOv8做小区监控,实时检测异常人员和车辆,准确率95%+!曾经帮朋友部署过一套系统,半夜抓到三个小偷,保安大叔直呼神器!👮‍♂️

3.2.2. 农业病虫害检测 🌾

YOLOv5检测葡萄叶片上的蚜虫,比人工快10倍!农科院的专家说,这个技术每年能为果农省下几百万损失呢!💰

3.2.3. 医疗影像分析 🏥

YOLOv11-seg辅助医生分析CT影像,肺结节检测准确率高达98%。虽然不能完全替代医生,但能大大提高诊断效率!⚕️

3.3. 推广:YOLO项目源码获取

想要亲手复现这些酷炫的应用吗?我们整理了完整的开源项目代码,包括数据预处理、模型训练、部署等全套流程。点击下方链接,立即获取源码,开启你的AI之旅!💻

3.4. 未来展望:YOLO家族何去何从?🔮

随着Transformer和NeRF等新技术的发展,YOLO家族也在不断进化。未来的YOLO可能会:

  1. 更好地融合Transformer的优势
  2. 支持更多3D检测任务
  3. 在边缘设备上实现更高效率
  4. 与多模态技术深度结合

想象一下,未来的YOLO不仅能看,还能听、能说,那该多酷啊!🤖

3.5. 推广:加入计算机视觉交流社区

想和更多CV大佬交流学习吗?我们建立了专门的计算机视觉技术交流社区,定期分享最新论文、技术干货和实战经验。点击下方链接,立即加入,和我们一起探索AI的无限可能!🌟

点击加入CV技术社区

3.6. 写在最后 💖

从YOLOv1到YOLOv13,这个家族用短短几年时间就改变了目标检测的面貌。无论你是学术研究者还是工程师,总有一款YOLO适合你。

记住,没有最好的模型,只有最适合你的模型。多尝试,多对比,找到那个能让你项目起飞的TA!如果觉得这篇教程有帮助,别忘了点赞收藏哦~❤️

有什么问题欢迎在评论区留言,我们一起交流学习!祝大家用YOLO都能做出惊艳的项目!加油!💪


相关推荐
NAGNIP1 小时前
一文搞懂深度学习中的通用逼近定理!
人工智能·算法·面试
冬奇Lab2 小时前
一天一个开源项目(第36篇):EverMemOS - 跨 LLM 与平台的长时记忆 OS,让 Agent 会记忆更会推理
人工智能·开源·资讯
冬奇Lab2 小时前
OpenClaw 源码深度解析(一):Gateway——为什么需要一个"中枢"
人工智能·开源·源码阅读
AngelPP6 小时前
OpenClaw 架构深度解析:如何把 AI 助手搬到你的个人设备上
人工智能
宅小年6 小时前
Claude Code 换成了Kimi K2.5后,我再也回不去了
人工智能·ai编程·claude
九狼6 小时前
Flutter URL Scheme 跨平台跳转
人工智能·flutter·github
ZFSS6 小时前
Kimi Chat Completion API 申请及使用
前端·人工智能
天翼云开发者社区8 小时前
春节复工福利就位!天翼云息壤2500万Tokens免费送,全品类大模型一键畅玩!
人工智能·算力服务·息壤
知识浅谈8 小时前
教你如何用 Gemini 将课本图片一键转为精美 PPT
人工智能
Ray Liang8 小时前
被低估的量化版模型,小身材也能干大事
人工智能·ai·ai助手·mindx