OpenCV C++ 图像平滑和几何变换
在计算机视觉与数字图像处理领域,图像平滑与几何变换是构建复杂图像处理系统的基石。本文将深入剖析 OpenCV C++ 库中图像平滑与几何变换的核心技术。我们不仅会详细解读均值滤波、高斯滤波等平滑方法,以及平移、旋转、仿射变换和缩放等几何操作的原理与公式推导,还会结合具体的函数原型与示例代码,帮助读者快速上手实践。

在计算机视觉与数字图像处理领域,图像平滑与几何变换是构建复杂图像处理系统的基石。本文将深入剖析 OpenCV C++ 库中图像平滑与几何变换的核心技术。我们不仅会详细解读均值滤波、高斯滤波等平滑方法,以及平移、旋转、仿射变换和缩放等几何操作的原理与公式推导,还会结合具体的函数原型与示例代码,帮助读者快速上手实践。
一、图像平滑
1.1 平滑概念
图像平滑(Image Smoothing),也被称为图像模糊(Image Blurring),是数字图像处理中最基础且重要的操作之一。其核心目标是降低图像中的噪声和减少图像细节,使图像看起来更加 “平滑” 或 “模糊”。
在实际应用中,图像平滑常用于以下场景:
-
噪声去除:例如相机传感器产生的椒盐噪声、高斯噪声等
-
预处理步骤:在边缘检测、特征提取等操作前减少噪声干扰
-
图像简化:降低图像复杂度,突出主要特征
平滑的基本原理
图像平滑本质上是一种邻域运算,通过对像素及其周围邻域内的像素值进行加权平均来实现。这种运算可以用数学公式表示为:
g(x,y)=∑i,j∈Sw(i,j)⋅f(x+i,y+j)g(x,y) = \sum_{i,j \in S} w(i,j) \cdot f(x+i, y+j)g(x,y)=∑i,j∈Sw(i,j)⋅f(x+i,y+j)
其中:
-
f(x,y)f(x,y)f(x,y) 是原始图像在位置 (x,y)(x,y)(x,y) 处的像素值
-
g(x,y)g(x,y)g(x,y) 是处理后图像在相同位置的像素值
-
SSS 是定义的邻域范围(例如 3×3、5×5 的矩阵)
-
w(i,j)w(i,j)w(i,j) 是邻域内每个点的权重值,不同的平滑方法有不同的权重计算方式
1.2 均值滤波(Mean Filter)
函数原型(OpenCV)
void blur(InputArray src, OutputArray dst, Size ksize,
Point anchor=Point(-1,-1), int borderType=BORDER_DEFAULT);
参数说明:
-
src:输入图像 -
dst:输出图像,与输入图像大小和类型相同 -
ksize:卷积核大小,例如Size(3,3)表示 3×3 的矩阵 -
anchor:锚点位置,默认值(-1,-1)表示锚点位于核中心 -
borderType:边界处理方式
原理与公式
均值滤波是最简单的平滑方法,它用邻域内所有像素的平均值替换中心像素值。对于一个 k×kk \times kk×k 的卷积核,每个像素的权重都是 1k2\frac{1}{k^2}k21。
数学公式表示为:
g(x,y)=1k2∑i,j∈Sf(x+i,y+j)g(x,y) = \frac{1}{k^2} \sum_{i,j \in S} f(x+i, y+j)g(x,y)=k21∑i,j∈Sf(x+i,y+j)
例如,一个 3×3 的均值滤波卷积核为:
19[111111111]\frac{1}{9} \begin{bmatrix} 1 & 1 & 1 \\ 1 & 1 & 1 \\ 1 & 1 & 1 \end{bmatrix}91 111111111
示例代码
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main() {
// 读取图像
Mat image = imread("lena.jpg", IMREAD_COLOR);
if (image.empty()) {
cout << "Could not open or find the image" << endl;
return -1;
}
// 均值滤波
Mat blurred;
blur(image, blurred, Size(5, 5)); // 使用5×5的卷积核
// 显示原图和处理后的图像
imshow("Original Image", image);
imshow("Blurred Image (Mean Filter)", blurred);
// 保存结果
imwrite("mean_filter_result.jpg", blurred);
waitKey(0);
return 0;
}
1.3 高斯滤波(Gaussian Filter)
函数原型(OpenCV)
void GaussianBlur(InputArray src, OutputArray dst, Size ksize,
double sigmaX, double sigmaY=0,
int borderType=BORDER_DEFAULT);
参数说明:
-
src和dst:输入 / 输出图像 -
ksize:卷积核大小,必须是奇数 -
sigmaX:X 方向的高斯核标准差 -
sigmaY:Y 方向的高斯核标准差,默认与sigmaX相同 -
borderType:边界处理方式
原理与公式
高斯滤波是一种加权平均滤波,它根据高斯函数计算邻域内每个像素的权重。与均值滤波不同,高斯滤波对距离中心越近的像素赋予更高的权重,因此能在平滑图像的同时更好地保留边缘。
二维高斯函数公式为:
G(x,y)=12πσ2e−x2+y22σ2G(x,y) = \frac{1}{2\pi\sigma^2} e^{-\frac{x^2+y^2}{2\sigma^2}}G(x,y)=2πσ21e−2σ2x2+y2
其中 σ\sigmaσ 是标准差,控制高斯函数的 “宽度”。
例如,一个 3×3 的高斯卷积核(σ=1.0\sigma=1.0σ=1.0)可能是:
116[121242121]\frac{1}{16} \begin{bmatrix} 1 & 2 & 1 \\ 2 & 4 & 2 \\ 1 & 2 & 1 \end{bmatrix}161 121242121
示例代码
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main() {
// 读取图像
Mat image = imread("lena.jpg", IMREAD_COLOR);
if (image.empty()) {
cout << "Could not open or find the image" << endl;
return -1;
}
// 高斯滤波
Mat gaussianBlur;
GaussianBlur(image, gaussianBlur, Size(5, 5), 0, 0); // 5×5卷积核,标准差自动计算
// 显示原图和处理后的图像
imshow("Original Image", image);
imshow("Gaussian Blur", gaussianBlur);
// 保存结果
imwrite("gaussian_filter_result.jpg", gaussianBlur);
waitKey(0);
return 0;
}
1.4 中值滤波(Median Filter)
函数原型(OpenCV)
void medianBlur(InputArray src, OutputArray dst, int ksize);
参数说明:
-
src和dst:输入 / 输出图像 -
ksize:卷积核大小,必须是奇数
原理
中值滤波是一种非线性滤波方法,它用邻域内所有像素值的中值替换中心像素值。具体步骤如下:
-
将邻域内的像素值按升序排列
-
选择中间值作为中心像素的新值
例如,对于以下 5×5 邻域内的像素值:
\[120, 200, 150, 90, 180,
170, 140, 160, 110, 130,
190, 210, 100, 125, 145,
220, 135, 165, 185, 205,
80, 105, 155, 175, 195]
排序后为:
\[80, 90, 100, 105, 110, 120, 125, 130, 135, 140,
145, 150, 155, 160, 165, 170, 175, 180, 185, 190,
195, 200, 205, 210, 220]
中值为第 13 个元素:150
示例代码
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main() {
// 读取图像
Mat image = imread("lena.jpg", IMREAD_COLOR);
if (image.empty()) {
cout << "Could not open or find the image" << endl;
return -1;
}
// 添加椒盐噪声
Mat noisyImage = image.clone();
int noiseAmount = 10000;
for (int i = 0; i < noiseAmount; i++) {
int x = rand() % noisyImage.cols;
int y = rand() % noisyImage.rows;
if (i % 2 == 0) {
noisyImage.at<Vec3b>(y, x) = Vec3b(255, 255, 255); // 白点
} else {
noisyImage.at<Vec3b>(y, x) = Vec3b(0, 0, 0); // 黑点
}
}
// 中值滤波
Mat medianFiltered;
medianBlur(noisyImage, medianFiltered, 5); // 使用5×5邻域
// 显示原图、噪声图和处理后的图像
imshow("Original Image", image);
imshow("Noisy Image", noisyImage);
imshow("Median Filtered", medianFiltered);
// 保存结果
imwrite("median_filter_result.jpg", medianFiltered);
waitKey(0);
return 0;
}
1.5 双边滤波(Bilateral Filter)
函数原型(OpenCV)
void bilateralFilter(InputArray src, OutputArray dst, int d,
double sigmaColor, double sigmaSpace,
int borderType=BORDER_DEFAULT);
参数说明:
-
src和dst:输入 / 输出图像 -
d:过滤时使用的像素邻域直径 -
sigmaColor:颜色空间滤波器的标准差 -
sigmaSpace:坐标空间滤波器的标准差 -
borderType:边界处理方式
原理与公式
一些滤波器再去除噪声的同时会模糊掉图像边缘,为了一定程度上保留边缘,可以选择双边滤波,它是一种保边去噪的滤波方法,它同时考虑了空间距离和颜色差异两个因素:
-
空间域权重:与高斯滤波类似,距离越近权重越高
-
值域权重:颜色差异越小权重越高
数学公式表示为:
g(x,y)=1Wp∑i,j∈Sf(i,j)⋅ws(i,j)⋅wr(i,j)g(x,y) = \frac{1}{W_p} \sum_{i,j \in S} f(i,j) \cdot w_s(i,j) \cdot w_r(i,j)g(x,y)=Wp1∑i,j∈Sf(i,j)⋅ws(i,j)⋅wr(i,j)
其中:
-
WpW_pWp 是归一化系数
-
ws(i,j)w_s(i,j)ws(i,j) 是空间域权重,由高斯函数计算
-
wr(i,j)w_r(i,j)wr(i,j) 是值域权重,取决于颜色差异
示例代码
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main() {
// 读取图像
Mat image = imread("lena.jpg", IMREAD_COLOR);
if (image.empty()) {
cout << "Could not open or find the image" << endl;
return -1;
}
// 双边滤波
Mat bilateralFiltered;
bilateralFilter(image, bilateralFiltered, 15, 80, 80);
// d=15: 表示在过滤时选取的邻域直径为15像素
// sigmaColor=80: 颜色空间滤波器的标准差,值越大表示颜色差异越大的像素会被混合在一起
// sigmaSpace=80: 坐标空间滤波器的标准差,值越大表示距离越远的像素会相互影响
// 显示原图和处理后的图像
imshow("Original Image", image);
imshow("Bilateral Filtered", bilateralFiltered);
// 保存结果
imwrite("bilateral_filter_result.jpg", bilateralFiltered);
waitKey(0);
return 0;
}
1.6 总结与对比
| 方法 | 类型 | 原理 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|---|
| 均值滤波 | 线性 | 邻域平均值 | 速度快 | 模糊边缘 | 初步预处理 |
| 高斯滤波 | 线性 | 基于高斯函数的加权平均 | 抑制高斯噪声 | 计算复杂度较高 | 大多数场景 |
| 中值滤波 | 非线性 | 邻域中值替换 | 抑制椒盐噪声 | 不适合高斯噪声 | 椒盐噪声处理 |
| 双边滤波 | 非线性 | 考虑空间和颜色差异 | 保留边缘 | 计算复杂度极高 | 美颜、细节保留场景 |
在实际应用中,应根据具体需求选择合适的平滑方法。如果需要快速处理且对细节要求不高,可以选择均值滤波;如果需要保留边缘信息,高斯滤波或双边滤波是更好的选择;而处理椒盐噪声时,中值滤波通常是首选。
二、几何变换
在图像处理中,几何变换是改变图像形状、位置和大小的重要操作,它不改变图像的像素值,而是通过对像素坐标的重新映射实现图像的重新布局。常见的几何变换包括平移、旋转、仿射变换和缩放,这些操作在图像配准、目标检测、图像矫正等领域有着广泛应用。
2.1 平移(Translation)
原理与公式推导
平移是将图像中每个像素在xxx轴和yyy轴方向上移动固定的距离。设原始图像中像素点坐标为(x,y)(x, y)(x,y),在xxx轴方向平移txt_xtx,在yyy轴方向平移tyt_yty,则平移后的坐标(x′,y′)(x', y')(x′,y′)可通过以下公式计算:
{x′=x+txy′=y+ty\begin{cases}x' = x + t_x \\y' = y + t_y\end{cases}{x′=x+txy′=y+ty
为了统一矩阵运算形式,引入齐次坐标表示,将二维坐标(x,y)(x, y)(x,y)扩展为三维坐标(x,y,1)(x, y, 1)(x,y,1),此时平移变换可以用矩阵乘法表示:
[x′y′1]=[10tx01ty001][xy1]\begin{bmatrix}x' \\ y' \\ 1\end{bmatrix} = \begin{bmatrix}1 & 0 & t_x \\ 0 & 1 & t_y \\ 0 & 0 & 1\end{bmatrix}\begin{bmatrix}x \\ y \\ 1\end{bmatrix} x′y′1 = 100010txty1 xy1
其中,左侧矩阵称为平移矩阵TTT,通过该矩阵与原始坐标向量相乘,即可得到平移后的坐标。
函数原型(OpenCV)
Mat getTranslationMatrix2D(Point2f offset);
void warpAffine(InputArray src, OutputArray dst, InputArray M, Size dsize,
int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT,
const Scalar& borderValue=Scalar());
getTranslationMatrix2D函数用于生成平移矩阵,参数offset是一个Point2f类型,表示在xxx轴和yyy轴方向上的平移量;warpAffine函数用于对图像进行仿射变换,参数src为输入图像,dst为输出图像,M为变换矩阵,dsize为输出图像的大小。
示例代码
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main() {
Mat image = imread("lena.jpg");
if (image.empty()) {
cout << "Could not open or find the image" << endl;
return -1;
}
// 生成平移矩阵,x方向平移100像素,y方向平移50像素
Mat T = getTranslationMatrix2D(Point2f(100, 50));
Mat translatedImage;
// 应用平移变换
warpAffine(image, translatedImage, T, image.size());
imshow("Original Image", image);
imshow("Translated Image", translatedImage);
waitKey(0);
return 0;
}
2.2 旋转(Rotation)
原理与公式推导
旋转是将图像围绕一个指定点(通常是图像中心)旋转一定角度。设原始像素点坐标为(x,y)(x, y)(x,y),绕原点旋转θ\thetaθ角度后得到新坐标(x′,y′)(x', y')(x′,y′) 。根据三角函数关系,可推导出以下公式:
{x′=xcosθ−ysinθy′=xsinθ+ycosθ\begin{cases}x' = x \cos\theta - y \sin\theta \\y' = x \sin\theta + y \cos\theta\end{cases}{x′=xcosθ−ysinθy′=xsinθ+ycosθ
转换为齐次坐标和矩阵乘法形式:
[x′y′1]=[cosθ−sinθ0sinθcosθ0001][xy1]\begin{bmatrix}x' \\y' \\1\end{bmatrix} =\begin{bmatrix}\cos\theta & -\sin\theta & 0 \\\sin\theta & \cos\theta & 0 \\0 & 0 & 1\end{bmatrix}\begin{bmatrix}x \\y \\1\end{bmatrix} x′y′1 = cosθsinθ0−sinθcosθ0001 xy1
如果旋转中心不是原点,而是图像中心(cx,cy)(c_x, c_y)(cx,cy),则需要先将图像平移到原点,进行旋转后再平移回原来位置,完整的旋转矩阵为:
[x′y′1]=[cosθ−sinθ0sinθcosθ0001][xy1]\begin{bmatrix}x' \\ y' \\ 1\end{bmatrix} = \begin{bmatrix}\cos\theta & -\sin\theta & 0 \\ \sin\theta & \cos\theta & 0 \\ 0 & 0 & 1\end{bmatrix}\begin{bmatrix}x \\ y \\ 1\end{bmatrix} x′y′1 = cosθsinθ0−sinθcosθ0001 xy1
函数原型(OpenCV)
Mat getRotationMatrix2D(Point2f center, double angle, double scale);
void warpAffine(InputArray src, OutputArray dst, InputArray M, Size dsize,
int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT,
const Scalar& borderValue=Scalar());
getRotationMatrix2D函数用于生成旋转矩阵,参数center表示旋转中心,angle表示旋转角度(单位为度),scale表示缩放比例;warpAffine函数同样用于应用变换。
示例代码
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main() {
Mat image = imread("lena.jpg");
if (image.empty()) {
cout << "Could not open or find the image" << endl;
return -1;
}
Point2f center(image.cols / 2, image.rows / 2);
double angle = 45; // 旋转45度
double scale = 1;
// 生成旋转矩阵
Mat R = getRotationMatrix2D(center, angle, scale);
Mat rotatedImage;
// 应用旋转变换
warpAffine(image, rotatedImage, R, image.size());
imshow("Original Image", image);
imshow("Rotated Image", rotatedImage);
waitKey(0);
return 0;
}
2.3 仿射变换(Affine Transformation)
原理与公式推导
仿射变换是一种线性变换,它保持了图像中的 “直线性” 和 “平行性”,可以实现平移、旋转、缩放、错切等多种变换的组合。仿射变换的一般公式为:
{x′=a1x+a2y+a3y′=a4x+a5y+a6\begin{cases}x' = a_1 x + a_2 y + a_3 \\y' = a_4 x + a_5 y + a_6\end{cases}{x′=a1x+a2y+a3y′=a4x+a5y+a6
用齐次坐标和矩阵乘法表示为:
[x′y′1]=[a1a2a3a4a5a6001][xy1]\begin{bmatrix}x' \\y' \\1\end{bmatrix} =\begin{bmatrix}a_1 & a_2 & a_3 \\a_4 & a_5 & a_6 \\0 & 0 & 1\end{bmatrix}\begin{bmatrix}x \\y \\1\end{bmatrix} x′y′1 = a1a40a2a50a3a61 xy1
要确定仿射变换矩阵,需要已知原始图像中三个不共线的点及其在变换后图像中的对应点,通过解线性方程组即可得到矩阵中的六个参数。
函数原型(OpenCV)
Mat getAffineTransform(const Point2f src[], const Point2f dst[]);
void warpAffine(InputArray src, OutputArray dst, InputArray M, Size dsize,
int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT,
const Scalar& borderValue=Scalar());
getAffineTransform函数根据原始图像和目标图像中三个对应点对,计算仿射变换矩阵;warpAffine函数用于应用变换。
示例代码
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main() {
Mat image = imread("lena.jpg");
if (image.empty()) {
cout << "Could not open or find the image" << endl;
return -1;
}
Point2f srcPoints[] = { Point2f(0, 0), Point2f(image.cols - 1, 0), Point2f(0, image.rows - 1) };
Point2f dstPoints[] = { Point2f(50, 50), Point2f(image.cols - 50, 30), Point2f(20, image.rows - 80) };
// 计算仿射变换矩阵
Mat M = getAffineTransform(srcPoints, dstPoints);
Mat affineImage;
// 应用仿射变换
warpAffine(image, affineImage, M, image.size());
imshow("Original Image", image);
imshow("Affine Transformed Image", affineImage);
waitKey(0);
return 0;
}
2.4 缩放(Scaling)
原理与公式推导
缩放是改变图像大小的操作,分为放大和缩小。设原始像素点坐标为(x,y)(x, y)(x,y),在xxx轴方向缩放比例为sxs_xsx,在yyy轴方向缩放比例为sys_ysy,则缩放后的坐标(x′,y′)(x', y')(x′,y′)计算公式为:
{x′=sx⋅xy′=sy⋅y\begin{cases}x' = s_x \cdot x \\y' = s_y \cdot y\end{cases}{x′=sx⋅xy′=sy⋅y
转换为齐次坐标和矩阵乘法形式:
[x′y′1]=[sx000sy0001][xy1]\begin{bmatrix}x' \\y' \\1\end{bmatrix} =\begin{bmatrix}s_x & 0 & 0 \\0 & s_y & 0 \\0 & 0 & 1\end{bmatrix}\begin{bmatrix}x \\y \\1\end{bmatrix} x′y′1 = sx000sy0001 xy1
如果sx=sys_x = s_ysx=sy,则为等比例缩放;如果sx≠sys_x \neq s_ysx=sy,则为非等比例缩放,会导致图像变形。
函数原型(OpenCV)
void resize(InputArray src, OutputArray dst, Size dsize, double fx=0, double fy=0,
int interpolation=INTER_LINEAR);
resize函数用于对图像进行缩放操作,参数src为输入图像,dst为输出图像,dsize为输出图像的大小;fx和fy分别为xxx轴和yyy轴方向的缩放比例,如果指定了dsize,则fx和fy会自动计算;interpolation表示插值方法,用于计算缩放后像素值,常见的有线性插值INTER_LINEAR、最近邻插值INTER_NEAREST等 。
示例代码
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main() {
Mat image = imread("lena.jpg");
if (image.empty()) {
cout << "Could not open or find the image" << endl;
return -1;
}
Mat scaledImage;
// 缩小为原来的0.5倍,使用线性插值
resize(image, scaledImage, Size(), 0.5, 0.5, INTER_LINEAR);
imshow("Original Image", image);
imshow("Scaled Image", scaledImage);
waitKey(0);
return 0;
}
2.5 总结与对比
| 变换类型 | 核心公式 | 主要参数 | 应用场景 | 函数原型 |
|---|---|---|---|---|
| 平移 | [x′y′1]=[10tx01ty001][xy1]\begin{bmatrix}x' \\ y' \\ 1\end{bmatrix} = \begin{bmatrix}1 & 0 & t_x \\ 0 & 1 & t_y \\ 0 & 0 & 1\end{bmatrix}\begin{bmatrix}x \\ y \\ 1\end{bmatrix} x′y′1 = 100010txty1 xy1 | 平移量(tx,ty)(t_x, t_y)(tx,ty) | 图像位置调整 | getTranslationMatrix2D、warpAffine |
| 旋转 | [x′y′1]=[cosθ−sinθ0sinθcosθ0001][xy1]\begin{bmatrix}x' \\ y' \\ 1\end{bmatrix} = \begin{bmatrix}\cos\theta & -\sin\theta & 0 \\ \sin\theta & \cos\theta & 0 \\ 0 & 0 & 1\end{bmatrix}\begin{bmatrix}x \\ y \\ 1\end{bmatrix} x′y′1 = cosθsinθ0−sinθcosθ0001 xy1 | 旋转中心、角度θ\thetaθ、缩放比例 | 图像方向调整 | getRotationMatrix2D、warpAffine |
| 仿射变换 | [x′y′1]=[a1a2a3a4a5a6001][xy1]\begin{bmatrix}x' \\ y' \\ 1\end{bmatrix} = \begin{bmatrix}a_1 & a_2 & a_3 \\ a_4 & a_5 & a_6 \\ 0 & 0 & 1\end{bmatrix}\begin{bmatrix}x \\ y \\ 1\end{bmatrix} x′y′1 = a1a40a2a50a3a61 xy1 | 三对对应点坐标 | 图像矫正、复杂变形 | getAffineTransform、warpAffine |
| 缩放 | [x′y′1]=[sx000sy0001][xy1]\begin{bmatrix}x' \\ y' \\ 1\end{bmatrix} = \begin{bmatrix}s_x & 0 & 0 \\ 0 & s_y & 0 \\ 0 & 0 & 1\end{bmatrix}\begin{bmatrix}x \\ y \\ 1\end{bmatrix} x′y′1 = sx000sy0001 xy1 | 缩放比例(sx,sy)(s_x, s_y)(sx,sy)或目标大小 | 调整图像尺寸 | resize |
几何变换是图像处理的基础操作,通过理解其数学原理和 OpenCV 函数的使用,能够灵活应对各种图像变换需求。在实际应用中,需根据具体场景选择合适的变换类型和参数,以达到理想的处理效果。
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)