基于MxNet实现目标检测-YoloV4【附部分源码及模型】

2023-05-16

文章目录

  • 前言
  • 目标检测发展史及意义
  • 一、数据集的准备
    • 1.标注工具的安装
    • 2.数据集的准备
    • 3.标注数据
    • 4.解释xml文件的内容
  • 二、网络结构的介绍
  • 三、代码实现
    • 0.工程目录结构如下
    • 1.导入库
    • 2.配置GPU/CPU环境
    • 3.数据加载器
    • 4.模型构建
    • 5.模型训练
      • 1.学习率设置
      • 2.优化器设置
      • 3.损失设置
      • 4.循环训练
    • 6.模型预测
  • 四、算法主入口
  • 五、训练效果展示


前言

  本文主要讲解基于mxnet深度学习框架实现目标检测,实现的模型为YoloV4

环境配置:
      python 3.8
      mxnet 1.7.0
      cuda 10.1


目标检测发展史及意义

  图像分类任务的实现可以让我们粗略的知道图像中包含了什么类型的物体,但并不知道物体在图像中哪一个位置,也不知道物体的具体信息,在一些具体的应用场景比如车牌识别、交通违章检测、人脸识别、运动捕捉,单纯的图像分类就不能完全满足我们的需求了。

  这时候,需要引入图像领域另一个重要任务:物体的检测与识别。在传统机器领域,一个典型的案例是利用HOG(Histogram of Gradient)特征来生成各种物体相应的“滤波器”,HOG滤波器能完整的记录物体的边缘和轮廓信息,利用这一滤波器过滤不同图片的不同位置,当输出响应值幅度超过一定阈值,就认为滤波器和图片中的物体匹配程度较高,从而完成了物体的检测。


一、数据集的准备

  首先我是用的是halcon数据集里边的药片,去了前边的100张做标注,后面的300张做测试,其中100张里边选择90张做训练集,10张做验证集。

1.标注工具的安装

pip install labelimg

进入cmd,输入labelimg,会出现如图的标注工具:
在这里插入图片描述

2.数据集的准备

首先我们先创建3个文件夹,如图:
在这里插入图片描述
DataImage:100张需要标注的图像
DataLabel:空文件夹,主要是存放标注文件,这个在labelimg中生成标注文件
test:存放剩下的300张图片,不需要标注
DataImage目录下和test目录的存放样子是这样的(以DataImage为例):
在这里插入图片描述

3.标注数据

  首先我们需要在labelimg中设置图像路径和标签存放路径,如图:
在这里插入图片描述
  然后先记住快捷键:w:开始编辑,a:上一张,d:下一张。这个工具只需要这三个快捷键即可完成工作。
  开始标注工作,首先按下键盘w,这个时候进入编辑框框的模式,然后在图像上绘制框框,输入标签(框框属于什么类别),即可完成物体1的标注,一张物体可以多个标注和多个类别,但是切记不可摸棱两可,比如这张图像对于某物体标注了,另一张图像如果出现同样的就需要标注,或者标签类别不可多个,比如这个图象A物体标注为A标签,下张图的A物体标出成了B标签,最终的效果如图:
在这里插入图片描述
最后标注完成会在DataLabel中看到标注文件,json格式:
在这里插入图片描述

4.解释xml文件的内容

在这里插入图片描述
xml标签文件如图,我们用到的就只有object对象,对其进行解析即可。


二、网络结构的介绍

论文地址:https://arxiv.org/pdf/2004.10934.pdf
网络结构:
图片来自于https://blog.csdn.net/qq_18824345/article/details/123514233

  就是说这个YOLO-v4算法是在原有YOLO目标检测架构的基础上,采用了近些年CNN领域中最优秀的优化策略,从数据处理、主干网络、网络训练、激活函数、损失函数等各个方面都有着不同程度的优化,虽没有理论上的创新,但是会受到许许多多的工程师的欢迎,各种优化算法的尝试。文章如同于目标检测的trick综述,效果达到了实现FPS与Precision平衡的目标检测 new baseline。


三、代码实现

0.工程目录结构如下

在这里插入图片描述
core:损失计算及一些核心计算的文件都存放在此文件夹
data:数据加载的相关函数及类
net:包含主干网络结构及标准的YoloV4结构
utils:数据预处理的相关文件
Ctu_YoloV4.py:YoloV4的训练类和测试类,是整个AI的主入口


1.导入库

import os, time, warnings,json,sys,cv2,colorsys,copy
sys.path.append('.')
import numpy as np
import mxnet as mx
from mxnet import nd
from PIL import Image,ImageFont,ImageDraw
from mxnet import gluon
from mxnet import autograd
from mxnet.contrib import amp
from data.data_loader import VOCDetection, VOC07MApMetric
from data.data_mixup import MixupDetection
from nets.yolo import get_yolov4
from data.batchify_fn import Tuple,Pad,Stack
from data.data_transform import YOLO3DefaultTrainTransform,YOLO3DefaultValTransform,RandomTransformDataLoader
from core.lr_scheduler import LRScheduler,LRSequential

2.配置GPU/CPU环境

self.ctx = [mx.gpu(int(i)) for i in USEGPU.split(',') if i.strip()]
self.ctx = self.ctx if self.ctx else [mx.cpu()]

3.数据加载器

这里输入的是迭代器,后面都会利用它构建训练的迭代器

class VOCDetection(dataset.Dataset):
    def CreateDataList(self,IMGDir,XMLDir):
        ImgList = os.listdir(IMGDir)
        XmlList = os.listdir(XMLDir)
        classes = []
        dataList=[]
        for each_jpg in ImgList:
            each_xml = each_jpg.split('.')[0] + '.xml'
            if each_xml in XmlList:
                dataList.append([os.path.join(IMGDir,each_jpg),os.path.join(XMLDir,each_xml)])
                with open(os.path.join(XMLDir,each_xml), "r", encoding="utf-8") as in_file:
                    tree = ET.parse(in_file)
                    root = tree.getroot()
                    for obj in root.iter('object'):
                        cls = obj.find('name').text
                        if cls not in classes:
                            classes.append(cls)
        return dataList,classes

    def __init__(self, ImageDir, XMLDir,transform=None):
        self.datalist,self.classes_names = self.CreateDataList(ImageDir,XMLDir)
        self._transform = transform
        self.index_map = dict(zip(self.classes_names, range(len(self.classes_names))))
        # self._label_cache = self._preload_labels()

    @property
    def classes(self):
        return self.classes_names

    def __len__(self):
        return len(self.datalist)

    def __getitem__(self, idx):
        img_path = self.datalist[idx][0]
        # label = self._label_cache[idx] if self._label_cache else self._load_label(idx)
        label = self._load_label(idx)
        img = mx.image.imread(img_path, 1)
        if self._transform is not None:
            return self._transform(img, label)
        return img, label.copy()

    def _preload_labels(self):
        return [self._load_label(idx) for idx in range(len(self))]

    def _load_label(self, idx):
        anno_path = self.datalist[idx][1]
        root = ET.parse(anno_path).getroot()
        size = root.find('size')
        width = float(size.find('width').text)
        height = float(size.find('height').text)
        label = []
        for obj in root.iter('object'):
            try:
                difficult = int(obj.find('difficult').text)
            except ValueError:
                difficult = 0
            cls_name = obj.find('name').text.strip().lower()
            if cls_name not in self.classes:
                continue
            cls_id = self.index_map[cls_name]
            xml_box = obj.find('bndbox')
            xmin = (float(xml_box.find('xmin').text) - 1)
            ymin = (float(xml_box.find('ymin').text) - 1)
            xmax = (float(xml_box.find('xmax').text) - 1)
            ymax = (float(xml_box.find('ymax').text) - 1)
            try:
                self._validate_label(xmin, ymin, xmax, ymax, width, height)
                label.append([xmin, ymin, xmax, ymax, cls_id, difficult])
            except AssertionError as e:
                pass
        return np.array(label)

    def _validate_label(self, xmin, ymin, xmax, ymax, width, height):
        assert 0 <= xmin < width, "xmin must in [0, {}), given {}".format(width, xmin)
        assert 0 <= ymin < height, "ymin must in [0, {}), given {}".format(height, ymin)
        assert xmin < xmax <= width, "xmax must in (xmin, {}], given {}".format(width, xmax)
        assert ymin < ymax <= height, "ymax must in (ymin, {}], given {}".format(height, ymax)


4.模型构建

本项目使用YoloV4的代码


class YOLOV4(gluon.HybridBlock):
    def __init__(self, anchors, strides, classes, alloc_size=(128, 128), nms_thresh=0.45, nms_topk=400, post_nms=100, pos_iou_thresh=1.0, ignore_iou_thresh=0.7, **kwargs):
        super(YOLOV4, self).__init__(**kwargs)
        self._classes = classes
        self.nms_thresh = nms_thresh
        self.nms_topk = nms_topk
        self.post_nms = post_nms
        self._pos_iou_thresh = pos_iou_thresh
        self._ignore_iou_thresh = ignore_iou_thresh
        if pos_iou_thresh >= 1:
            self._target_generator = YOLOV3TargetMerger(len(classes), ignore_iou_thresh)
        else:
            raise NotImplementedError("pos_iou_thresh({}) < 1.0 is not implemented!".format(pos_iou_thresh))
        self._loss = YOLOV3Loss()
        with self.name_scope():
            # backbone
            self.backbone = CSPDDarkNet53()
            # Neck
            self.Neck = Neck()
            self.Outputs = nn.HybridSequential()
            # note that anchors and strides should be used in reverse order
            for i, anchor, stride in zip(range(3), anchors[::-1], strides[::-1]):
                output = YOLO4OutputV3(i, len(classes), anchor, stride, alloc_size=alloc_size)
                self.Outputs.add(output)

    @property
    def num_class(self):
        return self._num_class

    @property
    def classes(self):
        return self._classes

    def hybrid_forward(self, F, x, *args):
        if len(args) != 0 and not autograd.is_training():
            raise TypeError('YOLOV4 inference only need one input data.')

        all_box_centers = []
        all_box_scales = []
        all_objectness = []
        all_class_pred = []
        all_anchors = []
        all_offsets = []
        all_feat_maps = []
        all_detections = []
        routes = []

        feat0, feat1, feat2 = self.backbone(x)
        routes = self.Neck(feat0, feat1, feat2)

        for tip, output in zip(routes, self.Outputs):
            if autograd.is_training():
                dets, box_centers, box_scales, objness, class_pred, anchors, offsets = output(tip)
                all_box_centers.append(box_centers.reshape((0, -3, -1)))
                all_box_scales.append(box_scales.reshape((0, -3, -1)))
                all_objectness.append(objness.reshape((0, -3, -1)))
                all_class_pred.append(class_pred.reshape((0, -3, -1)))
                all_anchors.append(anchors)
                all_offsets.append(offsets)
                fake_featmap = F.zeros_like(tip.slice_axis(axis=0, begin=0, end=1).slice_axis(axis=1, begin=0, end=1))
                all_feat_maps.append(fake_featmap)
            else:
                dets = output(tip)
            all_detections.append(dets)

        if autograd.is_training():
            if autograd.is_recording():
                box_preds = F.concat(*all_detections, dim=1)
                all_preds = [F.concat(*p, dim=1) for p in [
                    all_objectness, all_box_centers, all_box_scales, all_class_pred]]
                all_targets = self._target_generator(box_preds, *args)
                return self._loss(*(all_preds + all_targets))

            return (F.concat(*all_detections, dim=1), all_anchors, all_offsets, all_feat_maps,
                    F.concat(*all_box_centers, dim=1), F.concat(*all_box_scales, dim=1),
                    F.concat(*all_objectness, dim=1), F.concat(*all_class_pred, dim=1))

        result = F.concat(*all_detections, dim=1)
        if self.nms_thresh > 0 and self.nms_thresh < 1:
            result = F.contrib.box_nms(result, overlap_thresh=self.nms_thresh, valid_thresh=0.01, topk=self.nms_topk, id_index=0, score_index=1, coord_start=2, force_suppress=False)
            if self.post_nms > 0:
                result = result.slice_axis(axis=1, begin=0, end=self.post_nms)
        ids = result.slice_axis(axis=-1, begin=0, end=1)
        scores = result.slice_axis(axis=-1, begin=1, end=2)
        bboxes = result.slice_axis(axis=-1, begin=2, end=None)
        return ids, scores, bboxes

    def set_nms(self, nms_thresh=0.45, nms_topk=400, post_nms=100):
        self._clear_cached_op()
        self.nms_thresh = nms_thresh
        self.nms_topk = nms_topk
        self.post_nms = post_nms

    def reset_class(self, classes, reuse_weights=None):
        self._clear_cached_op()
        old_classes = self._classes
        self._classes = classes
        if self._pos_iou_thresh >= 1:
            self._target_generator = YOLOV3TargetMerger(len(classes), self._ignore_iou_thresh)
        if isinstance(reuse_weights, (dict, list)):
            if isinstance(reuse_weights, dict):
                # trying to replace str with indices
                new_keys = []
                new_vals = []
                for k, v in reuse_weights.items():
                    if isinstance(v, str):
                        try:
                            new_vals.append(old_classes.index(v))  # raise ValueError if not found
                        except ValueError:
                            raise ValueError("{} not found in old class names {}".format(v, old_classes))
                    else:
                        if v < 0 or v >= len(old_classes):
                            raise ValueError("Index {} out of bounds for old class names".format(v))
                        new_vals.append(v)
                    if isinstance(k, str):
                        try:
                            new_keys.append(self.classes.index(k))  # raise ValueError if not found
                        except ValueError:
                            raise ValueError("{} not found in new class names {}".format(k, self.classes))
                    else:
                        if k < 0 or k >= len(self.classes):
                            raise ValueError("Index {} out of bounds for new class names".format(k))
                        new_keys.append(k)
                reuse_weights = dict(zip(new_keys, new_vals))
            else:
                new_map = {}
                for x in reuse_weights:
                    try:
                        new_idx = self._classes.index(x)
                        old_idx = old_classes.index(x)
                        new_map[new_idx] = old_idx
                    except ValueError:
                        warnings.warn("{} not found in old: {} or new class names: {}".format(x, old_classes, self._classes))
                reuse_weights = new_map

        for outputs in self.Outputs:
            outputs.reset_class(classes, reuse_weights=reuse_weights)

5.模型训练

1.学习率设置

lr_steps = sorted([int(ls) for ls in lr_decay_epoch.split(',') if ls.strip()])
lr_decay_epoch = [e for e in lr_steps]

 lr_scheduler = LRSequential([
     LRScheduler('linear', base_lr=0, target_lr=learning_rate,
                 nepochs=0, iters_per_epoch=self.num_samples // self.batch_size),
     LRScheduler(lr_mode, base_lr=learning_rate,
                 nepochs=TrainNum,
                 iters_per_epoch=self.num_samples // self.batch_size,
                 step_epoch=lr_decay_epoch,
                 step_factor=lr_decay, power=2),
 ])

2.优化器设置

if optim == 1:
    trainer = gluon.Trainer(self.model.collect_params(), 'sgd', {'learning_rate': learning_rate, 'wd': 0.0005, 'momentum': 0.9, 'lr_scheduler': lr_scheduler})
elif optim == 2:
    trainer = gluon.Trainer(self.model.collect_params(), 'adagrad', {'learning_rate': learning_rate, 'lr_scheduler': lr_scheduler})
else:
    trainer = gluon.Trainer(self.model.collect_params(), 'adam', {'learning_rate': learning_rate, 'lr_scheduler': lr_scheduler})

3.损失设置

obj_metrics = mx.metric.Loss('ObjLoss')
center_metrics = mx.metric.Loss('BoxCenterLoss')
scale_metrics = mx.metric.Loss('BoxScaleLoss')
cls_metrics = mx.metric.Loss('ClassLoss')

4.循环训练

for i, batch in enumerate(self.train_loader):
    data = gluon.utils.split_and_load(batch[0], ctx_list=self.ctx, batch_axis=0)
    # objectness, center_targets, scale_targets, weights, class_targets
    fixed_targets = [gluon.utils.split_and_load(batch[it], ctx_list=self.ctx, batch_axis=0) for it in range(1, 6)]
    gt_boxes = gluon.utils.split_and_load(batch[6], ctx_list=self.ctx, batch_axis=0)
    sum_losses = []
    obj_losses = []
    center_losses = []
    scale_losses = []
    cls_losses = []
    with autograd.record():
        for ix, x in enumerate(data):
            obj_loss, center_loss, scale_loss, cls_loss = self.model(x, gt_boxes[ix], *[ft[ix] for ft in fixed_targets])
            sum_losses.append(obj_loss + center_loss + scale_loss + cls_loss)
            obj_losses.append(obj_loss)
            center_losses.append(center_loss)
            scale_losses.append(scale_loss)
            cls_losses.append(cls_loss)
        if self.ampFlag:
            with amp.scale_loss(sum_losses, trainer) as scaled_loss:
                autograd.backward(scaled_loss)
        else:
            autograd.backward(sum_losses)
    trainer.step(self.batch_size)

    obj_metrics.update(0, obj_losses)
    center_metrics.update(0, center_losses)
    scale_metrics.update(0, scale_losses)
    cls_metrics.update(0, cls_losses)

    name1, loss1 = obj_metrics.get()
    name2, loss2 = center_metrics.get()
    name3, loss3 = scale_metrics.get()
    name4, loss4 = cls_metrics.get()
    print('[Epoch {}][Batch {}], LR: {:.2E}, Speed: {:.3f} samples/sec, {}={:.3f}, {}={:.3f}, {}={:.3f}, {}={:.3f}'.format(epoch, i, trainer.learning_rate, self.batch_size/(time.time()-btic), name1, loss1, name2, loss2, name3, loss3, name4, loss4))
    btic = time.time()

6.模型预测

def predict(self,image,confidence=0.5, mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)):
    start_time = time.time()
    origin_img = copy.deepcopy(image)
    base_imageSize = origin_img.shape
    image = cv2.cvtColor(image,cv2.COLOR_RGB2BGR)
    image = cv2.resize(image,(self.image_size,self.image_size))
    img = nd.array(image)
    img = mx.nd.image.to_tensor(img)
    img = mx.nd.image.normalize(img, mean=mean, std=std)

    x = img.expand_dims(0)
    x = x.as_in_context(self.ctx[0])
    labels, scores, bboxes = [xx[0].asnumpy() for xx in self.model(x)]

    origin_img_pillow = self.cv2_pillow(origin_img)
    font = ImageFont.truetype(font='./model_data/simhei.ttf', size=np.floor(3e-2 * np.shape(origin_img_pillow)[1] + 0.5).astype('int32'))
    thickness = max((np.shape(origin_img_pillow)[0] + np.shape(origin_img_pillow)[1]) // self.image_size, 1)

    imgbox = []
    for i, bbox in enumerate(bboxes):
        if (scores is not None and scores.flat[i] < confidence) or labels is not None and labels.flat[i] < 0:
            continue
        cls_id = int(labels.flat[i]) if labels is not None else -1

        xmin, ymin, xmax, ymax = [int(x) for x in bbox]
        xmin = int(xmin / self.image_size * base_imageSize[1])
        xmax = int(xmax / self.image_size * base_imageSize[1])
        ymin = int(ymin / self.image_size * base_imageSize[0])
        ymax = int(ymax / self.image_size * base_imageSize[0])

        # print(xmin, ymin, xmax, ymax, self.classes_names[cls_id])
        class_name = self.classes_names[cls_id]
        score = '{:d}%'.format(int(scores.flat[i] * 100)) if scores is not None else ''
        imgbox.append([(xmin, ymin, xmax, ymax), cls_id, self.classes_names[cls_id], score])
        top, left, bottom, right = ymin, xmin, ymax, xmax

        label = '{}-{}'.format(class_name, score)
        draw = ImageDraw.Draw(origin_img_pillow)
        label_size = draw.textsize(label, font)
        label = label.encode('utf-8')

        if top - label_size[1] >= 0:
            text_origin = np.array([left, top - label_size[1]])
        else:
            text_origin = np.array([left, top + 1])

        for i in range(thickness):
            draw.rectangle([left + i, top + i, right - i, bottom - i], outline=self.colors[cls_id])
        draw.rectangle([tuple(text_origin), tuple(text_origin + label_size)], fill=self.colors[cls_id])
        draw.text(text_origin, str(label,'UTF-8'), fill=(0, 0, 0), font=font)
        del draw

    result_value = {
        "image_result": self.pillow_cv2(origin_img_pillow),
        "bbox": imgbox,
        "time": (time.time() - start_time) * 1000
    }

    return result_value

四、算法主入口

if __name__ == '__main__':
    # ctu = Ctu_YoloV4(USEGPU='0',image_size=300,ampFlag = False,mixup=False)
    # ctu.InitModel(DataDir=r'D:/Ctu/Ctu_Project_DL/DataSet/DataSet_Detection_YaoPian',batch_size=1,num_workers=0,Pre_Model = None,label_smooth=True)
    # ctu.train(TrainNum=150,learning_rate=0.0001,lr_decay_epoch='50,100,150,200',lr_decay = 0.9,ModelPath='./Model',optim=0,lr_mode='step')

    ctu = Ctu_YoloV4(USEGPU='0')
    ctu.LoadModel(r'./Model_yoloV4')
    cv2.namedWindow("result", 0)
    cv2.resizeWindow("result", 640, 480)
    index = 0
    for root, dirs, files in os.walk(r'D:/Ctu/Ctu_Project_DL/DataSet/DataSet_Detection_YaoPian/DataImage'):
        for f in files:
            img_cv = ctu.read_image(os.path.join(root, f))
            if img_cv is None:
                continue
            res = ctu.predict(img_cv, 0.7)
            for each in res['bbox']:
                print(each)
            print("耗时:" + str(res['time']) + ' ms')
            # cv2.imwrite(str(index + 1)+'.bmp',res['image_result'])
            cv2.imshow("result", res['image_result'])
            cv2.waitKey()
            # index +=1

五、训练效果展示

备注:项目模型的本人没有保存因此会后续提供训练效果
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于MxNet实现目标检测-YoloV4【附部分源码及模型】 的相关文章

  • git merge最简洁用法

    一 开发分支 xff08 dev xff09 上的代码达到上线的标准后 xff0c 要合并到 master 分支 git checkout dev git pull git checkout master git merge dev git
  • 汇编cmp比较指令详解

    刚刚看到了cmp指令 xff0c 一开始有点晕 后来上网找了些资料 xff0c 终于看明白了 xff0c 为了方便初学者 xff0c 我就简单写下我的思路吧 高手绕过 xff0c 谢谢 xff01 cmp compare 指令进行比较两个操
  • vim中复制粘贴

    在vim中要进行复制粘贴 需要使用yy和p指令 但是会发现当我们想讲从vim外面复制的内容粘贴进文本中时 光使用p达不到效果 原因是 在vim中维护者许多的clipboard 而不是只有一个 我们从vim外部 如浏览器 复制的文本所在的cl
  • NP问题真的很难理解

    希望通过这篇文章可以不仅让计算机相关专业的人可以看懂和区分什么是P类问题什么是NP类问题 xff0c 更希望达到的效果是非专业人士比如学文科的朋友也可以有一定程度的理解 有一则程序员界的笑话 xff0c 就是有一哥们去google面试的时候
  • USB转TTL、USB转串口、USB转232的区别

    PO主作为一个没有专业背景的小白 xff0c 在初玩单片机时曾被上面的几个名词所混淆 xff0c 不过后来终于大彻大悟 xff0c 现在把自己的理解写在这里 xff0c 同样准备入门单片机的小白可以看看 xff0c 或许对你有所帮助 首先
  • STM32的时钟系统RCC详细整理

    一 综述 xff1a 1 时钟源 在 STM32 中 xff0c 一共有 5 个时钟源 xff0c 分别是 HSI HSE LSI LSE PLL HSI 是高速内部时钟 xff0c RC 振荡器 xff0c 频率为 8MHz xff1b
  • 第一章 PX4程序编译过程解析

    版权声明 xff1a 本文为博主原创文章 xff0c 未经博主允许不得转载 第一章 PX4程序编译过程解析 PX4是一款软硬件开源的项目 xff0c 目的在于学习和研究 其中也有比较好的编程习惯 xff0c 大家不妨可以学习一下国外牛人的编
  • 第二章 PX4-RCS启动文件解析

    版权声明 xff1a 本文为博主原创文章 xff0c 未经博主允许不得转载 第二章 PX4 RCS启动文件解析 RCS的启动类似于linux的shell文件 xff0c 如果不知道shell文件是什么东西可以理解成是为程序的流程框 xff0
  • pixhawk position_estimator_inav.cpp思路整理及数据流

    写在前面 xff1a 这篇blog主要参考pixhawk的高度解算算法解读 xff0c 并且加以扩展 xff0c 扩展到其他传感器 xff0c 其实里面处理好多只是记录了流程 xff0c 至于里面实际物理意义并不是很清楚 xff0c 也希望
  • git创建新分支

    1 创建本地分支 git branch 分支名 xff0c 例如 xff1a git branch 2 0 1 20120806 注 xff1a 2 0 1 20120806是分支名称 xff0c 可以随便定义 2 切换本地分支 git c
  • 第一章 PX4-Pixhawk-程序编译过程解析

    第一章 PX4程序编译过程解析 PX4是一款软硬件开源的项目 xff0c 目的在于学习和研究 其中也有比较好的编程习惯 xff0c 大家不妨可以学习一下国外牛人的编程习惯 这个项目是苏黎世联邦理工大学的一个实验室搞出来的 该方案是基于NUT
  • 详解几种飞控的姿态解算算法

    姿态解算是飞控的一个基础 重要部分 xff0c 估计出来的姿态会发布给姿态控制器 xff0c 控制飞行平稳 xff0c 是飞行稳定 的最重要保障 有关姿态解算的基础知识 xff0c 这里笔者不会细细描述 xff0c 有关这方面的资料 xff
  • 陀螺仪的数据处理

    1 陀螺仪数据校准 1 1 原理 一款飞控上的传感器是需要进行校准的 xff0c 比如这里讲的陀螺仪 目前大多数的陀螺校准其实就是去掉零点偏移量 xff0c 采集一定的数据 xff0c 求平均 xff0c 这个平均值就是零点偏移 xff0c
  • LevelDB源码分析之从Put说起

    之前分享的文章leveldb实现原理分析详细描述了LevelDB的实现原理 xff0c 本文从Put接口来看下leveldb数据写流程的源码实现 LevelDB的读写接口在类DB中定义 xff08 leveldb db h xff09 xf
  • 大神浅谈无人机飞控软件设计 系统性总结

    写在前面 深感自己对飞控软件 算法的知识点过于杂乱 xff0c 很久没有进行系统的总结了 xff0c 因此决定写几篇文章记录一些飞控开发过程的知识点 主要是针对一些软件 算法部分进行讨论 xff0c 如内容有错误 xff0c 欢迎指出 1
  • 作为资深的无人机从业者,卡尔曼滤波你不能不知道 通俗易懂的来说卡尔曼滤波

    旋翼无人机的两类主要算法 先说一个旋翼类无人机系统的算法主要有两类 xff1a 姿态检测算法 姿态控制算法 姿态控制 被控对象 xff08 即四旋翼无人机 xff09 姿态检测三个部分构成一个闭环控制系统 被控对象的模型是由其物理系统决定
  • pixhawk commander.cpp的飞行模式切换解读

    commander cpp逻辑性太强了 xff0c 涉及整个系统的运作 xff0c 所以分别拆分成小块看 另此篇blog大部分是参考 xff08 Pixhawk原生固件解读 xff09 飞行模式 xff0c 控制模式的思路 xff0c 笔者
  • Pixhawk代码分析-源码框架

    源码框架 pixhawk代码框架 xff1a pixhawk代码框架基础分析 xff1a 阅读下面内容时请结合源码阅读 xff0c 便于理解 The basic structure of ArduPilot is broken up int
  • Pixhawk代码分析-姿态解算篇A

    姿态解算篇A 基本知识 1 如何实现控制 一个无人机系统的算法主要有两类 xff1a 姿态检测算法 姿态控制算法 姿态控制 被控对象 姿态检测三个部分构成一个闭环控制系统 被控对象的模型是由其物理系统决定 xff0c 设计无人机的算法就是设
  • 电路知识--认识原理图(一)

    开源硬件 xff0c 一个很重要的的一点就是有开放的原理图 xff0c 通过原理图 xff0c 我们可以了解一个模块的输入输出 xff0c 以及使用的芯片类型从而知道使用方法等几乎一切信息 原理图上有很多信息 xff0c 到底怎么看呢 xf

随机推荐

  • 初学PX4之飞控算法

    通知 xff1a 如果你对本站无人机文章不熟悉 xff0c 建议查看无人机学习概览 xff01 xff01 xff01 注意 xff1a 基于参考原因 xff0c 本文参杂了APM的算法分析 本篇文章首先简述了下px4和apm调用姿态相关应
  • Pixhawk之姿态控制篇

    一 开篇 姿态控制篇终于来了 来了 来了 心情爽不爽 xff1f 愉悦不愉悦 xff1f 开心不开心 xff1f 喜欢的话就请我吃顿饭吧 xff0c 哈哈 其实这篇blog一周前就应该写的 xff0c 可惜被上一篇blog霸占了 但是也不算
  • PX4原生固件SPI驱动动编写与IMU传感器替换

    适用于PX4原生固件 核心目标 xff1a 完成XSENS的MTI3 xff0c IMU替换 MTI3是一款航姿参考系统 xff0c 可以独立的输出四元数 xff0c 加速度 xff0c 磁力计等 xff0c 角速度等航姿信息 里面有完整的
  • C语言指针详解----指针声明定义赋值

    C语言的指针是让新手很头疼的事情 xff0c 但是由于其太过于灵活 xff0c 以至于可以很好得的解决一些复杂的问题 xff0c 因此不得不掌握 我最近正在学习指针相关的内容 xff0c 因此在这里做一个小的总结 本篇是不涉及到函数以及结构
  • 【slam-2020-01-02】扩展应用

    一篇比较全面的slam博客 一 VR 43 AR 1 VR和AR的关系 AR MR是平台 xff0c 覆盖面比VR更广 xff0c VR是一种媒体形式 xff0c 任何用得到媒体的场景 xff0c 如娱乐 教育等 xff0c 都会有VR的影
  • nvidia-smi卡顿详解

    如果显卡数量在4张以上 xff0c 在nvidia smi信息后会非常的慢 xff0c 非常的卡 尤其在只在乎计算量服务器的时候 我试过把8张卡 tesla K80 显卡一个个拆下来 8张 7张 6 5 4 3 2 1 试试nvidia s
  • c语言将十进制数转换为16进制的函数

    有3种方式实现 xff0c 其中两种是使用系统函数 xff0c 另一种是直接自己编写 使用系统函数实现要加入 include lt stdlib h gt xff0c 自己编写则不需要这个头文件 下面的代码就是3种方式的实现 xff0c 包
  • go-gl搭建开发环境(一)

    1 简介 Go语言 xff08 Golang xff09 是Google在2009年推出的一种编程语言 Golang是一门开源的语言 xff0c 可以从github上找到它的源码 Golang也是一门跨平台的语言 xff0c 可以运行在Wi
  • 串口UART透传WiFi模块常见的几种参数配置方法含web网页配置

    串口透传WiFi参数配置方法 目前 xff0c 在嵌入式领域 xff0c 智能家居 智能工业 智能公交等等控制中 xff0c WiFi 已经成为了一种普遍被采用的技术 笔者常年在嵌入式 WiFi 行业做一线技术开发 本文我们将介绍串口 wi
  • DockerHub基于Github自动化构建

    Docker Hub上的自动化构建 关于自动化构建 自动化构建是一个特殊的功能 xff0c 它允许您在 Docker Hub 上使用构建集群 xff0c 根据指定的 Dockerfile 或者 GitHub BitBucket 仓库 xff
  • 机器人三维视觉引导系统

    基于结构光测量技术和3D物体识别技术开发的机器人3D视觉引导系统 xff0c 可对较大测量深度范围内散乱堆放的零件进行全自由的定位和拾取 相比传统的2D视觉定位方式只能对固定深度零件进行识别且只能获取零件的部分自由度的位置信息 xff0c
  • rviz 官网

    rviz使用教程 官网 http wiki ros org rviz UserGuide Install or build rviz
  • Robocup2D入门笔记(4)——常见模型

    Robocup2D中有几个常见的模型 xff0c 例如听觉 视觉 移动 踢球等 xff0c 这篇博客主要介绍这几个常见的模型 xff0c 这些模型也都可以在官方发布的说明书中找到 xff08 懒得找可以点这里 xff09 一 球场模型 Ro
  • 2020电赛小记

    64 2020电赛总结 xff08 吐槽 xff09 2020电赛小记 本篇全为吐槽 xff0c 不是经验贴 坐标青岛某双非 说不上最恶心不过够恶心 20年参加电赛 xff0c 和一个大三的师哥组队 xff0c 在组期间任劳任怨 xff0c
  • 如何通过nodejs快速搭建一个服务器

    在前端开发过程中 xff0c 可能某些时候需要自己搭建一台服务器用于一些文件图片请求或者进行后端相关知识的学习 本文主要讲解如何通过nodejs进行一个基础服务器的搭建 xff0c 包括如何将文件布置的服务器 xff0c 以及基础接口的开发
  • import 一些已有的模块,会出现红色下划线

    导入tensorflow 以及使用print xff0c 都会出现红色下划线 xff0c 然而程序是没有错误的 这种情况其实可以不用管 xff0c 是可以正常运行的 xff1b 但是 xff0c 如果看着不舒服 xff0c 可以进行以下过程
  • UCOSIII(1)——SVC与PenSV实现任务切换

    本文基于STM32F407ZGT6 SVC异常 xff1a SVC 系统服务调用 xff0c 亦简称系统调用 用于产生系统函数的调用请求 SVC 异常是必须立即得到响应的应用程序执行 SVC 时都是希望所需的请求立即得到响应 在 UCOS
  • Windows编程之核心书籍推荐

    一 Windows程序设计 xff08 第5版 珍藏版 xff09 Windows程序设计 xff08 第5版 珍藏版 xff09 这是一本经典的Windows编程圣经 xff0c 曾经伴随着近50万Windows程序员步入编程殿堂 xff
  • 使用dockerfile创建镜像报错

    do 34 docker build requires exactly 1 argument See docker build help Usage docker build OPTIONS PATH URL Build an image
  • 基于MxNet实现目标检测-YoloV4【附部分源码及模型】

    文章目录 前言目标检测发展史及意义一 数据集的准备1 标注工具的安装2 数据集的准备3 标注数据4 解释xml文件的内容 二 网络结构的介绍三 代码实现0 工程目录结构如下1 导入库2 配置GPU CPU环境3 数据加载器4 模型构建5 模