基于Yolov8面部七种表情检测与识别C++模型部署

news2025/1/24 5:41:41

表情识别

七种表情识别是一个多学科交叉的研究领域,它结合了心理学、认知科学、计算机视觉和机器学习等学科的知识和技术。

基本概念

  • 表情的定义:表情是人们在情绪体验时面部肌肉活动的结果,是人类情感交流的基本方式之一。
  • 基本表情理论:心理学家Paul Ekman提出,人类有七种基本情绪,每种情绪都有其特定的面部表情模式。

七种基本表情

  1. 快乐:通常与积极情绪相关,特征是嘴角上扬,眼睛周围肌肉收缩。
  2. 悲伤:与失落或痛苦相关,特征是眉毛下垂,嘴角下拉。
  3. 愤怒:与愤怒或挫败相关,特征是眉毛下压,嘴唇紧闭。
  4. 惊讶:与意外或震惊相关,特征是眼睛和嘴巴张开。
  5. 恐惧:与害怕或焦虑相关,特征是眼睛瞪大,眉毛提升。
  6. 厌恶:与反感或不喜欢相关,特征是上唇提升,嘴角下拉。
  7. 轻蔑:与鄙视或不屑一顾相关,特征是嘴角一侧上扬。

应用领域

  • 心理健康监测:通过表情识别来评估个体的情绪状态。
  • 人机交互:使机器人或计算机系统能够理解和响应用户的情绪。
  • 安全监控:在安全检查中识别可疑行为或情绪异常。
  • 娱乐和媒体:在电影、游戏和虚拟现实中生成逼真的虚拟角色表情。

挑战和限制

  • 个体差异:不同人表达相同情绪的方式可能不同。
  • 文化差异:不同文化背景下,表情的表达和解读可能存在差异。
  • 环境因素:光照、遮挡和面部表情的微妙变化可能影响识别的准确性。
  • 实时性要求:在某些应用场景下,如视频监控或实时交互,对系统的处理速度有较高要求。

发展趋势

  • 多模态识别:结合面部表情以外的信息,如语音、心率等,以提高识别的准确性。
  • 迁移学习:利用预训练的深度学习模型来提高小样本学习的性能。
  • 无监督和半监督学习:减少对大量标注数据的依赖,提高模型的泛化能力。

数据集

数据集内容:RAF-DB数据集是一个大规模面部表情数据库,由315名工作人员(大学的学生和教职员工)对表情进行标注。

在对表情的选择上,从一系列表情(例如:微笑,咯咯笑声,哭泣,愤怒,害怕,害怕,恐惧,震惊,惊讶,厌恶,无表情)中,挑选出六种基本情感以及中立情感,一共7种表情进行表情标注。

数据集数量:RAF-DB数据集,包含大约3万张面部图像。除了表情标注外,对每个人脸还有5个特征点标注,人脸边界框,种族,年龄范围和性别等属性的标注。

数据集功能:表情识别、人脸检测、年龄估计

下载链接:http://www.whdeng.cn/RAF/model1.html

在这里插入图片描述

Yolov8目标检测

YOLOv8是YOLO系列的最新迭代产品,它在目标检测领域带来了一系列创新和改进。以下是YOLOv8的一些关键特点和功能:

  1. 模型结构:YOLOv8采用了新的SOTA模型,包括不同分辨率的目标检测网络和基于YOLACT的实例分割模型。它在骨干网络和Neck部分可能参考了YOLOv7 ELAN的设计思想,将YOLOv5的C3结构换成了C2f结构,并对不同尺度模型调整了不同的通道数。

  2. Head部分:与YOLOv5相比,YOLOv8的Head部分改动较大,换成了目前主流的解耦头结构,将分类和检测头分离,并且从Anchor-Based换成了Anchor-Free。

  3. Loss计算:YOLOv8采用了TaskAlignedAssigner正样本分配策略,并引入了Distribution Focal Loss,这有助于提高检测过程的准确性和效率。

  4. 数据增强:在训练过程中,YOLOv8引入了YOLOX中的最后10个epoch关闭Mosaic增强的操作,这可以有效地提升精度。

  5. 训练策略:YOLOv8的模型训练总epoch数从300提升到了500,这导致训练时间增加,但可能有助于进一步提升模型性能。

  6. 性能和速度:YOLOv8专注于保持精度与速度之间的最佳平衡,适用于各种应用领域的实时目标检测任务。

  7. 预训练模型:YOLOv8提供一系列预训练模型,以满足各种任务和性能要求,从而更容易为您的特定用例找到合适的模型。

  8. 支持的任务和模式:YOLOv8系列提供多种模型,每种模型都专门用于计算机视觉中的特定任务,如物体检测、实例分割、姿态/关键点检测等。

  9. 性能基准测试:YOLOv8可以进行性能基准测试,以评估在不同导出格式下的速度和准确性。

  10. 实战应用:有教程提供了YOLOv8在LabVIEW中的部署,包括模型的导出、图片和视频推理的实现。

环境安装

安装环境:

conda create -n yolov8 python=3.8
activate ylolv8
pip install ultralytics

转onnx

安装完成之后,分割数据进行模型训练。训练完之后把模型转成onnx,使用以下命令将YOLO模型从PyTorch导出为ONNX格式,并设置opset为12:

yolo export model=yolov8s.pt format=onnx dynamic=False opset=12

命令的含义解释如下:

yolo export: 使用YOLO导出功能、
model=yolov8s.pt: 指定PyTorch模型的路径
format=onnx: 导出为ONNX格式
dynamic=False: 关闭动态输入
opset=12: 设置ONNX模型的opset版本为12

转ncnn模型

得到onnx模型之后要转成ncnn的模型,可以使用onnx2ncnn.exe进行模型转换,也可以使用在线的模型转换工具。

模型C++推理部署

ncnn库

从官方下载以编译好的ncnn库,我这里使用的IDE是vs2022,下载对应自己的库。导入lib和include,如果想要指用GPU进行推理,则要编译vulkan库。

C++ 推理代码

#include "FacialEmotion.h"


static float fast_exp(float x)
{
    union {
        uint32_t i;
        float f;
    } v{};
    v.i = (1 << 23) * (1.4426950409 * x + 126.93490512f);
    return v.f;
}

static inline float sigmoid(float x)
{
    return 1.0f / (1.0f + fast_exp(-x));
}
static float intersection_area(const Object& a, const Object& b)
{
    cv::Rect_<float> inter = a.rect & b.rect;
    return inter.area();
}

static void qsort_descent_inplace(std::vector<Object>& faceobjects, int left, int right)
{
    int i = left;
    int j = right;
    float p = faceobjects[(left + right) / 2].prob;

    while (i <= j)
    {
        while (faceobjects[i].prob > p)
            i++;

        while (faceobjects[j].prob < p)
            j--;

        if (i <= j)
        {
            // swap
            std::swap(faceobjects[i], faceobjects[j]);

            i++;
            j--;
        }
    }

    //     #pragma omp parallel sections
    {
        //         #pragma omp section
        {
            if (left < j) qsort_descent_inplace(faceobjects, left, j);
        }
        //         #pragma omp section
        {
            if (i < right) qsort_descent_inplace(faceobjects, i, right);
        }
    }
}

static void qsort_descent_inplace(std::vector<Object>& faceobjects)
{
    if (faceobjects.empty())
        return;

    qsort_descent_inplace(faceobjects, 0, faceobjects.size() - 1);
}

static void nms_sorted_bboxes(const std::vector<Object>& faceobjects, std::vector<int>& picked, float nms_threshold)
{
    picked.clear();

    const int n = faceobjects.size();

    std::vector<float> areas(n);
    for (int i = 0; i < n; i++)
    {
        areas[i] = faceobjects[i].rect.width * faceobjects[i].rect.height;
    }

    for (int i = 0; i < n; i++)
    {
        const Object& a = faceobjects[i];

        int keep = 1;
        for (int j = 0; j < (int)picked.size(); j++)
        {
            const Object& b = faceobjects[picked[j]];

            // intersection over union
            float inter_area = intersection_area(a, b);
            float union_area = areas[i] + areas[picked[j]] - inter_area;
            // float IoU = inter_area / union_area
            if (inter_area / union_area > nms_threshold)
                keep = 0;
        }

        if (keep)
            picked.push_back(i);
    }
}
static void generate_grids_and_stride(const int target_w, const int target_h, 
    std::vector<int>& strides, std::vector<GridAndStride>& grid_strides)
{
    for (int i = 0; i < (int)strides.size(); i++)
    {
        int stride = strides[i];
        int num_grid_w = target_w / stride;
        int num_grid_h = target_h / stride;
        for (int g1 = 0; g1 < num_grid_h; g1++)
        {
            for (int g0 = 0; g0 < num_grid_w; g0++)
            {
                GridAndStride gs;
                gs.grid0 = g0;
                gs.grid1 = g1;
                gs.stride = stride;
                grid_strides.push_back(gs);
            }
        }
    }
}

static void generate_proposals(std::vector<GridAndStride> grid_strides, 
    const ncnn::Mat& pred, float prob_threshold, std::vector<Object>& objects)
{
    const int num_points = grid_strides.size();
    const int num_class = 7;
    const int reg_max_1 = 16;

    for (int i = 0; i < num_points; i++) //out.h
    {
        const float* scores = pred.row(i) + 4 * reg_max_1;

        // find label with max score
        int label = -1;
        float score = -FLT_MAX;
        for (int k = 0; k < num_class; k++)
        {
            float confidence = scores[k];
            if (confidence > score)
            {
                label = k;
                score = confidence;
            }
        }
        float box_prob = sigmoid(score);
        if (box_prob >= prob_threshold)
        {
            ncnn::Mat bbox_pred(reg_max_1, 4, (void*)pred.row(i));
            {
                ncnn::Layer* softmax = ncnn::create_layer(ncnn::layer_to_index("Softmax"));
//                ncnn::layer_to_index("Softmax")
                ncnn::ParamDict pd;
                pd.set(0, 1); // axis
//                pd.set(1, 1);
                softmax->load_param(pd);

                ncnn::Option opt;
                opt.num_threads = 1;
                opt.use_packing_layout = false;

                softmax->create_pipeline(opt);

                softmax->forward_inplace(bbox_pred, opt);

                softmax->destroy_pipeline(opt);

                delete softmax;
            }

            float pred_ltrb[4];
            for (int k = 0; k < 4; k++)
            {
                float dis = 0.f;
                const float* dis_after_sm = bbox_pred.row(k);
                for (int l = 0; l < reg_max_1; l++)
                {
                    dis += l * dis_after_sm[l];
                }

                pred_ltrb[k] = dis * grid_strides[i].stride;
            }

            float pb_cx = (grid_strides[i].grid0 + 0.5f) * grid_strides[i].stride; 
            float pb_cy = (grid_strides[i].grid1 + 0.5f) * grid_strides[i].stride;

            float x0 = pb_cx - pred_ltrb[0];
            float y0 = pb_cy - pred_ltrb[1];
            float x1 = pb_cx + pred_ltrb[2];
            float y1 = pb_cy + pred_ltrb[3];

            Object obj;
            obj.rect.x = x0;
            obj.rect.y = y0;
            obj.rect.width = x1 - x0;
            obj.rect.height = y1 - y0;
            obj.label = label;
            obj.prob = box_prob;

            objects.push_back(obj);
        }
    }
}

//调用ncnn转置操作
static void transpose(const ncnn::Mat& in, ncnn::Mat& out)
{
    ncnn::Option opt;
    opt.num_threads = 1;
    opt.use_fp16_storage = false;
    opt.use_packing_layout = true;

    ncnn::Layer* op = ncnn::create_layer("Permute");

    // set param
    ncnn::ParamDict pd;
    pd.set(0, 1);// order_type=1

    op->load_param(pd);
    op->create_pipeline(opt);

    op->forward(in,out, opt);
    op->destroy_pipeline(opt);

    delete op;
}



FacialEmotion::FacialEmotion()
{
    blob_pool_allocator.set_size_compare_ratio(0.f);
    workspace_pool_allocator.set_size_compare_ratio(0.f);
}


int FacialEmotion::load(std::string parma_path,std::string bin_path,int _target_size,bool use_gpu)
{
    yolo.clear();
    blob_pool_allocator.clear();
    workspace_pool_allocator.clear();

    ncnn::set_cpu_powersave(2);
    ncnn::set_omp_num_threads(ncnn::get_big_cpu_count());

    yolo.opt = ncnn::Option();

#if NCNN_VULKAN
    yolo.opt.use_vulkan_compute = use_gpu;
#endif

    yolo.opt.num_threads = 2;
    yolo.opt.blob_allocator = &blob_pool_allocator;
    yolo.opt.workspace_allocator = &workspace_pool_allocator;

    yolo.load_param(parma_path.c_str());
    yolo.load_model(bin_path.c_str());

    target_size = _target_size;

    return 0;
}

int FacialEmotion::detect(const cv::Mat& rgb, std::vector<Object>& objects, float prob_threshold, float nms_threshold)
{
    int width = rgb.cols;
    int height = rgb.rows;

    // pad to multiple of 32
    int w = width;
    int h = height;
    float scale = 1.f;
    if (w > h)
    {
        scale = (float)target_size / w;
        w = target_size;
        h = h * scale;
    }
    else
    {
        scale = (float)target_size / h;
        h = target_size;
        w = w * scale;
    }

    ncnn::Mat in = ncnn::Mat::from_pixels_resize(rgb.data, ncnn::Mat::PIXEL_BGR, width, height, w, h);

    // pad to target_size rectangle
    int wpad = (w + 31) / 32 * 32 - w;
    int hpad = (h + 31) / 32 * 32 - h;
    ncnn::Mat in_pad;
    ncnn::copy_make_border(in, in_pad, hpad / 2, hpad - hpad / 2, wpad / 2, wpad - wpad / 2, ncnn::BORDER_CONSTANT, 0.f);

    in_pad.substract_mean_normalize(0, norm_vals);

    ncnn::Extractor ex = yolo.create_extractor();

    ex.input("images", in_pad);

    std::vector<Object> proposals;
    
    ncnn::Mat out;
    ex.extract("/model.22/Concat_3_output_0", out);

    ncnn::Mat out1;
    transpose(out, out1);


    std::vector<int> strides = {8, 16, 32}; // might have stride=64
    std::vector<GridAndStride> grid_strides;
    generate_grids_and_stride(in_pad.w, in_pad.h, strides, grid_strides);
    generate_proposals(grid_strides, out1, prob_threshold, proposals);

    qsort_descent_inplace(proposals);

    // apply nms with nms_threshold
    std::vector<int> picked;
    nms_sorted_bboxes(proposals, picked, nms_threshold);

    int count = picked.size();

    objects.resize(count);
    for (int i = 0; i < count; i++)
    {
        objects[i] = proposals[picked[i]];

        // adjust offset to original unpadded
        float x0 = (objects[i].rect.x - (wpad / 2)) / scale;
        float y0 = (objects[i].rect.y - (hpad / 2)) / scale;
        float x1 = (objects[i].rect.x + objects[i].rect.width - (wpad / 2)) / scale;
        float y1 = (objects[i].rect.y + objects[i].rect.height - (hpad / 2)) / scale;

        // clip
        x0 = std::max(std::min(x0, (float)(width - 1)), 0.f);
        y0 = std::max(std::min(y0, (float)(height - 1)), 0.f);
        x1 = std::max(std::min(x1, (float)(width - 1)), 0.f);
        y1 = std::max(std::min(y1, (float)(height - 1)), 0.f);

        objects[i].rect.x = x0;
        objects[i].rect.y = y0;
        objects[i].rect.width = x1 - x0;
        objects[i].rect.height = y1 - y0;
    }

    // sort objects by area
    struct
    {
        bool operator()(const Object& a, const Object& b) const
        {
            return a.rect.area() > b.rect.area();
        }
    } objects_area_greater;


    std::sort(objects.begin(), objects.end(), objects_area_greater);

    return 0;
}

int FacialEmotion::draw(cv::Mat& rgb, const std::vector<Object>& objects)
{
    static const char *class_names[] = 
    {
           "surprise", "fear","disgust","happiness","sadness","anger","neutral"
    };


    static const unsigned char colors[19][3] = {
        { 54,  67, 244},
        { 99,  30, 233},
        {176,  39, 156},
        {183,  58, 103},
        {181,  81,  63},
        {243, 150,  33},
        {244, 169,   3},
        {212, 188,   0},
        {136, 150,   0},
        { 80, 175,  76},
        { 74, 195, 139},
        { 57, 220, 205},
        { 59, 235, 255},
        {  7, 193, 255},
        {  0, 152, 255},
        { 34,  87, 255},
        { 72,  85, 121},
        {158, 158, 158},
        {139, 125,  96}
    };

    int color_index = 0;

    for (size_t i = 0; i < objects.size(); i++)
    {
        const Object& obj = objects[i];
        const unsigned char* color = colors[color_index % 19];
        color_index++;

        cv::Scalar cc(color[0], color[1], color[2]);

        cv::rectangle(rgb, obj.rect, cc, 2);

        char text[256];
        sprintf(text, "%s %.1f%%", class_names[obj.label], obj.prob * 100);

        int baseLine = 0;
        cv::Size label_size = cv::getTextSize(text, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);

        int x = obj.rect.x;
        int y = obj.rect.y - label_size.height - baseLine;
        if (y < 0)
            y = 0;
        if (x + label_size.width > rgb.cols)
            x = rgb.cols - label_size.width;

        cv::rectangle(rgb, cv::Rect(cv::Point(x, y), cv::Size(label_size.width, label_size.height + baseLine)), cc, -1);

        cv::Scalar textcc = (color[0] + color[1] + color[2] >= 381) ? cv::Scalar(0, 0, 0) : cv::Scalar(255, 255, 255);

        cv::putText(rgb, text, cv::Point(x, y + label_size.height), cv::FONT_HERSHEY_SIMPLEX, 0.5, textcc, 1);
    }

    return 0;
}

实现的效果如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
源码地址:https://download.csdn.net/download/matt45m/89612957

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

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

相关文章

matplotlib显示opencv读取的图片颜色异常,BGR转RGB的两种方式:cv2.cvtColor与img[:,:,::-1]

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

github添加ssh密钥,通过ssh方式推送代码

左手编程&#xff0c;右手年华。大家好&#xff0c;我是一点&#xff0c;关注我&#xff0c;带你走入编程的世界。 公众号&#xff1a;一点sir&#xff0c;关注领取python编程资料 很多人在使用github的时候&#xff0c;如果还是使用https的方式推送代码的话&#xff0c;可能会…

《LeetCode热题100》---<5.①普通数组篇五道>

本篇博客讲解LeetCode热题100道普通数组篇中的五道题 第一道&#xff1a;最大子数组和&#xff08;中等&#xff09; 第二道&#xff1a;合并区间&#xff08;中等&#xff09; 第一道&#xff1a;最大子数组和&#xff08;中等&#xff09; 法一&#xff1a;贪心算法 class So…

「文件加密软件精选」13个惊艳无比的软件推荐请查收!

信息安全是企业生存与发展的基石。 一次不慎的数据泄露&#xff0c;就可能给企业带来难以估量的损失。因此&#xff0c;文件加密成为了保护企业核心资产的重要手段。 某日&#xff0c;两位员工小李和小张在茶水间闲聊&#xff1a; “你知道吗&#xff1f;最近公司开始推广文…

飞浆OCR模型训练详细教程

目录 飞浆使用文档一 环境查看1.1 Python 环境1.2 版本选择1.3 飞浆测试 二 数据集的标准备2.1 PPOCRLabelv22.1.1 安装 PaddlePaddle2.1.2 安装与运行 PPOCRLabel2.1.3 数据集划分 三 PaddleOCR 的环境搭建3.1 环境搭建3.2 模型下载 四 模型训练4.1 检测模型训练4.2 识别模型训…

萱仔环境记录——git的安装流程

最近由于我有一个大模型的offer&#xff0c;由于我只在实验室的电脑上装了git&#xff0c;我准备在自己的笔记本上本地安装一个git&#xff0c;也给我的一个师弟讲解一下git安装和使用的过程&#xff0c;给我的环境安装章节添砖加瓦。 github是基于git的一个仓库托管平台。 g…

用Python实现亚马逊Amazon高性能爬虫采集销量信息

用Python实现亚马逊Amazon高性能爬虫采集销量信息 引言 亚马逊作为全球最大的电商平台&#xff0c;拥有丰富的商品种类和庞大的用户基数。因此&#xff0c;采集亚马逊的销量信息对于市场分析、竞争对手研究以及运营优化有着重要的作用。本文将详细介绍如何用Python实现高性能的…

机械学习—零基础学习日志(高数20——洛必达法则)

零基础为了学人工智能&#xff0c;真的开始复习高数 这里讲解一个历史&#xff0c;洛必达法则其实并不是洛必达想出来的&#xff0c;洛必达整理了第一本微积分的书籍&#xff0c;是真正的知识传播者。洛必达法则是洛必达从伯努利哪里买过来的&#xff0c;并结合了莱布尼兹的论…

本地部署 Llama-3-EvoVLM-JP-v2

本地部署 Llama-3-EvoVLM-JP-v2 0. 引言1. 关于 Llama-3-EvoVLM-JP-v22. 本地部署2-0. 克隆代码2-1. 安装依赖模块2-2. 创建 Web UI2-3.启动 Web UI2-4. 访问 Web UI 0. 引言 Sakana AI 提出了一种称为进化模型合并的方法&#xff0c;并使用该方法创建大规模语言模型&#xff…

数论——线性同余方程、扩欧求解线性同余方程、线性组合、原根求解

线性同余方程 线性同余方程是形如 的方程&#xff0c;其中a 、b、m 为给定的整数&#xff0c;x 是未知整数。 扩欧求解线性同余方程 void mod_slover(int a, int b, int n) {int d, x, y, x0;d extend_gcd(a, n, x, y);if (b % d ! 0)cout << "no answer";…

联邦学习研究综述【联邦学习】

文章目录 0 前言机器学习两大挑战&#xff1a; 1 什么是联邦学习&#xff1f;联邦学习的一次迭代过程如下&#xff1a;联邦学习技术具有以下几个特点&#xff1a; 2 联邦学习的算法原理目标函数本地目标函数联邦学习的迭代过程 3 联邦学习分类横向联邦学习纵向联邦学习联邦迁移…

科普文:微服务之Spring Cloud OpenFeign服务调用调用过程分析

概叙 Feign和OpenFeign的关系 其实到现在&#xff0c;至少是2018年之后&#xff0c;我们说Feign&#xff0c;或者说OpenFeign其实是一个东西&#xff0c;就是OpenFeign&#xff0c;是2018.12 Netflix停止维护后&#xff0c;Spring cloud整合Netflix生态系统的延续。后面其实都…

ComfyUI-BrushNet(局部重绘)节点安装及效果、模型下载及详细使用方法✨

&#x1f35c;背景介绍 ComfyUI 中BrushNet的节点已经发布了三个月左右的时间了&#xff0c;后来陆续更新了更多的功能和模型接入&#xff0c;整体效果看起来还是不错的。这个节点随着能力的更新&#xff0c;接入了更多的模型&#xff0c;而每个模型默认的名字又比较相似&…

RoboDK的插件

目录 collision-free-planner&#xff1a; opc-ua&#xff1a; collision-free-planner&#xff1a; RoboDK 的无碰撞规划器插件使用概率路线图 (PRM) 自动在机器人工作空间内创建无碰撞路径。 有关无碰撞规划器的更多信息&#xff0c;请访问我们的 文档。 生成参数无碰撞…

揭秘:查询大数据信用报告的三大作用

相信很多朋友都听说过大数据信用是什么&#xff0c;其实早在几年前&#xff0c;不少的网贷平台都是用人行征信加上大数据信用作为平台风控审核的依据&#xff0c;直到大数据技术的发展&#xff0c;现在不少的银行等机构都将大数据信用作为银行放贷风控审核的重要指标&#xff0…

趋势跟踪策略 文华财经指标公式源码 九稳量化系统 多空趋势指标神器 期货起爆点买入指标源码

斯坦利•克罗 1、赢利时是长线&#xff0c;亏损时就是短线。 2、50%回调位金字塔加码&#xff0c;“坐”着赚钱&#xff0c;甚至不惜用鸵鸟政策&#xff0c;眼不见心不烦。 3、阻碍长线操作成功的最主要原因是觉得单调乏味和失去纪律。 4、把自己的止损点设在远离绝大多数投…

detr论文解读

参考&#xff1a;https://www.bilibili.com/video/BV1md4y1s7nW/?spm_id_from333.788&vd_source156234c72054035c149dcb072202e6be 补充&#xff1a;decoder更关注边缘特征 补充&#xff1a; spatial pos.enc.&#xff1a;空间位置编码。包含encoder和decoder的空间位置…

Flutter 2024: Impeller引擎引领渲染新纪元

本文首发于公众号“AntDream”&#xff0c;欢迎微信搜索“AntDream”或扫描文章底部二维码关注&#xff0c;和我一起每天进步一点点 Flutter 2024: Impeller引擎引领渲染新纪元 在移动应用开发领域&#xff0c;Flutter凭借其跨平台能力、丰富的组件库和高性能的渲染引擎&#…

OpenStack概述

一、初识OpenStack OpenStack Docs: 概况 一&#xff09;OpenStack架构简述 1、理解OpenStack OpenStack既是一个社区&#xff0c;也是一个项目和一个开源软件&#xff0c;提供开放源码软件&#xff0c;建立公共和私有云&#xff0c;它提供了一个部署云的操作平台或工具集&…

Linux 内核源码分析---通用文件模型及 VFS 结构

通用文件模型 通常一个完整的 Linux 系统由数千到数百万个文件组成&#xff0c;文件中存储了程序、数据和各种信息。层次化的目录结构用于对文件进行编排和分组。 ReiserFS&#xff08;新型的文件系统&#xff09;–>Reiser4 它通过一种与众不同的方式—完全平衡树结构来容…