[MED]features

FV(Fisher Vector)

1.http://blog.youkuaiyun.com/ikerpeng/article/details/41644197
本质是对高斯分布的变量求偏导,也就是对权重,均值,标准差求偏导.
我们将一张图近似为一个高斯分布,由这个高斯分布来表示这张图像。假设我们是做目标的检测,那么当你得到一个有相同的高斯分布的图的时候你就可以判断出这就是那个目标了。但实际的情况是却不一定是这样的,我们看一张图:
这里写图片描述
这两张图上特征点的分布在黑色的区域,二者的分布却可以一样(当然我画的不是很好)!
由此,我们知道,在高斯分布的基础上我们再找到变化的方向,我们便可以更加准确的表示这一张图!
2.http://blog.youkuaiyun.com/carrierlxksuper/article/details/28151013
Fisher vector本质上是用似然函数的梯度vector来表达一幅图像,这个梯度向量的物理意义就是describes the direction in which parameters should be modified to best fit the data,说白了就是数据拟合中对参数调优的过程。似然函数是哪里来的呢?这里就涉及到上面所说的生成方法了。对于一幅图像 ,有T个描述子(比如SIFT),那么这幅图像就可以表示为:

X={xt,t=1,2,...,T}

如果假设这些特征xt符合一定的分布并且这些分布彼此独立,也就是i.i.d(独立同分布)。于是就有:
p(X|λ)=t=1Tp(xt|λ)λ={wi,μi,i,i=1,2,...,N}

取对数之后变成
L(X|λ)=logp(x|λ)=t=1Tlogp(xt|λ)(1)

现在需要一组N个高斯分布的线性组合来逼近这些i.i.d.,假设这些高斯混合分布参数也是 λ ,于是
p(xt|λ)=iNwipi(xt|λ)(2)

公式(2)中的 pi(xt|λ) 就是高斯分布,
pi(x|λ)=exp{12(xμi)1i(xμi)}(2π)D/2|i|1/2(3)

有了公式(1),(2),(3)之后,就可以对公式(1)求导,然后将偏导数,也就是梯度作为fisher vector了。
L(X|λ)wi

L(X|λ)μdi

L(X|λ)σdi

HOG(Histogram of Oriented Gradients)

focuses on static appearance information
1.图像灰度化
2.划分成小cell(2x2)
3.计算每个 cell中每个pixel的gradient(即orientation)
4.统计每个cell中的梯度直方图(不同梯度的个数)即可形成每个cell的descriptor
5.将每n个cell组成一个block(如3x3cell/block),一个block中所有cell的特征descriptor串联起来便可以得到这个block的HOG特征descriptor.
6.将所有block的descriptor串联起来便可以得到整张图的…

HOG(Histogram of Optical Flow)

capture the local motion information

MBH(Motion Boundry Histogram)

[derivatives of optical flows]
在存在背景运动时,MBH能捕捉到相对运动,
The MBH descriptor separates the optical flow field Iw=(Ix,Iy) into its x and y component. Spatial derivatives are computed for each of them and orientation information is quantized into histograms, similarly to the HOG descriptor.
Since MBH represents the gradient of the optical flow, constant motion information is suppressed and only information about changes in the flow field (i.e., motion boundaries) is kept.
It is a simple way to eliminate noise due to background motion.

Dense Trajectory

[Action Recognition by Dense Trajectories, cvpr2011]
这里写图片描述
densely sample feature points in each frame
track points in the video based on optical flow.
compute multiple descriptors along the trajectories(the length of a trajectory is L frames) of feature points to capture shape, appearance and motion information.

IDT(Improved Dense Trajectory)

  • Explicit camera motion estimation
    · Assumption: two consecutive frames are related by a homography.
    · Match feature points between frames using SURF descriptors and dense optical flow
  • Removing inconsistent matches due to humans: use a human detector to remove matches from human regions (computation expensive)

bag of features

http://yongyuan.name/blog/bag-of-word-model.html
1.feature extraction
N张图片,每张图提n个features(或者说第 i 张图有n个patch,每个patch去提特征)。最后,这 N 张图片一共有 M个features
2.codebook
这些features经过了kmeans聚类后,得到了k个聚类中心(在BOW模型中聚类中心我们称它们为视觉词),码本的长度也就为k
3.生成每张图的histogram(according to codebook)
计算每一幅图像的每一个feature到这k个中心的距离,并将其映射到距离最近的视觉词中(即将该视觉词的对应词频+1)。完成这一步后,每一幅图像就变成了一个与视觉词序列相对应的词频矢量。
4.train
5.新的图先经过3后,再用4的分类器进行分类

TIP

have significent local variations in both spatial and temporal domain

Spatial Pyramid Matching

SPM出现的背景是bag of visual words模型被大量地用在了Image representation中,但是BOW模型完全缺失了特征点的spatial信息。
文章的贡献,看完以后觉得其实挺简单的,和分块直方图其实是一个道理——将图像分成若干块(sub-regions),分别统计每一子块的特征,最后将所有块的特征拼接起来,形成完整的特征。这就是SPM中的Spatial。在分块的细节上,作者采用了一种多尺度的分块方法,即分块的粒度越大越细(increasingly fine),呈现出一种层次金字塔的结构,这就是SPM中的Pyramid。(http://www.cnblogs.com/yymn/p/4589327.html)

X 和Y 是d维特征空间上的两个集合。(图像的特征空间 d=2 )
More specifically, let us construct a sequence of grids at resolutions 0,...,L , such that the grid at level l has 2l cells along each dimension, for a total of D=2dl cells.
Let HlX and HlY denote the histograms of X and Y at this resolution, so that HlX(i) and HlY(i) are the numbers of points from X and Y that fall into the ith cell of the grid. Then the number of matches at level l is

Γ(HlX,HlX)=i=1Dmin(HlX(i),HlY(i))

Note that the number of matches found at level l also includes all the matches found at the finer level l+1. Putting all the pieces together, we get the following definition of a pyramid match kernel: KL(X,Y)=....
这里写图片描述
Specifically, we quantize all feature vectors into M discrete types(图中有M=3,菱形,圆点,十字架), and make the simplifying assumption that only features of the same type can be matched to one another.
Each channel m gives us two sets of two-dimensional vectors, Xm and Ym , representing the coordinates of features of type m found in the respective images. The final kernel is then the sum of the separate channel kernels:
KL(X,Y)=m=1MKL(Xm,Ym)

This approach has the advantage of maintaining continuity with the popular “visual vocabulary” paradigm — in fact, it reduces to a standard bag of features when L=0 .
we can implement KL as a single histogram intersection of “long” vectors formed by concatenating the appropriately weighted histograms of all channels at all resolutions.
For L levels and M channels, the resulting vector has dimensionality: MLl=02dl=MLl=04l

//to be continued
■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■ 首先说明: 1、绿色无毒,亲测可用,放心使用,分享万岁 2、找了好久,终于可用 3、secureCRT_6.7.4.354 可以自己到官网下载 也可以用我下载的(无毒) 4、注册机无毒(之前我找的注册机,被查杀了。 但这个没的哦。大家可以去在杀毒。 提供一个在线杀毒网址(里面有很多杀毒软件) http://r.virscan.org/report/5f784624d930eb5b75cbcc7112876edc.html (这个是我杀毒留下的日志,可以查看一下,是不是没有毒哦) http://www.virscan.org/(自己上传注册机,杀毒就可以了) --------------------------------------- 文件名称 : secureCRT_6.7.4.354.exe (本站不提供任何文件的下载服务) 文件大小 : 16296112 byte 文件类型 : PE32 executable for MS Windows (GUI) Intel 80386 32-bit MD5 : dba0a9f69dd227e147beec161d29785a SHA1 : 5e67b0759c598d382fba9430324f140150ef53af --------------------------------------- ■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■ 测试版本:SecureCRT 6.7.4 软件首页:SecureCRT (non-integrated) 下载地址:http://www.vandyke.com/download/securecrt/download.html 帐号密码:zhanqi0404@163.com/zhanqi0404 注册机:SecureCRT.v.6.X-kg ■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■ 注册步骤: 1:安装 SecureCRT 2:复制 SecureCRT.6.X.Keygen.exe 到 SecureCRT 安装目录 3:启动注册机,输入注册信息,随便输入用户和公司,点击 Patch 4:点击 Generate,生成序列号跟 Licence 5:启动 SecureCRT,按照步骤输入注册信息 6:完成注册 7、”features:(leave blank if license has no features“这个地方不用填写,否则完成不了 ■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■ 备注说明: 我安装时候,缺水一个mfc100u.dll文件,搜索后再站长网(admin5.com)下载的 其它网站不放心哦。 没发现其它问题。 2013.8.14 ■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■
嗯,这个代码中 ,当前特征值的画图好像没有 显示出来,请问是被覆盖了么,请给出完整修改代码 classdef SVMSpeechRecognitionGUI < matlab.apps.AppBase % 属性 properties (Access = public) UIFigure matlab.ui.Figure RecordButton matlab.ui.control.Button PlayButton matlab.ui.control.Button RecognizeButton matlab.ui.control.Button ResultLabel matlab.ui.control.Label AudioAxes matlab.ui.control.UIAxes FeatureAxes matlab.ui.control.UIAxes Model % SVM模型 FeatureMean % 特征均值 FeatureStd % 特征标准差 AudioData % 录制的音频数据 SampleRate = 16000; % 采样率 IsRecording = false; % 录音状态 Recorder % 录音对象 Categories = {'0','1','2','3','4','5','6','极7','8','9','+','-','×','÷','='}; % 类别标签 FeatureLegend matlab.ui.control.Label % 特征图例标签 ClassFeatures % 各类别平均特征(用于可视化) end % 公共构造函数 methods (Access = public) function app = SVMSpeechRecognitionGUI(model) % 加载模型和标准化参数 try modelData = load('svm_model.mat'); app.Model = modelData.model; app.FeatureMean = modelData.featureMean; app.FeatureStd = modelData.featureStd; % 尝试加载类别平均特征(用于可视化) if isfield(modelData, 'classFeatures') app.ClassFeatures = modelData.classFeatures; else app.ClassFeatures = []; end catch ME % 如果加载失败,使用传入的模型 if exist('model', 'var') && ~isempty(model) app.Model = model; % 尝试从文件加载标准化参数 if exist('svm_model.mat', 'file') modelData = load('svm_model.mat'); app.FeatureMean = modelData.featureMean; app.FeatureStd = modelData.featureStd; if isfield(modelData, 'classFeatures') app.ClassFeatures = modelData.classFeatures; end else % 默认标准化参数 app.FeatureMean = zeros(1, 40); app.FeatureStd = ones(1, 40); app.ClassFeatures = []; warning('标准化参数未找到,使用默认值'); end else uialert([], sprintf('加载模型失败: %s', ME.message), '错误'); delete(app); return; end end % 创建UI createComponents(app); % 注册关闭事件 app.UIFigure.CloseRequestFcn = @(~,~)closeRequest(app); % 初始化图形 initializePlots(app); % 显示UI app.UIFigure.Visible = 'on'; end end % 私有方法 methods (Access = private) % 窗口关闭请求函数 function closeRequest(app) % 停止录音并释放资源 if app.IsRecording && ~isempty(app.Recorder) && isrecording(app.Recorder) stop(app.Recorder); end % 删除UI delete(app.UIFigure); end % 初始化图形 function initializePlots(app) % 初始化音频波形图 plot(app.AudioAxes, 0, 0); title(app.AudioAxes, '等待录音...'); xlabel(app.AudioAxes, '时间(s)'); ylabel(app.AudioAxes, '幅度'); grid(app.AudioAxes, 'on'); % 初始化特征图 bar(app.FeatureAxes, zeros(1, 40)); title(app.FeatureAxes, '特征向量'); xlabel(app.FeatureAxes, '特征索引'); ylabel(app.FeatureAxes, '特征值'); grid(app.FeatureAxes, 'on'); % 设置特征图属性 app.FeatureAxes.XLabel.FontSize = 12; app.FeatureAxes.YLabel.FontSize = 12; app.FeatureAxes.FontSize = 10; app.FeatureAxes.XLim = [0, 41]; % 创建特征图例 featureTypes = {'均值', '标准差', '能量', '熵', '过零率', '最大值', '最小值', '峰度', '偏度', '中值'}; legendText = sprintf('特征类型:\n'); for i = 1:length(featureTypes) legendText = sprintf('%s%d. %s\n', legendText, i, featureTypes{i}); end app.FeatureLegend = uilabel(app.UIFigure, ... 'Position', [700, 50, 150, 120], ... 'Text', legendText, ... 'FontSize', 9, ... 'BackgroundColor', [0.95, 0.95, 0.95], ... 'Visible', 'off'); % 初始不可见 end % 创建UI组件 function createComponents(app) % 创建主窗口(增加高度以容纳更多内容) app.UIFigure = uifigure('Name', 'SVM语音识别系统', ... 'Position', [100 100 900 600]); % 创建录音按钮 app.RecordButton = uibutton(app.UIFigure, 'push', ... 'Text', '开始录音', ... 'Position', [50 550 100 30], ... 'ButtonPushedFcn', @(src,event)recordButtonPushed(app)); % 创建播放按钮 app.PlayButton = uibutton(app.UIFigure, 'push', ... 'Text', '播放录音', ... 'Position', [170 550 100 30], ... 'ButtonPushedFcn', @(src,event)playButtonPushed(app)); % 创建识别按钮 app.RecognizeButton = uibutton(app.UIFigure, 'push', ... 'Text', '识别语音', ... 'Position', [290 550 100 30], ... 'ButtonPushedFcn', @(src,event)recognizeButtonPushed(app)); % 创建结果显示标签 app.ResultLabel = uilabel(app.UIFigure, ... 'Position', [410 550 300 30], ... 'Text', '结果: ', ... 'FontSize', 16, ... 'FontWeight', 'bold'); % 创建音频波形图 app.AudioAxes = uiaxes(app.UIFigure, 'Position', [50 350 800 180]); title(app.AudioAxes, '音频波形'); xlabel(app.AudioAxes, '时间(s)'); ylabel(app.AudioAxes, '幅度'); grid(app.AudioAxes, 'on'); % 创建特征向量图(增加高度) app.FeatureAxes = uiaxes(app.UIFigure, 'Position', [50 100 800 220]); title(app.FeatureAxes, '特征向量'); xlabel(app.FeatureAxes, '特征索引'); ylabel(app.FeatureAxes, '特征值'); grid(app.FeatureAxes, 'on'); % 设置特征图属性 app.FeatureAxes.XLabel.FontSize = 12; app.FeatureAxes.YLabel.FontSize = 12; app.FeatureAxes.FontSize = 10; app.FeatureAxes.XLim = [0, 41]; end % 录音按钮回调(参考CNN方法改进) function recordButtonPushed(app) if ~app.IsRecording % 开始录音 app.RecordButton.Text = '停止录音'; app.IsRecording = true; app.AudioData = []; % 清空旧数据 % 创建录音对象 app.Recorder = audiorecorder(app.SampleRate, 16, 1); record(app.Recorder); % 更新状态 app.ResultLabel.Text = '录音中...'; app.ResultLabel.FontColor = [0 0 0]; % 黑色 % 隐藏特征图例 app.FeatureLegend.Visible = 'off'; % 实时更新波形(使用循环) while app.IsRecording && isrecording(app.Recorder) pause(0.1); % 更新间隔100ms try audioData = getaudiodata(app.Recorder); if ~isempty(audioData) t = (0:length(audioData)-1)/app.SampleRate; plot(app.AudioAxes, t, audioData); title(app.AudioAxes, sprintf('录音中 (时长: %.2fs)', t(end))); drawnow; end catch % 忽略绘图错误 end end % 录音结束后处理 app.RecordButton.Text = '开始录音'; app.IsRecording = false; % 确保Recorder有效 if ~isempty(app.Recorder) && isvalid(app.Recorder) stop(app.Recorder); % 获取音频数据 app.AudioData = getaudiodata(app.Recorder); else app.AudioData = []; end % 端点检测 if ~isempty(app.AudioData) app.AudioData = app.detectSpeechEndpoints(app.AudioData, app.SampleRate); % 显示最终波形 if ~isempty(app.AudioData) t = (0:length(app.AudioData)-1)/app.SampleRate; plot(app.AudioAxes, t, app.AudioData); title(app.AudioAxes, sprintf('录音波形 (时长: %.2fs)', t(end))); % 更新状态 app.ResultLabel.Text = '录音完成!'; app.ResultLabel.FontColor = [0 0.5 0]; % 绿色 else app.ResultLabel.Text = '录音失败或无声!'; app.ResultLabel.FontColor = [1 0 0]; % 红色 end else app.ResultLabel.Text = '录音失败!'; app.ResultLabel.FontColor = [1 0 0]; % 红色 end else % 停止录音 app.IsRecording = false; end end % 端点检测函数(基于CNN方法改进) function audioOut = detectSpeechEndpoints(~, audioIn, fs) % 简单端点检测算法 frameSize = round(0.025 * fs); % 25ms帧 frameStep = round(0.01 * fs); % 10ms步长 % 确保音频长度大于帧长 if length(audioIn) < frameSize audioOut = audioIn; % 返回原始音频 return; end % 计算短时能量 numFrames = floor((length(audioIn)-frameSize)/frameStep)+1; energy = zeros(1, numFrames); for i = 1:numFrames startIdx = (i-1)*frameStep+1; endIdx = startIdx + frameSize - 1; frame = audioIn(startIdx:endIdx); energy(i) = sum(frame.^2); end % 归一化能量 if max(energy) > 0 energy = energy / max(energy); else % 如果能量全为0,则返回原始音频 audioOut = audioIn; return; end % 设置阈值 threshold = 0.05; % 能量阈值 % 检测语音起点 startIdx = find(energy > threshold, 1, 'first'); % 检测语音终点 endIdx = find(energy > threshold, 1, 'last'); if isempty(startIdx) || isempty(endIdx) audioOut = []; % 无声 else % 扩展边界确保包含完整语音 startSample = max(1, (startIdx-5)*frameStep); % 提前5帧 endSample = min(length(audioIn), (endIdx+5)*frameStep+frameSize); % 延后5帧 % 提取有效语音段 audioOut = audioIn(startSample:endSample); end end % 播放按钮回调(参考CNN方法改进) function playButtonPushed(app) if ~isempty(app.AudioData) sound(app.AudioData, app.SampleRate); app.ResultLabel.Text = '播放中...'; app.ResultLabel.FontColor = [0 0.5 0]; % 绿色 % 计算播放时间 duration = length(app.AudioData)/app.SampleRate; startTime = tic; while toc(startTime) < duration % 实时更新进度 elapsed = toc(startTime); progress = min(elapsed/duration, 1); % 更新波形显示 t = (0:length(app.AudioData)-1)/app.SampleRate; plot(app.AudioAxes, t, app.AudioData); hold(app.AudioAxes, 'on'); plot(app.AudioAxes, [elapsed, elapsed], ylim(app.AudioAxes), 'r-', 'LineWidth', 2); hold(app.AudioAxes, 'off'); title(app.AudioAxes, sprintf('播放中 (进度: %.1f%%)', progress*100)); drawnow; end app.ResultLabel.Text = '播放完成!'; plot(app.AudioAxes, (0:length(app.AudioData)-1)/app.SampleRate, app.AudioData); title(app.AudioAxes, sprintf('录音波形 (时长: %.2fs)', duration)); else app.ResultLabel.Text = '无录音数据!'; app.ResultLabel.FontColor = [1 0 0]; % 红色 end end % 识别按钮回调(增强特征可视化) function recognizeButtonPushed(app) if isempty(app.AudioData) app.ResultLabel.Text = '请先录音!'; app.ResultLabel.FontColor = [1 0 0]; % 红色 return; end try % 特征提取 features = extractDWTFeatures(app, app.AudioData); % 显示特征向量 - 改进可视化 cla(app.FeatureAxes); % 清除之前的图形 % 标准化特征用于预测 normalizedFeatures = (features - app.FeatureMean) ./ app.FeatureStd; % 预测 predicted = predict(app.Model, normalizedFeatures); % 显示结果 resultText = ['识别结果: ', char(app.Categories{predicted})]; app.ResultLabel.Text = resultText; app.ResultLabel.FontColor = [0 0 1]; % 蓝色 % 绘制当前特征(蓝色) bar(app.FeatureAxes, features, 'FaceColor', [0.2 0.4 0.8], 'BarWidth', 0.6); hold(app.FeatureAxes, 'on'); % 如果可用,绘制该类别的平均特征(红色) if ~isempty(app.ClassFeatures) % 获取该类别对应的平均特征(注意:模型中的特征已经标准化,但这里我们显示原始量级) classMean = app.ClassFeatures(predicted, :) .* app.FeatureStd + app.FeatureMean; plot(app.FeatureAxes, 1:40, classMean, 'r-o', 'LineWidth', 2, 'MarkerSize', 5); % 添加图例 legend(app.FeatureAxes, {'当前特征', '类别平均特征'}, 'Location', 'best'); else legend(app.FeatureAxes, {'当前特征'}, 'Location', 'best'); end hold(app.FeatureAxes, 'off'); % 设置坐标轴属性 title(app.FeatureAxes, sprintf('%s的特征向量', resultText)); xlabel(app.FeatureAxes, '特征索引'); ylabel(app.FeatureAxes, '特征值'); grid(app.FeatureAxes, 'on'); % 添加特征组标签(D1, D2, D3, D4) yLim = ylim(app.FeatureAxes); labelY = yLim(1) - 0.05 * diff(yLim); for k = 1:4 text(app.FeatureAxes, (k-1)*10+5, labelY, ... sprintf('D%d', k), ... 'HorizontalAlignment', 'center', ... 'VerticalAlignment', 'top', ... 'FontSize', 11, ... 'FontWeight', 'bold'); end % 在特征图上添加特征类型标记 featureTypes = {'Mean','Std','Energy','Entropy','ZCR','Max','Min','Kurt','Skew','Med'}; for group = 0:3 for ftype = 1:10 idx = group*10 + ftype; text(app.FeatureAxes, idx, labelY + 0.01*diff(yLim), ... featureTypes{ftype}, ... 'HorizontalAlignment', 'center', ... 'VerticalAlignment', 'bottom', ... 'FontSize', 8, ... 'Rotation', 90); end end % 显示特征图例 app.FeatureLegend.Visible = 'on'; catch ME app.ResultLabel.Text = '识别失败!'; app.ResultLabel.FontColor = [1 0 0]; % 红色 uialert(app.UIFigure, sprintf('错误: %s', ME.message), '识别错误'); end end % DWT特征提取函数(增强版,防止NaN) function features = extractDWTFeatures(~, audio) % 空音频处理 if isempty(audio) || all(audio == 0) features = nan(1, 40); return; end % 确保音频长度合适 targetLength = 16000; % 1秒@16kHz if length(audio) > targetLength audio = audio(1:targetLength); elseif length(audio) < targetLength audio = [audio; zeros(targetLength-length(audio), 1)]; end % DWT特征提取 wavelet = 'db4'; level = 4; [C, L] = wavedec(audio, level, wavelet); % 提取特征 features = zeros(1, 40); % 40维特征向量 % 各层细节系数的统计特征 for k = 1:level d = detcoef(C, L, k); startIdx = (k-1)*10 + 1; % 安全特征计算 features(startIdx) = mean(d); % 均值 % 标准差(防除0) if numel(d) > 1 features(startIdx+1) = std(d); else features(startIdx+1) = 0; end features(startIdx+2) = sum(d.^2); % 能量 % 熵(防log(0)if all(d == d(1)) || numel(d) < 2 features(startIdx+3) = 0; else [p, ~] = histcounts(d, 10, 'Normalization', 'probability'); p(p == 0) = []; % 移除零概率 features(startIdx+3) = -sum(p.*log2(p+eps)); end % 过零率 features(startIdx+4) = sum(abs(diff(sign(d)))); % 最大值/最小值 features(startIdx+5) = max(d); features(startIdx+6) = min(d); % 峰度(需要≥4个点) if numel(d) > 3 features(startIdx+7) = kurtosis(d); else features(startIdx+7) = 0; end % 偏度(需要≥3个点) if numel(d) > 2 features(startIdx+8) = skewness(d); else features(startIdx+8) = 0; end features(startIdx+9) = median(d); % 中值 end % 最终NaN检查(防止意外情况) if any(isnan(features)) warning('特征包含NaN,使用零填充'); features(isnan(features)) = 0; end end end end
06-23
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值