YOLOv8改进 | 2023 | MPDIoU、InnerMPDIoU助力细节涨点

news2024/11/17 13:39:51

论文地址:官方论文地址点击即可跳转

代码地址:官方并没有开源的该损失的函数的代码,我根据文章内容进行了复现代码块在第三章

 一、本文介绍

本文为读者详细介绍了YOLOv8模型的最新改进,带来的改进机制是最新的损失函数MPDIoU和融合了最新的Inner思想的InnerMPDIoU(效果打爆之前的所有的损失函数)提升检测精度和处理细节方面的作用。通过深入探讨MPDIoU和InnerMPDIoU(全网首发)的工作原理和实际代码实现,本文旨在指导读者如何将这些先进的损失函数技术应用到YOLOv8模型中,以提高其性能和准确性。文章内容涵盖从理论基础、代码实现,到实际教你如何添加本文的机制到你的模型中

  专栏回顾:YOLOv8改进系列专栏——本专栏持续复习各种顶会内容——科研必备

实验效果图如下所示-> 

因为资源有限我发的文章都要做对比实验所以本次实验我只用了一百张图片检测的是安全帽训练了一百个epoch,该结果只能展示出该机制有效,但是并不能产生决定性结果,因为具体的效果还要看你的数据集和实验环境所影响。

分析下这个结果图片:最左面的是基础版本没做任何修改的,中间的只是修改了MPDIoU可以看到涨点相对于基础版本的大概有0.05个点左右,但是我增加了InnerMPDIoU的效果基本持平(我个人觉得是我的数据集原因)所以大家自己进行实验的时候可以多做一轮进行一下对比。 

目录

 一、本文介绍

二、MPDIoU的机制原理

三、MPDIoU的代码复现 

四、手把手教你添加MPDIoU到你的模型中 

 4.1 CARAFE的添加教程

五、全文总结


二、MPDIoU的机制原理

问题提出:文章指出,在目标检测和实例分割的过程中,传统的边界框回归(BBR)损失函数难以优化预测框和真实框在宽高比相同但具体尺寸不同时的情况,下面是描述现有的边界框回归的方法的计算因素总结(包括GIoU、DIoU、CIoU和EIoU)的计算因素。这些度量方法是用于评估和优化边界框回归模型性能的关键工具。虽然文章没有直接展示下图的内容,但它们包括以下几个方面:

  • GIoU(Generalized IoU):除了传统的IoU(交并比)之外,GIoU还考虑了边界框之间的包含关系和空间分布。

  • DIoU(Distance IoU):在IoU的基础上,DIoU还考虑了边界框中心点之间的距离,以改进对齐和尺度不一致的情况。

  • CIoU(Complete IoU):结合了DIoU的特点,并加入了宽高比的考虑,进一步提高了对边界框的精确度。

  • EIoU(Expected IoU):这是一种更高级的度量方法,考虑了预测边界框与真实边界框之间的预期相似度。

文章提出的MPDIoU是在这些现有度量方法的基础上发展起来的,旨在通过直接最小化预测框和真实框之间的关键点距离,提供一种易于实现的解决方案,用于计算两个轴对齐矩形之间的MPDIoU​

 

  

MPDIoU的提出:为了克服这一挑战,文章提出了一种新的边界框相似度度量方法——MPDIoU(Minimum Point Distance Intersection over Union)。MPDIoU是基于水平矩形的最小点距离来计算的,能够综合考虑重叠区域、中心点距离以及宽度和高度的偏差。

下图展示了两种不同的边界框回归结果情况。其中,绿色框代表真实的边界框而红色框代表预测的边界框。在这两种情况下,传统的损失函数(如GIoU、DIoU、CIoU和EIoU)计算出的损失值是相同的,但是使用MPDIoU方法计算出的损失值却有所不同。这说明传统方法在某些特定情况下可能无法区分不同的预测结果,而MPDIoU能更准确地反映预测框和真实框之间的差异。

这个发现突显了MPDIoU在处理边界框回归问题上的优势,尤其是在区分具有相同宽高比但不同尺寸或位置的边界框时。MPDIoU通过直接计算预测框和真实框之间的关键点距离,提供了更精确的损失度量方法。

LMPDIoU损失函数:基于MPDIoU的概念,文章定义了一种新的损失函数LMPDIoU。LMPDIoU的公式如下:

LMPDIoU=1-MPDIoU

这一公式表明LMPDIoU损失函数与MPDIoU的相似度成反比关系,即MPDIoU越高,LMPDIoU损失越低,这推动模型预测的边界框更加接近真实框。

公式推理:在下图展示了作者提出的LMPDIoU损失函数的各种因素。

这些因素包括如何在训练阶段通过最小化损失函数来使模型预测的边界框接近其真实边界框。具体来说,每个预测的边界框

B_{prd} = \left[ \begin{array}{c} x_{prd} \\ y_{prd} \\ w_{prd} \\ h_{prd} \end{array} \right]

通过最小化以下损失函数来逼近其真实边界框:

B_{gt} = [x_{gt}, y_{gt}, w_{gt}, h_{gt}]^T 

L = \min_{\Theta} L(B_{gt}, B_{prd} | \Theta) 

其中,B_{gt} 是真实边界框的集合,而 \Theta 是回归深度模型的参数。文章中提出的LMPDIoU损失函数公式为: 

LMPDIoU=1-MPDIoU

实验验证:通过在多个数据集(如PASCAL VOC、MS COCO和IIIT5k)上对YOLACT和YOLOv7等模型的训练和测试,文章验证了MPDIoU和LMPDIoU在实际应用中的有效性。实验结果显示,这种新的损失函数在多个方面优于传统的损失函数,尤其是在处理具有相似宽高比但不同尺寸的边界框时。

下面是一些检测效果对比图 

总结来说,文章通过引入MPDIoU和LMPDIoU(我又将其和Inner的思想结合了在一起形成了InnerMPDIoU双重提高了效果),提供了一种新的视角来优化目标检测中的边界框回归问题,同时通过实验验证了其在提高检测模型准确性方面的有效性。

三、MPDIoU的代码复现 

论文中不仅提出了MPDIoU还提出了一个LMPDIoU但是这个LMPDIoU我用了以后模型根本收敛不了,所以我不知道这是我数据集的原因还是其它原因导致的,但是MPDIoU我使用效果是非常好的,其中我还添加了Focus和Inner的思想, 如果你Inner和MPDIoU都设置为True使用的就是InnerMPDIoU,如果Inner为False但是MPDIoU设置为True就是MPDIoU,Focus同理,支持FocusInnerMPDIoU,所以大家可以多进行尝试。 

class WIoU_Scale:
    ''' monotonous: {
            None: origin v1
            True: monotonic FM v2
            False: non-monotonic FM v3
        }
        momentum: The momentum of running mean'''

    iou_mean = 1.
    monotonous = False
    _momentum = 1 - 0.5 ** (1 / 7000)
    _is_train = True

    def __init__(self, iou):
        self.iou = iou
        self._update(self)

    @classmethod
    def _update(cls, self):
        if cls._is_train: cls.iou_mean = (1 - cls._momentum) * cls.iou_mean + \
                                         cls._momentum * self.iou.detach().mean().item()

    @classmethod
    def _scaled_loss(cls, self, gamma=1.9, delta=3):
        if isinstance(self.monotonous, bool):
            if self.monotonous:
                return (self.iou.detach() / self.iou_mean).sqrt()
            else:
                beta = self.iou.detach() / self.iou_mean
                alpha = delta * torch.pow(gamma, beta - delta)
                return beta / alpha
        return 1

def bbox_iou(box1, box2, x1y1x2y2=True, ratio=1, GIoU=False, DIoU=False, CIoU=False, SIoU=False,
             EIoU=False, WIoU=False, MPDIoU=False, LMPDIoU=False, Inner=False, Focal=False, alpha=1, gamma=0.5,
             scale=False, eps=1e-7):
    if Inner:
        (x1, y1, w1, h1), (x2, y2, w2, h2) = box1.chunk(4, -1), box2.chunk(4, -1)
        w1_, h1_, w2_, h2_ = w1 / 2, h1 / 2, w2 / 2, h2 / 2

        # Inner-IoU      #Inner-IoU        #Inner-IoU        #Inner-IoU        #Inner-IoU        #Inner-IoU        #Inner-IoU
        b1_x1, b1_x2, b1_y1, b1_y2 = x1 - w1_ * ratio, x1 + w1_ * ratio, \
                                                             y1 - h1_ * ratio, y1 + h1_ * ratio
        b2_x1, b2_x2, b2_y1, b2_y2 = x2 - w2_ * ratio, x2 + w2_ * ratio, \
                                                             y2 - h2_ * ratio, y2 + h2_ * ratio
        inter = (torch.min(b1_x2, b2_x2) - torch.max(b1_x1, b2_x1)).clamp(0) * \
                      (torch.min(b1_y2, b2_y2) - torch.max(b1_y1, b2_y1)).clamp(0)
        union = w1 * ratio * h1 * ratio + w2 * ratio * h2 * ratio - inter + eps

        iou = inter / union  # inner_iou

    else:
        # Returns the IoU of box1 to box2. box1 is 4, box2 is nx4
        box2 = box2.T
        # Get the coordinates of bounding boxes
        if x1y1x2y2:  # x1, y1, x2, y2 = box1
            b1_x1, b1_y1, b1_x2, b1_y2 = box1[0], box1[1], box1[2], box1[3]
            b2_x1, b2_y1, b2_x2, b2_y2 = box2[0], box2[1], box2[2], box2[3]
        else:  # transform from xywh to xyxy
            b1_x1, b1_x2 = box1[0] - box1[2] / 2, box1[0] + box1[2] / 2
            b1_y1, b1_y2 = box1[1] - box1[3] / 2, box1[1] + box1[3] / 2
            b2_x1, b2_x2 = box2[0] - box2[2] / 2, box2[0] + box2[2] / 2
            b2_y1, b2_y2 = box2[1] - box2[3] / 2, box2[1] + box2[3] / 2

        # Intersection area
        inter = (torch.min(b1_x2, b2_x2) - torch.max(b1_x1, b2_x1)).clamp(0) * \
                (torch.min(b1_y2, b2_y2) - torch.max(b1_y1, b2_y1)).clamp(0)

        # Union Area
        w1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1 + eps
        w2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1 + eps
        union = w1 * h1 + w2 * h2 - inter + eps

        # IoU
        # iou = inter / union # ori iou
        iou = torch.pow(inter / (union + eps), alpha)  # alpha iou

    if scale:
        self = WIoU_Scale(1 - (inter / union))

    if CIoU or DIoU or GIoU or EIoU or SIoU or WIoU or MPDIoU or LMPDIoU:
        cw = b1_x2.maximum(b2_x2) - b1_x1.minimum(
            b2_x1)  # convex (smallest enclosing box) width
        ch = b1_y2.maximum(b2_y2) - b1_y1.minimum(b2_y1)  # convex height
        if CIoU or DIoU or EIoU or SIoU or WIoU or MPDIoU or LMPDIoU:  # Distance or Complete IoU
            # https://arxiv.org/abs/1911.08287v1
            c2 = (cw ** 2 + ch ** 2) ** alpha + eps  # convex diagonal squared
            rho2 = (((b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2 + (
                    b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2) / 4) ** alpha  # center dist ** 2
            if CIoU:  # https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47
                v = (4 / math.pi ** 2) * (torch.atan(w2 / h2) - torch.atan(w1 / h1)).pow(2)
                with torch.no_grad():
                    alpha_ciou = v / (v - iou + (1 + eps))
                if Focal:
                    return iou - (rho2 / c2 + torch.pow(v * alpha_ciou + eps, alpha)), torch.pow(
                        inter / (union + eps),
                        gamma)  # Focal_CIoU
                else:
                    return iou - (rho2 / c2 + torch.pow(v * alpha_ciou + eps, alpha))  # CIoU
            elif MPDIoU:
                d1 = (b2_x1 - b1_x1) ** 2 + (b2_y1 - b1_y1) ** 2
                d2 = (b2_x2 - b1_x2) ** 2 + (b2_y2 - b1_y2) ** 2
                w = (b2_x2 - b2_x1)   # x2 - x1
                h = (b2_y2 - b2_y1)  # y2 - y1
                if Focal:
                    return iou - ((d1 + d2) / (w ** 2 + h ** 2)), torch.pow(inter / (union + eps), gamma)  # Focal_MPDIoU
                else:
                    return iou - ((d1 + d2)/(w ** 2 + h ** 2))
            elif LMPDIoU:
                d1 = (b2_x1 - b1_x1) ** 2 + (b2_y1 - b1_y1) ** 2
                d2 = (b2_x2 - b1_x2) ** 2 + (b2_y2 - b1_y2) ** 2
                w = (b2_x2 - b2_x1)   # x2 - x1
                h = (b2_y2 - b2_y1)  # y2 - y1
                if Focal:
                    return 1 - (iou - ((d1 + d2)/(w ** 2 + h ** 2))), torch.pow(inter / (union + eps), gamma)  # Focal_MPDIo  # MPDIoU
                else:
                    return 1 - (iou - ((d1 + d2) / (w ** 2 + h ** 2)))
            elif EIoU:
                rho_w2 = ((b2_x2 - b2_x1) - (b1_x2 - b1_x1)) ** 2
                rho_h2 = ((b2_y2 - b2_y1) - (b1_y2 - b1_y1)) ** 2
                cw2 = torch.pow(cw ** 2 + eps, alpha)
                ch2 = torch.pow(ch ** 2 + eps, alpha)
                if Focal:
                    return iou - (rho2 / c2 + rho_w2 / cw2 + rho_h2 / ch2), torch.pow(
                        inter / (union + eps),
                        gamma)  # Focal_EIou
                else:
                    return iou - (rho2 / c2 + rho_w2 / cw2 + rho_h2 / ch2)  # EIou
            elif SIoU:
                # SIoU Loss https://arxiv.org/pdf/2205.12740.pdf
                s_cw = (b2_x1 + b2_x2 - b1_x1 - b1_x2) * 0.5 + eps
                s_ch = (b2_y1 + b2_y2 - b1_y1 - b1_y2) * 0.5 + eps
                sigma = torch.pow(s_cw ** 2 + s_ch ** 2, 0.5)
                sin_alpha_1 = torch.abs(s_cw) / sigma
                sin_alpha_2 = torch.abs(s_ch) / sigma
                threshold = pow(2, 0.5) / 2
                sin_alpha = torch.where(sin_alpha_1 > threshold, sin_alpha_2, sin_alpha_1)
                angle_cost = torch.cos(torch.arcsin(sin_alpha) * 2 - math.pi / 2)
                rho_x = (s_cw / cw) ** 2
                rho_y = (s_ch / ch) ** 2
                gamma = angle_cost - 2
                distance_cost = 2 - torch.exp(gamma * rho_x) - torch.exp(gamma * rho_y)
                omiga_w = torch.abs(w1 - w2) / torch.max(w1, w2)
                omiga_h = torch.abs(h1 - h2) / torch.max(h1, h2)
                shape_cost = torch.pow(1 - torch.exp(-1 * omiga_w), 4) + torch.pow(1 - torch.exp(-1 * omiga_h), 4)
                if Focal:
                    return iou - torch.pow(0.5 * (distance_cost + shape_cost) + eps, alpha), torch.pow(
                        inter / (union + eps), gamma)  # Focal_SIou
                else:
                    return iou - torch.pow(0.5 * (distance_cost + shape_cost) + eps, alpha)  # SIou
            elif WIoU:
                if Focal:
                    raise RuntimeError("WIoU do not support Focal.")
                elif scale:
                    return getattr(WIoU_Scale, '_scaled_loss')(self), (1 - iou) * torch.exp(
                        (rho2 / c2)), iou  # WIoU https://arxiv.org/abs/2301.10051
                else:
                    return iou, torch.exp((rho2 / c2))  # WIoU v1
            if Focal:
                return iou - rho2 / c2, torch.pow(inter / (union + eps), gamma)  # Focal_DIoU
            else:
                return iou - rho2 / c2  # DIoU

        c_area = cw * ch + eps  # convex area
        if Focal:
            return iou - torch.pow((c_area - union) / c_area + eps, alpha), torch.pow(
                inter / (union + eps),
                gamma)  # Focal_GIoU https://arxiv.org/pdf/1902.09630.pdf
        else:
            return iou - torch.pow((c_area - union) / c_area + eps,
                                         alpha)  # GIoU https://arxiv.org/pdf/1902.09630.pdf
    if Focal:
        return iou, torch.pow(inter / (union + eps), gamma)  # Focal_IoU
    else:
        return iou  # IoU

四、手把手教你添加MPDIoU到你的模型中 

 4.1 CARAFE的添加教程

添加教程这里不再重复介绍、因为专栏内容有许多,添加过程又需要截特别图片会导致文章大家读者也不通顺如果你已经会添加注意力机制了,可以跳过本章节,如果你还不会,大家可以看我下面的文章,里面详细的介绍了拿到一个任意机制(C2f、Conv、Bottleneck、Loss、DetectHead)如何添加到你的网络结构中去。

本为提到损失函数里面也有详细版本的教程,再次强调一下使用方法:如果你Inner和MPDIoU都设置为True使用的就是InnerMPDIoU,如果Inner为False但是MPDIoU设置为True就是MPDIoU,Focus同理,还支持FocusInnerMPDIoU。 

添加教程->YOLOv8改进 | 如何在网络结构中添加注意力机制、C2f、卷积、Neck、检测头

这里顺便推荐一下我之前的博客讲的是InnerIoU这个损失函数的思想我做了很多次实验都可以有效涨点,里面进行了详细的介绍大家有兴趣可以进行回顾。

InnerIoU回顾:YOLOv8改进 | 2023 | InnerIoU、InnerSIoU、InnerWIoU、FocusIoU等损失函数

五、全文总结

到此本文的正式分享内容就结束了,在这里给大家推荐我的YOLOv8改进有效涨点专栏,本专栏目前为新开的平均质量分98分,后期我会根据各种最新的前沿顶会进行论文复现,也会对一些老的改进机制进行补充,目前本专栏免费阅读(暂时,大家尽早关注不迷路~),如果大家觉得本文帮助到你了,订阅本专栏,关注后续更多的更新~

专栏回顾:YOLOv8改进系列专栏——本专栏持续复习各种顶会内容——科研必备

 

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

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

相关文章

在游戏开发中,实时渲染和离线渲染对于游戏平衡的影响有哪些?

实时渲染和离线渲染对游戏平衡有那些影响呢?在游戏开发中,渲染方式的选择对游戏的整体表现和玩家体验有着至关重要的作用。那么,实时渲染和离线渲染究竟有哪些利弊呢? 一、实时渲染 实时渲染,顾名思义,是…

Windows核心编程 进程间通信

目录 进程间通信概述 发送消息 WM_COPYDATA DLL共享段 文件映射 文件相关API CreateFile ReadFile WriteFile CloseHandle SetFilePointerEx 设置文件指针 获取文件大小 GetFileSize 结构体 LARGE_INTEGER 文件映射用于读写文件数据 文件映射用于进程间通信(带文…

Xilinx Zynq-7000系列FPGA实现视频拼接显示,提供两套工程源码和技术支持

目录 1、前言免责声明 2、相关方案推荐FPGA图像处理方案FPGA视频拼接叠加融合方案推荐 3、设计思路详解Video Mixer介绍 4、工程代码1:2路视频拼接 HDMI 输出PL 端 FPGA 逻辑设计PS 端 SDK 软件设计 5、工程代码2:4路视频拼接 HDMI 输出PL 端 FPGA 逻辑设…

【SpringBoot篇】阿里云OSS—存储文件的利器

文章目录 🌹什么是阿里云OSS⭐阿里云OSS的优点 🏳️‍🌈为什么要使用云服务OSS🎄使用步骤⭐OSS开通⭐参考官方SDK 🍔编写代码⭐上传文件 🌹综合案例 🌹什么是阿里云OSS 阿里云对象存储&#xf…

css给盒子写四个角

如图:之前一直用定位 现在发现可以用css写 background: linear-gradient(to top, #306eef, #306eef) left top no-repeat, /*上左*/ linear-gradient(to right, #306eef, #386eef) left top no-repeat, /*左上*/ linear-gradient(to left, #386eef, #306eef) righ…

Java核心知识点整理大全13-笔记

Java核心知识点整理大全-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全2-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全3-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全4-笔记-CSDN博客 Java核心知识点整理大全5-笔记-CSDN博客 Java核心知识点整理大全6…

【网易云商】构建高效 SaaS 系统的技术要点与最佳实践

SaaS 是什么 定义 相信大家都对云服务中的 IaaS、PaaS、SaaS 早就有所耳闻,现在更是衍生出了 aPaaS、iPaaS、DaaS 等等的类似概念。对于 SaaS 也有各种各样的定义,本文给出的定义是: SaaS 是一种基于互联网提供服务和软件的交付模式&#xf…

自动化部署 扩容openGauss —— Ansible for openGauss

前言 大家好,今天我们为大家推荐一套基于Ansible开发的,自动化部署及扩容openGauss的脚本工具:Ansible for openGauss(以下简称 AFO)。 通过AFO,我们只需简单修改一些配置文件,即可快速部署多种…

elasticsearch 索引库操作和文档操作

文章目录 索引库操作mapping映射属性索引库的CRUD(创建,读取,更新,删除)创建索引库和映射基本语法:示例: 查询索引库修改索引库删除索引库 文档操作新增文档查询文档删除文档修改文档全量修改增…

2023年亚太杯数学建模C题新能源汽车成品文章(思路模型代码成品)

一、翻译 新能源汽车是指采用先进的技术原理、新技术和新结构,以非常规车用燃料(非常规车用燃料是指汽油和柴油以外的燃料(非常规车用燃料是指汽油和柴油以外的燃料),并集成了汽车动力控制和驱动等先进技术的汽车。新能源汽车包括…

新版PY系列离线烧录器,支持PY002A/002B/003/030/071等MCU各封装,不同 FLASH 大小型号

PY系列离线烧录器,目前支持PY32F002A/002B/002/003/030/071/072/040/403/303 各封装、不同 FLASH 大小型号。PY离线烧录器需要搭配上位机软件使用,上位机软件可以在芯岭技术官网上下载,还包括了离线烧录器的使用说明。PY离线烧录器使用MINI U…

激光雷达报告:单月上车提前突破5万台关口!车企真实搭载「去伪存真」

高工智能汽车研究院监测数据显示,截至2023年9月,激光雷达已经连续2个月交付破5万台关口。 这也意味着,这一交付关口早于预期被突破。回溯来看,2023年6月,高工智能汽车研究院在第十四届智驾开发者大会上释放预测&#…

AIDL 如何分片传输大量 Parcelable 数据列表

本文针对 AIDL 跨进程传输大量 Parcelable 数据所产生的问题总结出一套分片传输的解决方案,并分析了一下其实现的原理。 1. 概述 大家在通过 AIDL 实现跨进程数据传输的时候,可能会遇到数据量过大导致异常的情况,通常抛出的异常如下&#xf…

【从浅识到熟知Linux】基本指令之基本权限

🎈归属专栏:从浅学到熟知Linux 🚗个人主页:Jammingpro 🐟每日一句:用博客整理整理之前学过的知识,是个不错的选择。 文章前言:本文介绍Linux中的基本权限及相关指令用法并给出示例和…

【web】Fastapi自动生成接口文档(Swagger、ReDoc )

简介 FastAPI是流行的Python web框架,适用于开发高吞吐量API和微服务(直接支持异步编程) FastAPI的优势之一:通过提供高级抽象和自动数据模型转换,简化请求数据的处理(用户不需要手动处理原始请求数据&am…

第96步 深度学习图像目标检测:FCOS建模

基于WIN10的64位系统演示 一、写在前面 本期开始,我们继续学习深度学习图像目标检测系列,FCOS(Fully Convolutional One-Stage Object Detection)模型。 二、FCOS简介 FCOS(Fully Convolutional One-Stage Object D…

通过ros系统中websocket中发送sensor_msgs::Image数据给web端显示(三)

通过ros系统中websocket中发送sensor_msgs::Image数据给web端显示(三) 不使用base64编码方式传递 #include <ros/ros.h> #include <signal.h> #include <sensor_msgs/Image.h> #include <message_filters/subscriber.h> #include <message_filter…

C#,《小白学程序》第九课:堆栈(Stack),先进后出的数据型式

1 文本格式 /// <summary> /// 《小白学程序》第九课&#xff1a;堆栈&#xff08;Stack&#xff09; /// 堆栈与队列是相似的数据形态&#xff1b;特点是&#xff1a;先进后出&#xff1b; /// 比如&#xff1a;狭窄的电梯&#xff0c;先进去的人只能最后出来&#xff1…

Springboot 南阳旅游平台-计算机毕设 附源码 31829

Springboot 南阳旅游平台 目 录 摘要 1 绪论 1.1 研究背景 1.2 研究意义 1.3 论文结构与章节安排 2 南阳旅游平台系统分析 2.1 可行性分析 2.1.1 技术可行性分析 2.1.2 经济可行性分析 2.1.3 法律可行性分析 2.2 系统功能分析 2.2.1 功能性分析 2.2.2 非功能性分析…

【matlab程序】matlab利用工具包nctool读取grib2、nc、opendaf、hdf5、hdf4等格式数据

【matlab程序】matlab利用工具包nctool读取grib2、nc、opendaf、hdf5、hdf4等格式数据 引用&#xff1a; B. Schlining, R. Signell, A. Crosby, nctoolbox (2009), Github repository, https://github.com/nctoolbox/nctoolbox Brief summary: nctoolbox is a Matlab toolbox…