《Adaptive Local Tone Mapping Based on Retinex for High Dynamic Range Images》C++实现

局部色调映射(Local Tone Mapping) 重建视觉外观是色调映射的终极目标。色调映射算法在降低高动态图像(HDR)范围的同时着力保护捕捉到的原始图像的外观。色调映射算子分两种策略,一种是全局的,另一种是局部的。 1. 全局映射算子 每一个像素点将会根据它的全图特征和亮度信息进行映射,不管其空间位置几何。全局算子一个比较典型的例子就是色调曲线。全局色调映射在处理12位(12-bit)深度的图像的时候是完全OK的,当图像的动态范围特别高的时候,那就不行了。这是因为所有的像素点都采取同一种方式进行处理,根本就没有管它是在较亮区域还是较暗区域。这样的话,. 阅读详情

前言

最近在做低照度图像恢复时,发现了一个充满知识的github工程:点这里,里面有一篇论文,《Adaptive Local Tone Mapping Based on Retinex for High Dynamic Range Images》,它结合传统的Retinex技术提出了全局自适应和局部自适应的HDR实现过程,这里是参考了作者的matlab代码写出了暴力版本的代码实现,在720p的图像上处理速度为68ms/张。论文的讲解不是很好翻译,大家可以去查看原始论文,我也没怎么读啦。。。论文地址在这里:http://koasas.kaist.ac.kr/bitstream/10203/172985/1/73275.pdf ,我只是实现了论文中的一小部分,就是全局自适应,发现对于低照度的彩色图像恢复效果很好。

原理

在这里插入图片描述

首先引入了这个公式,这些符号代表些啥呢? L g ( x , y ) L_g(x,y) Lg​(x,y)是全自适应输出的结果,我们这里就是需要得到它, L w ( x , y ) L_w(x,y) Lw​(x,y)代表输入图像的luminance值(亮度值), L w m a x L_{wmax} Lwmax​表示输入图像亮度值对的最大值, L w {L_w} Lw​横线 表示输入亮度对数的平均值。
然后:
在这里插入图片描述

其中N表示像素的总数,而δ一般是个很小的值,其作用主要是为了避免对纯黑色像素进行log计算时数值溢出,这个问题在图像处理时非常常见。直接应用原文的话,(这段描述来自:https://www.cnblogs.com/Imageshop/p/9460334.html)上述算式的主要作用是:The input world luminance values and the maximum luminance values are divided by the log-average luminance of he scene. This enables (4) to adapt to each scene. As the log-verage luminance converges to the high value, the function converges from the shape of the logarithm function to the near function. Thus, scenes of the low log-average luminance reboosted more than scenes with high values. As a result, the overall scene luminance values are adequately compressed in ccordance with the log-average luminance of the scene.特别注意的是 scenes of the low log-average luminance reboosted more than scenes with high values. 这句话,他的意思是说低照度的亮度部分比高照度的部分要能得到更大程度的提升,所以对于低照度图,上述公式能起到很好的增强作用。而算式中使用了全局的对数平均值,这就有了一定的自适应性。

代码实现

我暂时只实现了c++暴力版本,代码如下:

#include "function.h"

void simple_color_balance(float ** input_img, float ** out_img, int rows, int cols) {
	float max_value = 0;
	float min_value = 256;
	for (int i = 0; i < rows; i++) {
		for (int j = 0; j < cols; j++) {
			max_value = max(max_value,input_img[i][j]);
			min_value = min(min_value, input_img[i][j]);
		}
	}
	if (max_value <= min_value) {
		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < cols; j++) {
				out_img[i][j] = max_value;
			}
		}
	}
	else {
		float scale = 255.0 / (max_value - min_value);
		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < cols; j++) {
				if (input_img[i][j] < min_value) {
					out_img[i][j] = 0;
				}
				else if (input_img[i][j] > max_value) {
					out_img[i][j] = 255;
				}
				else {
					out_img[i][j] = scale * (input_img[i][j] - min_value);
				}
			}
		}
	}
}

int HDR(cv::Mat input_img, cv::Mat out_img) {
	int rows = input_img.rows;
	int cols = input_img.cols;
	//DouImg
	float ***DouImg;
	DouImg = new float **[rows];
	for (int i = 0; i < rows; i++) {
		DouImg[i] = new float *[cols];
		for (int j = 0; j < cols; j++) {
			DouImg[i][j] = new float[3];
		}
	}
	for (int i = 0; i < rows; i++) {
		for (int j = 0; j < cols; j++) {
			DouImg[i][j][0] = (float)input_img.at<Vec3b>(i, j)[0];
			DouImg[i][j][1] = (float)input_img.at<Vec3b>(i, j)[1];
			DouImg[i][j][2] = (float)input_img.at<Vec3b>(i, j)[2];
		}
	}
	//Lw
	float **Lw;
	Lw = new float *[rows];
	for (int i = 0; i < rows; i++) {
		Lw[i] = new float [cols];
	}
	for (int i = 0; i < rows; i++) {
		for (int j = 0; j < cols; j++) {
			Lw[i][j] = 0;
		}
	}
	//B
	float **B;
	B = new float *[rows];
	for (int i = 0; i < rows; i++) {
		B[i] = new float[cols];
	}
	for (int i = 0; i < rows; i++) {
		for (int j = 0; j < cols; j++) {
			B[i][j] = (float)input_img.at<Vec3b>(i, j)[0];
		}
	}
	//G
	float **G;
	G = new float *[rows];
	for (int i = 0; i < rows; i++) {
		G[i] = new float[cols];
	}
	for (int i = 0; i < rows; i++) {
		for (int j = 0; j < cols; j++) {
			G[i][j] = (float)input_img.at<Vec3b>(i, j)[1];
		}
	}
	//R
	float **R;
	R = new float *[rows];
	for (int i = 0; i < rows; i++) {
		R[i] = new float[cols];
	}
	for (int i = 0; i < rows; i++) {
		for (int j = 0; j < cols; j++) {
			R[i][j] = (float)input_img.at<Vec3b>(i, j)[2];
		}
	}
	//Lwmax
	float Lwmax = 0.0;
	//Lw
	for (int i = 0; i < rows; i++) {
		for (int j = 0; j < cols; j++) {
			Lw[i][j] = 0.299 * R[i][j] + 0.587 * G[i][j] + 0.114 * B[i][j];
			if (Lw[i][j] == 0) {
				Lw[i][j] = 1;
			}
			Lwmax = max(Lw[i][j], Lwmax);
		}
	}
	//Lw_sum
	float Lw_sum = 0;
	//log_Lw
	float **log_Lw;
	log_Lw = new float *[rows];
	for (int i = 0; i < rows; i++) {
		log_Lw[i] = new float[cols];
	}
	for (int i = 0; i < rows; i++) {
		for (int j = 0; j < cols; j++) {
			log_Lw[i][j] = log(0.001 + Lw[i][j]);
			Lw_sum += log_Lw[i][j];
		}
	}
	//Lwaver
	float Lwaver = exp(Lw_sum / (rows * cols));
	//Lg
	float **Lg;
	Lg = new float *[rows];
	for (int i = 0; i < rows; i++) {
		Lg[i] = new float[cols];
	}
	for (int i = 0; i < rows; i++) {
		for (int j = 0; j < cols; j++) {
			Lg[i][j] = log(Lw[i][j] / Lwaver + 1) / log(Lwmax / Lwaver + 1);
		}
	}
	//gain
	float **gain;
	gain = new float *[rows];
	for (int i = 0; i < rows; i++) {
		gain[i] = new float[cols];
	}
	for (int i = 0; i < rows; i++) {
		for (int j = 0; j < cols; j++) {
			gain[i][j] = Lg[i][j] / Lw[i][j];
		}
	}
	//gain*B, gain*G, gain*R
	for (int i = 0; i < rows; i++) {
		for (int j = 0; j < cols; j++) {
			B[i][j] *= gain[i][j];
			G[i][j] *= gain[i][j];
			R[i][j] *= gain[i][j];
		}
	}
	simple_color_balance(B, B, rows, cols);
	simple_color_balance(G, G, rows, cols);
	simple_color_balance(R, R, rows, cols);

	for (int i = 0; i < rows; i++) {
		for(int j = 0; j < cols; j++){
			out_img.at<Vec3b>(i, j)[0] = uchar((int)B[i][j]);
			out_img.at<Vec3b>(i, j)[1] = uchar((int)G[i][j]);
			out_img.at<Vec3b>(i, j)[2] = uchar((int)R[i][j]);
		}
	}
	//Free
	//DouImg
	for (int i = 0; i < rows; i++) {
		for (int j = 0; j < cols; j++) {
			delete DouImg[i][j];
		}
		delete DouImg[i];
	}
	delete DouImg;
	//Lw
	for (int i = 0; i < rows; i++) {
		delete[] Lw[i];
	}
	delete Lw;
	//log_Lw
	for (int i = 0; i < rows; i++) {
		delete[] log_Lw[i];
	}
	delete log_Lw;
	//B
	for (int i = 0; i < rows; i++) {
		delete[] B[i];
	}
	delete B;
	//G
	for (int i = 0; i < rows; i++) {
		delete[] G[i];
	}
	delete G;
	//R
	for (int i = 0; i < rows; i++) {
		delete[] R[i];
	}
	delete R;
	//Lg
	for (int i = 0; i < rows; i++) {
		delete[] Lg[i];
	}
	delete Lg;
	//gain
	for (int i = 0; i < rows; i++) {
		delete[] gain[i];
	}
	delete gain;
	return 0;
}

头文件:

#pragma once
#include "opencv2\opencv.hpp"
#include "cv.h"
#include "iostream"
#include "algorithm"
using namespace std;
using namespace cv;

void simple_color_balance(float ** input_img, float ** out_img, int rows, int cols);
int HDR(cv::Mat input_img, cv::Mat out_img);

优化版本出来了,我会再放上来,欢迎大家多交流。我的github:点这里

【ISP图像处理】Tone Mapping基础知识及相关算法(附代码) 一般LDR(Low Dynamic Range)图像的颜色显示范围通常只有8位,即每个颜色通道的颜色数值有2^8=256个等级。这个量级用于描述现实场景中的景象往往十分有限,以LDR储存图像往往需要对颜色进行压缩。为了更加真实还原真实场景的颜色,HDR图像应运而生,一般通道位数超过8位,便可称为HDR,常见有12位和16位。虽然存储图像的信息量提升了,但是现在使用的大部分显示设备宽动态范围只有100:1甚至更低。为了使得HDR图像能够在低动态范围的显示设备上显示,Tone Mapping技术便十分重要。 阅读详情

相关推荐

Enhanced local tone mapping for detail preserving reproduction of highdynamic range images

ABSTRAC T增强局部音调映射(ELTM)是一种灵活的音调映射算子,旨在在各种测试场景中同时提供良好的全局和局部对比度。此外,它有直观的和解耦的调优界面,为用户提供了对最终图像外观的完全控制。ELTM基于细节/基础层分解,在线性域和对数域压缩基面。这为ELTM提供了鲁棒性,而改进的音调压缩函数提供了良好的局部对比度。使用不同内容、亮度和分辨率的图像对结果进行了验证。在本次测试中,ELTM在7个最先进的全球和本地音调映射算子中被认为是最佳的音调映射算子。甚至更好的整体效果,通过使用建议的亮度控制,以处理极

u013049912的博客 1158

【图像处理】一种低光照图像的亮度提升方法(Adaptive Local Tone Mapping Based on Retinex for High Dynamic Range Images)

【fishing-pan:https://blog.youkuaiyun.com/u013921430 转载请注明出处】 前言   在实际的拍照过程中,常常会遇到,光线不足的情况。这时候单反用户一般会调大感光度,调大光圈,以让照片整体更清晰,更亮。那么如果照片已经被拍的很暗了,怎么办呢?这时候我们可以利用算法来对提升图像整体的光照情况,让图像更清晰。   2013年这篇《Adaptive Local Tone...

不用先生的博客 1万+

视频HDR -> LDR问题(Tone Mapping)综述

笔者按:最近开始作视频HDR的相关工作,对相关内容都不太了解,从综述文章开始阅读。本文主要记录文章 《A comparative review of tone-mapping algorithms for high dynamic range video》的阅读记录。Review文章不会讲很具体的原理,只是给出一些启发式的公式,作为这个问题的入门。 这篇文章的展开逻辑是先笼统地讲讲HDR,然后图像HDR,然后视频HDR,一直到第六章才会从原理上讲一些TM算法的详细原理。想看具体的算法原理的同学也可以直接看

q274488181的博客 4085

一种快速简单而又有效的低照度图像恢复算法

                       一种快速简单而又有效的低照度图像恢复算法 《Adaptive Local Tone Mapping Based on Retinex for High Dynamic Range Images  》的文章提出的主要内容时这对高动态图像的显示问题,他结合传统的Retinex技术提出了全局自适应和局部自适应的HDR实现过程,我也实现了整个的代码,但感觉前...

大熊 7932

Tone Mapping Correction

上一篇说了 Gamma 矫正的概念,而色调映射的本质理解和 Gamma 有相似之处,所以就顺着思路说到色调映射的概念。色调映射(Tone mapping)用一句话来总结就是用于在显示设备上面更好的呈现出 HDR 的图像效果,包括亮度以及色彩的主观感觉上的增强,最直观的影响就是会造成色调和对比度的变化,从目的上来讲,Tone mapping 和 Gamma 的之所以诞生最开始的作用都是用来在 LDR 设备上面显示 HDR 图像的。

YellowMax 2698

tone mapping code.rar_Local Tone Mapping_tone mapping _tone mapp

专门为彩色图像实行的局部色调映射 算法,比全局色调映射更好的还原了细节灰度。

低照度图像恢复算法

基于《Adaptive Local Tone Mapping Based on Retinex for High Dynamic Range Images 》 主要公式如下:  是全自适应输出的结果,我们这里就是需要得到他,表示输入图像的luminance值(亮度值),表示输入图像亮度值对的最大值,表示输入亮度对数的平均值,如下式所示 c++主要代码: void ALTM_R...

favomj的博客 1217

c++rgb-hdr.cpp_hdr_HDR算法_datew3n_

hdr算法的c++实现(曝光/饱和对比度)

tonemapping:Adaptive Local Tone Mapping Based on Retinex for High Dynamic Range Images

最终公式9将 公式3中的L(x,y)替换为 V1, 然后解释了为什么是 dodging 和 burned.每个尺度求一个高斯差分。若高斯差分的值小于某个阈值,则认为该尺度是平坦的。利用dodging and burning方法将公式3变为公式9。进而找到满足小于阈值条件下的最大的尺度 s, 命名为sm.某个点的像素是 应该降低还是上升应该受到周围像素的影响。以上其实是找到该像素周围最大的平坦区域。其中公式9的原理是什么呢?公式5,6,7表示高斯差分。公式8找到满足条件的s。

tony365的博客 549

MAX30102心率血氧传感器

估算AC、DC值的方法如下:找两个波谷点,两个波谷点之间有一个波峰点,两个波谷点相连成一条直线,与Y轴平行的线穿过波峰点会与两个波谷点连接成的直线相交于一点,这个点就是DC点,DC点的Y轴对应值就是直流分量,AC分量的值为波峰点到DC点之间的差值。在医院测量中常用的一种血氧采集方式,如下图所示,光电传感器和光源分别置于手指的两侧,光源穿过手指被另一侧的光电二极管接收,根据光衰减量计算血氧浓度。那么,根据上面的Beer-Lambert 定理,针对测量的具体场景,测量过程的衰减为三层穿透物质衰减量的叠加。

qq_41861711的博客 1万+

YOLOv11多模态融合实战:基于YOLOFuse的RGB与红外线(IR)协同检测技术解析

本文深入解析了基于YOLOv11的YOLOFuse多模态融合技术,重点探讨了RGB与红外线(IR)协同检测的实现原理与实战应用。文章详细介绍了双流架构与数据级、特征级、决策级三种融合策略,并通过实战案例展示了其在低光照、复杂环境下显著提升检测精度与鲁棒性的优势,为全天候安防、自动驾驶等场景提供了有效的技术解决方案。

weixin_29041195的博客 648

learn opencv-HDR成像

参考:https://github.com/spmallick/learnopencv使用OpenCV进行高动态范围(HDR)成像(C ++ / Python)什么是高动态范围(HDR)成像?大多数数码相机和显示器都将彩色图像捕获或显示为24位矩阵。 每个颜色通道有8位,因此每个通道的像素值在0-255范围内。 换句话说,普通的相机或显示器的动态范围是有限的。但是,我们周围的世界有一个非常大的动态范

风吴痕的博客 9945

修勾逃生巨人危机v10.9.9修改版:免广告无限内购与GM工具详解

游戏修改技术是通过对原版游戏程序进行代码层面的调整,实现特定功能的增强或限制解除。其核心原理涉及内存修改、资源替换和API拦截等技术手段,能够有效提升用户体验和测试效率。在移动游戏领域,免广告和无限内购是常见的技术实现方向,通过屏蔽广告SDK调用和修改内购验证逻辑,为用户提供更流畅的游戏体验。这类技术特别适合游戏开发者进行功能测试,以及玩家希望完整体验游戏内容而不受商业模式限制的场景。以修勾逃生巨人危机v10.9.9版本为例,该修改版集成了GM工具开启功能,通过特定操作路径即可激活调试面板,实现了广告去除和

weixin_30855099的博客 2588

ALTM算法简谈

ALTM算法简谈 优快云创作小白,这几天接触了很多新的东西,觉得有一些深度,也很有价值,想记录一下,有需要的朋友也可以对这方面了解的更加深入一些。 从ALTM的全名入手 Adaptive Local Tone Mapping Based on Retinex for High Dynamic Range Images 翻译一下大致就是自适应的局部色调映射基于Rrtinex为了HDR图像。 这个算法中有几个比较重要的点: 该算法分为两个部分,第一部分是全局的自适应,第二部分是局部的自适应 该算法是基于Re

m0_46624423的博客 2422

用ESP32-S3+OV2640摄像头+ILI9488屏,DIY一个能联网的智能猫眼(附完整代码)

本文详细介绍了如何利用ESP32-S3微控制器搭配OV2640摄像头和ILI9488显示屏,DIY一个功能强大的智能猫眼系统。从硬件选型、电路设计到软件开发,提供了完整的解决方案和优化技巧,包括图像采集显示、WiFi远程访问及低功耗设计,适合智能家居爱好者动手实践。

weixin_30897233的博客 501

移动支付APP(仿支付宝)

Toast.makeText(PayActivity.this, "支付失败:" + payResponse.getMsg(), Toast.LENGTH_SHORT).show();Toast.makeText(PayActivity.this, "支付失败:" + t.getMessage(), Toast.LENGTH_SHORT).show();Toast.makeText(PayActivity.this, "支付失败", Toast.LENGTH_SHORT).show();

寒寒豆豆软件公司的博客 134

转载之色调映射

一、概述         虽然HDR 图像有较大的动态范围,能更细致地反映真实场景,但他的缺点也很明显。一是同尺寸的数据比低动态范围图像大,需要更大的存储空间与传输带宽。二是难以输出,目前大多数显示器、打印机等图形输出设备的动态范围要比普通的高动态范围图像小得多。。因此,色调映射技术在这样的背景下,就显得尤为重要。HDR 图像处理的一...

a1的博客 4479

【光斑定位】空间激光通信、光斑定位、CCD、光斑定位——13000字

0.完整源码获得方式 订阅MATLAB/FPGA教程,免费获得教程案例以及任意2份完整源码 ----------------------------------------------------------------- 空间激光通信是指以光波作为载波进行数据传输的一种通信方式。目前,空间激光通信己成为人们关注的焦点。在空间激光通信系统中,光斑定位是是一项关键技术。 本论文首先对国内外空间激光通信系统的研究现状进行了阐述,论述了空间激光通信的理论只是,并对CCD成像原理,...

FPGA/MATLAB学习教程/源码/项目合作开发 1288

一种基于视神经网络的高动态范围(HDR)图像自适应局部色调映射的实现【OpenCV】【CUDA】

原理是基于这篇论文——《Adaptive Local Tone Mapping Based on Retinex for High Dynamic Range Images》 论文提出的背景 虽然可以从不同曝光的照片中获得包含真实场景全动态范围的高动态范围 (HDR) 图像,但是普通显示器等低动态范围(LDR)显示设备无法处理场景的全动态范围。LDR 设备只能显示两个数量级的。一旦将 H...

ShaderJoy 的兴趣技术杂货铺 4721

彻底解决Win11锁屏界面黑屏或者图片不变化

windows锁屏后黑屏

renkai721的专栏 1万+

基于毫米波雷达的智能风扇算法设计与实现

摘要:本文设计了一种基于毫米波雷达的智能风扇控制系统,采用FMCW雷达实现人体目标的精准检测与定位。系统通过距离FFT、速度FFT、CFAR检测和AoA估计构建完整的信号处理链路,并针对风扇叶片干扰设计了基于自相关函数的抗干扰算法。创新性地提出了人在开机、多人优先送风、摇头追踪等控制策略。研究采用MATLAB完成全链路算法仿真验证,并在STM32平台上实现实物系统。实验表明,该系统可实现0.15m测距精度和±60°方位角覆盖,有效解决了传统风扇的能源浪费和用户体验问题。本文提供了完整的MATLAB仿真代码和

huanghm88的专栏 403

毕设—高动态范围图像渲染算法之基于Retinex的色调映射技术(七)

这次和前几次一样,也是只介绍算法思路和实现步骤,再给出本人项目中Retinex的代码,Retinex的原理就不做解释。参考的论文是《Adaptive Local Tone Mapping Based on Retinex for High Dynamic Range Images》 本篇参考论文把算法分为两个部分,第一个部分是全局色调映射;第二部分是局部色调映射。全局自适应这部分原理既简单又容易实现,局部自适应这部分原理不简单但是容易实现。

A_ACM的博客 1852

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Tone-Mapping Using Perceptual-Quantizer and Image Histogram

分享一篇在谷歌学术上看到的2020年的一篇色调映射与直方图结合的文章。 这篇文章之前17年在TIE上又一篇类似的文章。**《A tone-mapping technique based on histogram using a sensitivity model of the human visual system》**这两篇文章有异曲同工之处(17年的这篇文章代码以及开源),下面就来说说2020的这篇文章。 这篇文章引入了一个感知量化(PQ)的概念,文章中作者说PQ跟HVS的工作原理类似,并且比HVS效果

qq_35872942的博客 870

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Unity 3D : 圖像暗部增強的算法

主要參考這幾位大老實現 論文 : Adaptive Local Tone Mapping Based on Retinex for High Dynamic Range Images 程式碼 : https://www.cnblogs.com/Imageshop/p/9460334.html 主要公式 : _ Lw : 輸入的 Log 亮度平均值 Lg : 自適應的結果 ( 可以...

攝影界的碼農 946

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

OpenCV图像处理专栏十二 |《基于二维伽马函数的光照不均匀图像自适应校正算法》

欢迎STAR我的论文复现工程: https://github.com/BBuf/-Image-processing-algorithm 算法原理 论文使用了Retinex的多尺度高斯滤波求取光照分量,然后使用了二维Gamma函数针对原图的HSV空间的V分量进行亮度改变,得到结果。原理还是蛮简单的,因为是中文论文,且作者介绍得很清楚,我就不细说了,可以自己看论文,论文地址: https://wenk...

I good vegetable a! 8840
上一篇: Softmax函数求导
下一篇: OpenCV图像处理专栏二十 |《Adaptive Logarithmic Mapping For Displaying High Contrast Scenes》复现
just_sort
博客等级 码龄11年 2356粉丝 1667原创
评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值