基于Deepface的情緒識別c++

基于Deepface的情緒識別c++

文章目錄

  • 基于Deepface的情緒識別c++
    • 簡介
    • 下載模型并轉為onnx(facial_expression_model_weights.h5)
    • 測試
      • 取出照片的人臉部分并處理成模型輸入格式
      • 用模型推理一下看看結果
    • 用onnxruntime的c++庫推理

簡介

DeepFace是一個基于深度學習的開源人臉識別與屬性分析框架,其情緒識別模塊通過卷積神經網絡(CNN)架構實現了對7種基礎情緒(生氣、厭惡、恐懼、開心、悲傷、驚訝、中性)的高精度分類。該技術結合了OpenCV的圖像處理能力,支持從人臉檢測、對齊到情緒預測的全流程自動化處理,準確率高達97.53%,超越人類平均水平。其核心模型如VGG-Face、ArcFace等通過大規模數據集(如FER2013、AffectNet)訓練,能夠捕捉面部微表情的細微差異。(以上內容來著deepseek)
deepface情緒識別

下載模型并轉為onnx(facial_expression_model_weights.h5)

這是情緒識別部分的源碼

# stdlib dependencies
from typing import List, Union# 3rd party dependencies
import numpy as np
import cv2# project dependencies
from deepface.commons import package_utils, weight_utils
from deepface.models.Demography import Demography
from deepface.commons.logger import Logger# dependency configuration
tf_version = package_utils.get_tf_major_version()if tf_version == 1:from keras.models import Sequentialfrom keras.layers import Conv2D, MaxPooling2D, AveragePooling2D, Flatten, Dense, Dropout
else:from tensorflow.keras.models import Sequentialfrom tensorflow.keras.layers import (Conv2D,MaxPooling2D,AveragePooling2D,Flatten,Dense,Dropout,)# Labels for the emotions that can be detected by the model.
labels = ["angry", "disgust", "fear", "happy", "sad", "surprise", "neutral"]logger = Logger()# pylint: disable=line-too-long, disable=too-few-public-methodsWEIGHTS_URL = "https://github.com/serengil/deepface_models/releases/download/v1.0/facial_expression_model_weights.h5"class EmotionClient(Demography):"""Emotion model class"""def __init__(self):self.model = load_model()self.model_name = "Emotion"def _preprocess_image(self, img: np.ndarray) -> np.ndarray:"""Preprocess single image for emotion detectionArgs:img: Input image (224, 224, 3)Returns:Preprocessed grayscale image (48, 48)"""img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)img_gray = cv2.resize(img_gray, (48, 48))return img_graydef predict(self, img: Union[np.ndarray, List[np.ndarray]]) -> np.ndarray:"""Predict emotion probabilities for single or multiple facesArgs:img: Single image as np.ndarray (224, 224, 3) orList of images as List[np.ndarray] orBatch of images as np.ndarray (n, 224, 224, 3)Returns:np.ndarray (n, n_emotions)where n_emotions is the number of emotion categories"""# Preprocessing input image or image list.imgs = self._preprocess_batch_or_single_input(img)processed_imgs = np.expand_dims(np.array([self._preprocess_image(img) for img in imgs]), axis=-1)# Predictionpredictions = self._predict_internal(processed_imgs)return predictionsdef load_model(url=WEIGHTS_URL,
) -> Sequential:"""Consruct emotion model, download and load weights"""num_classes = 7model = Sequential()# 1st convolution layermodel.add(Conv2D(64, (5, 5), activation="relu", input_shape=(48, 48, 1)))model.add(MaxPooling2D(pool_size=(5, 5), strides=(2, 2)))# 2nd convolution layermodel.add(Conv2D(64, (3, 3), activation="relu"))model.add(Conv2D(64, (3, 3), activation="relu"))model.add(AveragePooling2D(pool_size=(3, 3), strides=(2, 2)))# 3rd convolution layermodel.add(Conv2D(128, (3, 3), activation="relu"))model.add(Conv2D(128, (3, 3), activation="relu"))model.add(AveragePooling2D(pool_size=(3, 3), strides=(2, 2)))model.add(Flatten())# fully connected neural networksmodel.add(Dense(1024, activation="relu"))model.add(Dropout(0.2))model.add(Dense(1024, activation="relu"))model.add(Dropout(0.2))model.add(Dense(num_classes, activation="softmax"))# ----------------------------weight_file = weight_utils.download_weights_if_necessary(file_name="facial_expression_model_weights.h5", source_url=url)model = weight_utils.load_model_weights(model=model, weight_file=weight_file)return model

下載模型并轉為onnx

import tensorflow as tf
import tf2onnx
import onnx# 1. 加載原始模型
model = load_model()# 2. 定義輸入簽名
input_signature = [tf.TensorSpec(shape=(None, 48, 48, 1), dtype=tf.float32, name='input')]# 3. 轉換為ONNX
onnx_model, _ = tf2onnx.convert.from_keras(model,input_signature=input_signature,opset=13,output_path="deepface_emotion.onnx"
)

測試

取出照片的人臉部分并處理成模型輸入格式

測試圖片:
請添加圖片描述
取出人臉圖片:
在這里插入圖片描述

import cv2
import matplotlib.pyplot as plt#處理成輸入格式
img = cv2.imread("../img/test2_face.jpg")
img = img.astype(np.float32)/255.0
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_gray = cv2.resize(img_gray, (48, 48))
gray_img = np.expand_dims(img_gray, axis=-1)
test_input = np.expand_dims(gray_img, axis=0) 

用模型推理一下看看結果

import onnxruntime as ort
import numpy as np# 加載ONNX模型
ort_session = ort.InferenceSession("deepface_emotion.onnx", providers=['CPUExecutionProvider'])# 運行推理
outputs = ort_session.run(None, {'input': test_input})
print("預測概率:", outputs[0])# 獲取預測結果
predicted_class = np.argmax(outputs[0])
print("預測類別:", predicted_class)labels = ["angry", "disgust", "fear", "happy", "sad", "surprise", "neutral"]
print(f"預測類型:{labels[predicted_class]},概率:{outputs[0][0][predicted_class]:.2f}")

結果:

預測概率: [[2.0709881e-10 1.9225350e-18 4.2878087e-06 9.9998260e-01 1.3058154e-051.4756028e-11 1.7358280e-08]]
預測類別: 3
預測類型:happy,概率:1.00

用onnxruntime的c++庫推理

#pragma once
#include <iostream>
#include <numeric> //數值計算
#include <tuple>   //C++17 元組
#include <opencv2/opencv.hpp>
#include <onnxruntime_cxx_api.h>namespace LIANGBAIKAI_BASE_MODEL_NAME
{#define ORT_OLD_VISON 12 // ort1.12.0 之前的版本為舊版本APIclass Deepface_Emotion_Onnxruntime{public:enum Severity_log{E_INTERNAL_ERROR = 0, // 內部錯誤E_ERROR = 1,          // 一般錯誤E_WARNING = 2,        // 警告E_INFO = 3,           // 信息};Deepface_Emotion_Onnxruntime() : _OrtMemoryInfo(Ort::MemoryInfo::CreateCpu(OrtAllocatorType::OrtDeviceAllocator, OrtMemType::OrtMemTypeCPUOutput)) {};virtual ~Deepface_Emotion_Onnxruntime() {};/*** @description: 設置日志等級* @param {Severity_log} severity* @return {*}*/virtual void setReportableSeverity(Severity_log severity){_reportableSeverity = severity;log(E_INFO, "reportableSeverity set to " + std::to_string(severity));}/*** @description:* @param {string} &modelPath 模型文件* @param {int} netWidth 模型輸入尺寸寬* @param {int} netHeight 模型輸入尺寸高* @param {bool} isCuda 是否使用cuda* @param {int} cudaID cuda的id* @param {bool} warmUp warm up gpu-model* @return {*}  返回是否初始化成功*/bool init(const std::string &modelPath, int netWidth = 48, int netHeight = 48, bool isCuda = true, int cudaID = 0, bool warmUp = true){_netWidth = netWidth;_netHeight = netHeight;bool rec = ReadModel(modelPath, isCuda, cudaID, warmUp);return rec;}/*** @description: 推理* @param {cv::Mat} &img : 輸入人臉圖片* @return {std::tuple<int, float>}  返回情緒,置信度*/std::tuple<int, float> infer(const cv::Mat &img){log(E_INFO, "infer");cv::Mat img_tmp = img.clone();cv::resize(img_tmp, img_tmp, cv::Size(224, 224));cv::Mat normalizedImage;//  cv::normalize(img_tmp, normalizedImage, 0, 1, cv::NORM_MINMAX, CV_32F); // 歸一化 結果與python的源碼結果有一點偏差,用下面的方法img_tmp.convertTo(normalizedImage, CV_32F, 1.0 / 255.0);cv::Mat resizedImage;cv::resize(normalizedImage, resizedImage, cv::Size(_netWidth, _netHeight));cv::Mat grayImage;cv::cvtColor(resizedImage, grayImage, cv::COLOR_BGR2GRAY);cv::Mat blob;cv::dnn::blobFromImage(grayImage, blob, 1.0, cv::Size(0, 0), cv::Scalar(0), false, false);int64_t input_tensor_length = VectorProduct(_inputTensorShape);std::vector<Ort::Value> input_tensors;std::vector<Ort::Value> output_tensors;input_tensors.push_back(Ort::Value::CreateTensor<float>(_OrtMemoryInfo, (float *)blob.data, input_tensor_length, _inputTensorShape.data(), _inputTensorShape.size()));log(E_INFO, "infer run");output_tensors = _OrtSession->Run(Ort::RunOptions{nullptr},_inputNodeNames.data(),input_tensors.data(),_inputNodeNames.size(),_outputNodeNames.data(),_outputNodeNames.size());float *all_data = output_tensors[0].GetTensorMutableData<float>();int max_index = 0;float max_value = 0.0f;for (int i = 0; i < _outputTensorShape[1]; i++){log(E_INFO, "result" + std::to_string(i) + ": " + std::to_string(all_data[i]));if (all_data[i] > max_value){max_value = all_data[i];max_index = i;}}return std::make_tuple(max_index, max_value * 99.99);}private:/*** @description: 讀取onnx模型* @param {string} &modelPath : onnx模型路徑* @param {bool} isCuda: 如果為true,使用Ort-GPU,否則在cpu上運行。* @param {int} cudaID: 如果isCuda==true,在cudaID上運行Ort-GPU。* @param {bool} warmUp: 如果isCuda==true,預熱GPU-model。* @return {*}*/bool ReadModel(const std::string &modelPath, bool isCuda = true, int cudaID = 0, bool warmUp = true){if (_batchSize < 1){_batchSize = 1;}try{// 列出可用的推理提供者 cpu cuda dml tensorrt openvinostd::vector<std::string> available_providers = Ort::GetAvailableProviders();auto cuda_available = std::find(available_providers.begin(), available_providers.end(), "CUDAExecutionProvider");if (isCuda && (cuda_available == available_providers.end())){log(E_ERROR, "Your ORT build without GPU. Change to CPU.");log(E_INFO, "************* Infer model on CPU! *************");}else if (isCuda && (cuda_available != available_providers.end())){log(E_INFO, "************* Infer model on GPU! *************");#if ORT_API_VERSION < ORT_OLD_VISONOrtCUDAProviderOptions cudaOption;cudaOption.device_id = cudaID;_OrtSessionOptions.AppendExecutionProvider_CUDA(cudaOption);
#else// 添加CUDA執行提供者OrtStatus *status = OrtSessionOptionsAppendExecutionProvider_CUDA(_OrtSessionOptions, cudaID);if (status != NULL){log(E_ERROR, "OrtSessionOptionsAppendExecutionProvider_CUDA ERROR");}
#endif}else{log(E_INFO, "************* Infer model on CPU! *************");}// 設置圖優化級別_OrtSessionOptions.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED);#ifdef _WIN32std::wstring model_path(modelPath.begin(), modelPath.end());_OrtSession = std::make_shared<Ort::Session>(_OrtEnv, modelPath.c_str(), _OrtSessionOptions);
#else// 創建會話_OrtSession = std::make_shared<Ort::Session>(_OrtEnv, modelPath.c_str(), _OrtSessionOptions);
#endif// 創建默認的內存分配器Ort::AllocatorWithDefaultOptions allocator;// 初始化輸入_inputNodesNum = _OrtSession->GetInputCount();
#if ORT_API_VERSION < ORT_OLD_VISON_inputName = _OrtSession->GetInputName(0, allocator);_inputNodeNames.push_back(_inputName);
#else// 獲取輸入名稱_inputName = std::move(_OrtSession->GetInputNameAllocated(0, allocator));_inputNodeNames.push_back(_inputName.get());
#endif// 獲取輸入類型信息Ort::TypeInfo inputTypeInfo = _OrtSession->GetInputTypeInfo(0);// 獲取輸入張量類型和形狀信息auto input_tensor_info = inputTypeInfo.GetTensorTypeAndShapeInfo();// 獲取輸入數據類型_inputNodeDataType = input_tensor_info.GetElementType();// 獲取輸入張量形狀_inputTensorShape = input_tensor_info.GetShape();if (_inputTensorShape[0] == -1){_isDynamicShape = true;_inputTensorShape[0] = _batchSize;}if (_inputTensorShape[2] == -1 || _inputTensorShape[3] == -1){_isDynamicShape = true;_inputTensorShape[2] = _netHeight;_inputTensorShape[3] = _netWidth;}// 獲取輸出節點數_outputNodesNum = _OrtSession->GetOutputCount();// 獲取輸出名稱
#if ORT_API_VERSION < ORT_OLD_VISON_output_name0 = _OrtSession->GetOutputName(0, allocator);_outputNodeNames.push_back(_output_name0);
#else_output_name0 = std::move(_OrtSession->GetOutputNameAllocated(0, allocator));_outputNodeNames.push_back(_output_name0.get());
#endifOrt::TypeInfo type_info_output0(nullptr);type_info_output0 = _OrtSession->GetOutputTypeInfo(0); // output0// 獲取輸出張量類型和形狀信息auto tensor_info_output0 = type_info_output0.GetTensorTypeAndShapeInfo();// 獲取輸出數據類型_outputNodeDataType = tensor_info_output0.GetElementType();// 獲取輸出張量形狀_outputTensorShape = tensor_info_output0.GetShape();log(E_INFO, "inputNodesNum:" + std::to_string(_inputNodesNum));log(E_INFO, "inputNodeNames:" + std::string(_inputNodeNames[0]));std::string inputTensorShapeStr = " ";for (unsigned int i = 0; i < _inputTensorShape.size(); i++){inputTensorShapeStr += std::to_string(_inputTensorShape[i]) + " ";}log(E_INFO, "inputTensorShape:" + inputTensorShapeStr);log(E_INFO, "outputNodesNum:" + std::to_string(_outputNodesNum));log(E_INFO, "outputNodeNames:" + std::string(_outputNodeNames[0]));std::string outputTensorShapeStr = " ";for (unsigned int i = 0; i < _outputTensorShape.size(); i++){outputTensorShapeStr += std::to_string(_outputTensorShape[i]) + " ";}log(E_INFO, "outputTensorShape:" + outputTensorShapeStr);log(E_INFO, "outputNodeDataType:" + std::to_string(_outputNodeDataType));// warm upif (isCuda && warmUp){// draw runlog(E_INFO, "Start warming up");// 計算輸入張量長度size_t input_tensor_length = VectorProduct(_inputTensorShape);float *temp = new float[input_tensor_length];// 創建輸入張量std::vector<Ort::Value> input_tensors;// 創建輸出張量std::vector<Ort::Value> output_tensors;input_tensors.push_back(Ort::Value::CreateTensor<float>(_OrtMemoryInfo, temp, input_tensor_length, _inputTensorShape.data(),_inputTensorShape.size()));for (int i = 0; i < 3; ++i){output_tensors = _OrtSession->Run(Ort::RunOptions{nullptr},_inputNodeNames.data(),input_tensors.data(),_inputNodeNames.size(),_outputNodeNames.data(),_outputNodeNames.size());}delete[] temp;}}catch (const std::exception &){log(E_ERROR, "read model error !");return false;}log(E_INFO, "read model success !");return true;}void log(Severity_log severity, const std::string msg) noexcept{// 根據嚴重性級別決定是否打印日志if (severity <= _reportableSeverity){switch (severity){case Severity_log::E_INTERNAL_ERROR:std::cerr << "[INTERNAL ERROR] " << msg << std::endl;break;case Severity_log::E_ERROR:std::cerr << "[ERROR] " << msg << std::endl;break;case Severity_log::E_WARNING:std::cerr << "[WARNING] " << msg << std::endl;break;case Severity_log::E_INFO:std::cout << "[INFO] " << msg << std::endl;break;default:break;}}}// 計算向量中所有元素的乘積template <typename T>T VectorProduct(const std::vector<T> &v){return std::accumulate(v.begin(), v.end(), 1, std::multiplies<T>());};int _netWidth = 48;  // ONNX-net-input-widthint _netHeight = 48; // ONNX-net-input-heightint _batchSize = 1;           // if multi-batch,set thisbool _isDynamicShape = false; // onnx support dynamic shape// ONNXRUNTIMEOrt::Env _OrtEnv = Ort::Env(OrtLoggingLevel::ORT_LOGGING_LEVEL_ERROR, "Resnet");Ort::SessionOptions _OrtSessionOptions = Ort::SessionOptions();std::shared_ptr<Ort::Session> _OrtSession;Ort::MemoryInfo _OrtMemoryInfo;
#if ORT_API_VERSION < ORT_OLD_VISONchar *_inputName, *_output_name0;
#elsestd::shared_ptr<char> _inputName, _output_name0;
#endifstd::vector<char *> _inputNodeNames;  // 輸入節點名std::vector<char *> _outputNodeNames; // 輸出節點名size_t _inputNodesNum = 0;  // 輸入節點數size_t _outputNodesNum = 0; // 輸出節點數ONNXTensorElementDataType _inputNodeDataType; // 數據類型ONNXTensorElementDataType _outputNodeDataType;std::vector<int64_t> _inputTensorShape; // 輸入張量shapestd::vector<int64_t> _outputTensorShape;Severity_log _reportableSeverity = Severity_log::E_ERROR;};
}

完整項目代碼

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/76553.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/76553.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/76553.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java的數據庫編程——JDBC基礎

JDBC編程 一、概述1.1 概念介紹1.2 驅動包下載1.3 導入驅動包 二、通過Java程序操作數據庫2.1 通過 JDBC 進行 插入數據 操作2.1.1 創建“數據源(DataSource)——描述要操作的數據庫、數據是在哪”2.1.2 與服務器建立連接2.1.3 構造sql語句&#xff0c;并且對字符串類型的sql進…

DeepSeek-R1 面試題匯總

Deepseek-r1 面試寶典 原文地址&#xff1a;https://articles.zsxq.com/id_91kirfu15qxw.html DeepSeek-R1 面試題匯總 DeepSeek-R1 面試題匯總 GRPO&#xff08;Group Relative Policy Optimization&#xff09;常見面試題匯總篇 DeepSeek-R1 DeepSeek-R1-Zero 常見面試題匯總…

SSL/TLS

http ssl傳輸層 -> https 安全套接層 SSL/TLS 1、核心角色與文件2、證書生成流程2.1、生成CA根證書2.2、生成服務端證書2.3 生成客戶端證書&#xff08;雙向認證&#xff09; 3、SSL/TLS 認證模式3.1、單向認證&#xff08;默認 HTTPS&#xff09;3.2、雙向認證&#xff0…

HTML 音頻(Audio)學習筆記

一、HTML 音頻概述 在 HTML 中&#xff0c;音頻可以通過多種方式播放&#xff0c;但要確保音頻在不同瀏覽器和設備上都能正常播放&#xff0c;需要掌握一些技巧。HTML5 引入了 <audio> 元素&#xff0c;為音頻播放提供了一種標準方法&#xff0c;但在 HTML4 中&#xff…

php開發rest api,哪個框架最好

在 2025 年&#xff0c;選擇適合開發 REST API 的 PHP 框架需要根據項目需求、性能要求和團隊技術棧進行權衡。以下是一些推薦的 PHP 框架及其適用場景&#xff1a; 1. Laravel 特點&#xff1a;功能豐富&#xff0c;生態系統強大&#xff0c;內置 API 資源&#xff0c;支持 …

前端入門之CSS

CSS: HTML負責定義頁面結構;JS負責處理頁面邏輯和點擊事件;CSS負責用于描述 HTML 元素的顯示方式,通過 CSS 可以控制顏色、字體、布局等。 核心語法: 選擇器: 類選擇器主要用于選中需要添加樣式的 HTML 元素。主要分為:類選擇器(.class-name { ... })、標簽選擇器(…

MCP協議的Streamable HTTP:革新數據傳輸的未來

引言 在數字化時代&#xff0c;數據傳輸的效率和穩定性是推動技術進步的關鍵。MCP&#xff08;Model Context Protocol&#xff09;作為AI生態系統中的重要一環&#xff0c;通過引入Streamable HTTP傳輸機制&#xff0c;為數據交互帶來了革命性的變化。本文將深入解讀MCP協議的…

MySQL - 索引原理與優化:深入解析B+Tree與高效查詢策略

文章目錄 引言一、BTree索引核心原理1.1 索引數據結構演化1.2 BTree的存儲結構通過主鍵查詢&#xff08;主鍵索引&#xff09;商品數據的過程通過非主鍵&#xff08;輔助索引&#xff09;查詢商品數據的過程 MySQL InnoDB 的索引原理 二、執行計劃深度解析三、索引失效的六大陷…

《K230 從熟悉到...》識別機器碼(AprilTag)

《K230 從熟悉到...》識別機器碼&#xff08;aprirltag&#xff09; tag id 《廬山派 K230 從熟悉到...》 識別機器碼&#xff08;AprilTag&#xff09; AprilTag是一種基于二維碼的視覺標記系統&#xff0c;最早是由麻省理工學院&#xff08;MIT&#xff09;在2008年開發的。A…

Linux驅動復習

應用層調用內核層函數稱為系統調用 1.硬件設備管理 1&#xff0c;字符設備驅動&#xff08;一個一個字節&#xff09;——芯片內部外設 &#xff1a;WDT,Timer&#xff0c;adc,iic&#xff0c;SPI,R,UART,LCD,CAMERA,USB,Keyboard&#xff0c;Mouse 2&#xff0c;塊設備驅動&a…

【FAQ】HarmonyOS SDK 閉源開放能力 —Account Kit(3)

1.問題描述&#xff1a; PC場景&#xff0c;青少年模式系統API不支持嗎&#xff1f; 解決方案&#xff1a; PC場景&#xff0c;青少年模式系統API不支持&#xff0c;另外文檔上的幾個API也不支持。 2.問題描述&#xff1a; 華為一鍵登錄 Beta7本地運行到手機可以拿到匿名手…

【gdutthesis模板】論文標題太長導致換頁問題解決

標題太長導致換頁問題解決方案如下&#xff1a; 調小下方數值即可

SAP學習筆記 - 豆知識18 - (TODO)Msg 番號 ME154 構成品目無法決定

1&#xff0c;現象 構成品目の決定は不可能です Msg 番號 ME154 構成品目無法決定 2&#xff0c;到Deepseek里找一下解決方案 SAP ME21N中錯誤「組件物料的確定不可行&#xff08;ME154&#xff09;」的解決步驟 此錯誤在創建分包采購訂單時出現&#xff0c;通常由于系統無…

10.多線程

預備知識 預備知識一 預備知識二 預備知識三 如何理解進程和線程的關系&#xff0c;舉一個生活中的例子 家庭&#xff1a;進程家庭成員&#xff1a;線程 每個家庭成員都會為這個家庭做貢獻&#xff0c;只不過大家都在做不同的事情&#xff08;比如&#xff1a;我們在上學&…

Python入門(8):文件

1. 文件基本概念 文件&#xff1a;存儲在計算機上的數據集合&#xff0c;Python 通過文件對象來操作文件。 文件類型&#xff1a; 文本文件&#xff1a;由字符組成&#xff0c;如 .txt, .py 二進制文件&#xff1a;由字節組成&#xff0c;如 .jpg, .mp3 2. 文件打開與關閉…

市場交易策略優化與波動管理

市場交易策略優化與波動管理 在市場交易中&#xff0c;策略的優化和波動的管理至關重要。市場價格的變化受多種因素影響&#xff0c;交易者需要根據市場環境動態調整策略&#xff0c;以提高交易的穩定性&#xff0c;并有效規避市場風險。 一、市場交易策略的優化方法 趨勢交易策…

HTTP數據傳輸的幾個關鍵字Header

本文著重針對http在傳輸數據時的幾種封裝方式進行描述。 1. Content-Type(描述body內容類型以及字符編碼) HTTP的Content-Type用于定義數據傳輸的媒體類型&#xff08;MIME類型&#xff09;&#xff0c;主要分為以下幾類&#xff1a; (一)、?基礎文本類型? text/plain? …

面向教育領域的實時更新RAG系統:核心模塊設計與技術選型實踐指南

目錄 面向教育領域的實時更新RAG系統&#xff1a;核心模塊設計與技術選型實踐指南 一、業務需求分析 二、系統架構設計&#xff08;核心模塊&#xff09; 三、核心模塊詳解與技術選型建議 &#xff08;一&#xff09;實時更新向量知識庫 &#xff08;二&#xff09;教材與…

k8s patch方法更新deployment和replace方法更新deployment的區別是什么

在Kubernetes中&#xff0c;patch 和 replace 方法用于更新資源&#xff08;如 Deployment&#xff09;&#xff0c;但它們的實現方式和適用場景有顯著差異。以下是兩者的核心區別&#xff1a; 1. 更新范圍 replace 方法 完全替換整個資源配置。需要用戶提供完整的資源定義&…

解決安卓手機WebView無法直接預覽PDF的問題(使用PDF.js方案)

在移動端開發中&#xff0c;通過 webview 組件直接加載PDF文件時&#xff0c;不同平臺的表現差異較大&#xff1a; iOS & 部分安卓瀏覽器&#xff1a;可正常內嵌預覽&#xff08;依賴系統內置PDF渲染能力&#xff09; 大多數安卓設備&#xff1a;由于缺乏原生PDF插件&…