磨皮特性 C++/C的OpenCV 实现
磨皮功能 C++/C的OpenCV 实现
前提条件
- OpenCV 安装: 你需要正确安装 OpenCV 库。
- C++ 编译器: 如 G++。
C++ 代码
#
include <opencv2/opencv.hpp>
#
include <iostream>
#
include <string>
// 使用标准命名空间
using
namespace std;
using
namespace cv;
/**
* @brief 对图像进行简单的磨皮处理 (使用双边滤波器)
*
* @param inputImage 输入的彩色图像
* @param d 滤波过程中每个像素邻域的直径。如果此值为非正数,则从 sigmaSpace 计算得到。
* @param sigmaColor 颜色空间滤波器的 sigma 值。这个参数的值越大,就意味着在邻域内有越宽广的颜色会被混合到一起,产生较大的半相等颜色区域。
* @param sigmaSpace 坐标空间滤波器的 sigma 值。这个参数的值越大,就意味着越远的像素会相互影响,从而使更大的区域中足够相似的颜色获取相同的颜色。当 d>0 时,d 指定了邻域大小且与 sigmaSpace 无关。否则,d 正比于 sigmaSpace。
* @return Mat 返回磨皮后的图像
*/
Mat simpleSkinSmoothing(
const Mat& inputImage,
int d = 15
,
double sigmaColor = 150
,
double sigmaSpace = 15
) {
if (inputImage.empty(
)
) {
cerr <<
"错误: 输入图像为空!" << endl;
return inputImage;
}
Mat smoothedImage;
bilateralFilter(inputImage, smoothedImage, d, sigmaColor, sigmaSpace)
;
return smoothedImage;
}
int main(
int argc,
char** argv) {
// --- 1. 加载图像 ---
string image_path = "portrait.jpg"
;
// 修改为你的肖像图片路径
if (argc >
1
) {
image_path = argv[1]
;
// 或者从命令行参数获取图片路径
}
Mat originalImage = imread(image_path, IMREAD_COLOR)
;
if (originalImage.empty(
)
) {
cout <<
"无法加载图像: " << image_path << endl;
return -1
;
}
cout <<
"图像加载成功: " << image_path << endl;
// --- 2. 应用磨皮处理 ---
// 调整这些参数以获得不同的磨皮效果
int diameter = 15
;
// 邻域直径。可以尝试 5, 10, 15, 20, 25 等
double sigma_color = 75
;
// 颜色标准差。可以尝试 50, 75, 100, 150 等
double sigma_space = 75
;
// 空间标准差。可以尝试 50, 75, 100, 150 等
cout <<
"应用磨皮效果: d=" << diameter <<
", sigmaColor=" << sigma_color <<
", sigmaSpace=" << sigma_space << endl;
Mat smoothedImage = simpleSkinSmoothing(originalImage, diameter, sigma_color, sigma_space)
;
if (smoothedImage.empty(
)
) {
cout <<
"磨皮处理失败。" << endl;
return -1
;
}
// --- 3. 显示结果 ---
namedWindow("原始图像"
, WINDOW_AUTOSIZE)
;
imshow("原始图像"
, originalImage)
;
namedWindow("简单磨皮效果"
, WINDOW_AUTOSIZE)
;
imshow("简单磨皮效果"
, smoothedImage)
;
cout <<
"按任意键退出..." << endl;
waitKey(0
)
;
// 等待按键
destroyAllWindows(
)
;
// 关闭所有窗口
return 0
;
}
如何编译
保存代码: 将上述代码保存为
skin_smoother.cpp。准备图片: 准备一张名为
portrait.jpg(或你在代码中指定的其他名称,或通过命令行传入) 的肖像图片,并将其放在与skin_smoother.cpp相同的目录下或指定正确路径。编译:
打开终端,使用以下命令编译 (假设你使用的是 g++,并且 OpenCV 已正确安装):g++ skin_smoother.cpp -o skin_smoother $(pkg-config --cflags --libs opencv4)- 注意:
opencv4可能需要根据你的 OpenCV 版本调整 (例如opencv或opencv3)。你可以通过运行pkg-config --libs opencv4来检查正确的链接标志。
- 注意:
如何运行
./skin_smoother
或者,如果你想指定图片路径:
./skin_smoother /path/to/your/portrait_image.jpg
程序会显示原始图像和磨皮后的图像。
代码解释
包含头文件
# include <opencv2/opencv.hpp> // OpenCV 主要头文件 # include <iostream> // 标准输入输出 # include <string> // STL stringsimpleSkinSmoothing函数Mat simpleSkinSmoothing( const Mat& inputImage, int d = 15 , double sigmaColor = 150 , double sigmaSpace = 15 ) { if (inputImage.empty( ) ) { /* ... 错误处理 ... */ } Mat smoothedImage; // 应用双边滤波器 bilateralFilter(inputImage, smoothedImage, d, sigmaColor, sigmaSpace) ; return smoothedImage; }- 这是核心的磨皮函数。它接收一个输入图像和双边滤波器的三个主要参数。
cv::bilateralFilter(): 这是 OpenCV 中实现双边滤波的函数。inputImage: 输入图像。smoothedImage: 输出的滤波后图像。d: 滤波过程中每个像素邻域的直径。值越大,计算越慢,但平滑区域会更大。sigmaColor: 颜色空间的标准差。值越大,意味着颜色差异更大的像素也会被一起平滑。sigmaSpace: 坐标空间的标准差。值越大,意味着距离更远的像素也会相互影响(如果它们的颜色相似的话)。
main函数- 加载图像 (
imread): 加载用户指定的或默认的图像。 - 调用磨皮函数:
这里设置了双边滤波器的参数。你可以调整这些值来观察不同的磨皮效果。int diameter = 15 ; double sigma_color = 75 ; double sigma_space = 75 ; Mat smoothedImage = simpleSkinSmoothing(originalImage, diameter, sigma_color, sigma_space) ; - 显示图像 (
imshow,waitKey): 显示原始图像和处理后的图像,并等待用户按键关闭。
- 加载图像 (
参数调整技巧
d(直径):- 较小的值 (如 5-10):平滑效果较弱,保留更多细节,计算速度快。
- 较大的值 (如 15-25 或更高):平滑效果更强,可能导致一些细节丢失,计算速度慢。对于高分辨率图像,可能需要更大的
d。
sigmaColor(颜色标准差):- 较小的值 (如 25-50):只有颜色非常相近的像素才会被平滑,保留更多纹理。
- 较大的值 (如 75-150 或更高):颜色差异较大的像素也会被平滑,导致更强的“涂抹”感,皮肤看起来更“干净”。
sigmaSpace(空间标准差):- 较小的值 (如 25-50):只有空间上非常接近的像素才会被一起考虑,效果更局部。
- 较大的值 (如 75-150 或更高):空间上较远的像素也会参与计算(如果颜色相似),平滑范围更广。
经验法则:
- 通常
sigmaColor和sigmaSpace会取相似的值。 - 可以从
d=15,sigmaColor=75,sigmaSpace=75开始尝试。 - 如果希望保留更多细节,减小这些值。
- 如果希望获得更强的平滑效果,增大这些值。
- 过度增大会导致图像看起来不自然,像塑料娃娃。
局限性
- 简单性: 这种方法非常基础,对于复杂的皮肤问题(如严重的痘痘、斑点或光照不均)可能效果有限。
- 全局性: 双边滤波器是全局应用的。如果只想对特定区域(如脸部皮肤)进行磨皮,需要先进行人脸检测和皮肤区域分割。
- 细节保留: 虽然双边滤波器比高斯模糊能更好地保留边缘,但非常强的磨皮参数仍然可能导致一些期望的细节(如痣、雀斑,如果想保留的话)模糊。
- 性能: 对于大图像和较大的
d值,双边滤波计算可能会比较慢。
对于更高级的磨皮效果,可能需要结合频率分离、表面模糊、更复杂的皮肤检测和遮罩技术,甚至深度学习方法。但对于快速实现一个简单的磨皮效果,双边滤波器是一个很好的起点。
浙公网安备 33010602011771号