系列文章目录

C++ OpenCV4.5环境搭建(一)

C++ OpenCV4.5常用API查询手册(二)

C++ OpenCV4.5 图像处理(三)

C++ OpenCV4.5 绘制形状与文字(四)

C++ OpenCV4.5 图像模糊(五)



前言

学了那么多OpenCV API,开始做一个小项目,巩固一下之前学的知识点



一、电子相册

针对一张图片,进行模糊、美颜、加边框和调亮度等等,制作一张电子相册,效果图如下:
在这里插入图片描述



二、实现原理

1.主函数

代码如下(示例):

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

Mat g_srcImg;			// 源图片	
Mat g_beautyFgImg;		// 美颜后的前景图片
Mat g_vagueBgImg;		// 模糊后背景图
Mat g_roiImg;			// 前景和背景组合后的图片
Mat g_rectImg;			// 绘制矩形边框
Mat g_brightImg;		// 调整亮度的图片

char g_szOutputWin[] = "output image";

// 调整模糊程度
int g_iVagueValue = 3;
int g_iVagueMaxSize = 10;
// 调整美颜程度
int g_iBeautyValue = 9;
int g_iBeautyMaxSize = 20;
// 绘制矩形,设置相框
int g_iRectValue = 5;
int g_iRectMaxSize = 30;
// 调整图片亮度
int g_iBrightValue = 6;
int g_iBrightMaxSize = 20;

// 调整模糊程度
void TrackbarVague(int, void*);
// 调整美颜程度
void TrackbarBeauty(int, void*);
// 绘制矩形,设置相框
void TrackbarRect(int, void*);
// 调整图片亮度
void TrackbarBright(int, void*);
// 将美颜前景图贴到模糊背景图层上
void SetROI(void);

int main(void)
{
	g_srcImg = imread("E:\\1.png");
	if (g_srcImg.empty())
	{
		cout << "load image fail..." << endl;
		return -1;
	}
	imshow("input image", g_srcImg);

	// 必须先创建窗口,不然滚动条无法绑定父窗口
	namedWindow(g_szOutputWin, WINDOW_AUTOSIZE);

	// 功能:创建滚动条并将其附加到指定的窗口
	// 参数:trackbarname 创建的滚动条的名称
	//		 winname 滚动条父窗口的名称
	//		 value 滚动条所在位置的值,滑动滚动条,该值会改变
	//		 count 滚动条的最大值,最小值总是0
	//		 onChange 指向滚动条改变位置时要调用的函数的指针(回调函数),函数的原型应该是void Foo(int,void*);
	//				其中第一个参数是滚动条所在位置,第二个参数是用户数据(见下一个参数);如果回调函数传空,则不调用回调,但只更新滚动条值
	//		 userdata 按原样传递给回调的用户数据,它可以用来处理滚动条不使用全局变量的事件。	
	//	返回:成功返回0		 
	createTrackbar("背景模糊", g_szOutputWin, &g_iVagueValue, g_iVagueMaxSize, TrackbarVague);
	TrackbarVague(0, 0);

	createTrackbar("前景美颜", g_szOutputWin, &g_iBeautyValue, g_iBeautyMaxSize, TrackbarBeauty);
	TrackbarBeauty(0, 0);

	createTrackbar("相框宽度", g_szOutputWin, &g_iRectValue, g_iRectMaxSize, TrackbarRect);
	TrackbarRect(0, 0);

	createTrackbar("图片亮度", g_szOutputWin, &g_iBrightValue, g_iBrightMaxSize, TrackbarBright);
	TrackbarBright(0, 0);

	waitKey(0);

	return 0;
}

2.调整背景模糊

代码如下(示例):

void TrackbarVague(int, void*)
{
	// SigmaX和SigmaY必须是奇数
	int iSigma = 2 * g_iVagueValue + 1;
	// 利用高斯模糊做底图
	GaussianBlur(g_srcImg, g_vagueBgImg, Size(iSigma, iSigma), iSigma, iSigma);

	// 全部初始化完才显示
	if (g_beautyFgImg.data && g_vagueBgImg.data)
	{
		SetROI();
	}
}

3.调整前景美颜

代码如下(示例):

void TrackbarBeauty(int, void*)
{
	// 利用双边模糊,实现磨皮的效果
	int iSigmaSpace = 50 + 10 * g_iBeautyValue;
	Mat tmpImg;
	bilateralFilter(g_srcImg, tmpImg, 15, iSigmaSpace, 0);

	// 再利用掩膜计算,增加图像对比度,最终实现美颜相机的效果
	Mat kernal = (Mat_<int>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
	filter2D(tmpImg, g_beautyFgImg, -1, kernal, Point(-1, -1), 0);

	// 功能:调整图像大小
	// 参数:src 源图像
	//		 dst 目标图像
	//		 dsize 输出图像大小,如果为(0, 0),则大小为(img.cols * fx, img.rows * fy)
	//		 fx x方向的缩小比例
	//		 fy y方向的缩小比例
	resize(g_beautyFgImg, g_beautyFgImg, Size(0, 0), 0.8, 0.8);

	// 全部初始化完才显示
	if (g_beautyFgImg.data && g_vagueBgImg.data)
	{
		SetROI();
	}
}

4.调整相框厚度

代码如下(示例):

void TrackbarRect(int, void*)
{
	if (!g_roiImg.data)
	{
		return;
	}

	// 绘制一个矩形,当做相框
	int iPosX = (g_vagueBgImg.cols - g_beautyFgImg.cols) / 2 - g_iRectValue / 2;
	int iPosY = (g_vagueBgImg.rows - g_beautyFgImg.rows) / 2 - g_iRectValue / 2;
	int iWidth = g_beautyFgImg.cols + g_iRectValue;
	int iHeight = g_beautyFgImg.rows + g_iRectValue;
	Rect rect(iPosX, iPosY, iWidth, iHeight);
	Scalar color(255, 255, 255);
	g_rectImg = g_roiImg.clone();
	rectangle(g_rectImg, rect, color, g_iRectValue);

	// 调整颜色
	TrackbarBright(g_iBrightValue, 0);
}

5.调整图片亮度

代码如下(示例):

void TrackbarBright(int, void*)
{
	if (!g_rectImg.data)
	{
		cout << "g_rectImg is empty" << endl;
		return;
	}
	int iRows = g_rectImg.rows;
	int iCols = g_rectImg.cols;
	Mat tmpImg = Mat::zeros(g_rectImg.size(), g_rectImg.type());
	float fAlpha = 0.1 + (float)g_iBrightValue / 10.0;
	float fBeta = 30; // 增益变量

	for (int i = 0; i < iRows; i++)
	{
		for (int j = 0; j < iCols; j++)
		{
			if (g_rectImg.channels() == 1)
			{
				float f = g_rectImg.at<uchar>(i, j);
				tmpImg.at<uchar>(i, j) = saturate_cast<uchar>(f * fAlpha + fBeta);
			}
			else if (g_rectImg.channels() == 3)
			{
				float fGreen = g_rectImg.at<Vec3b>(i, j)[0];
				float fBlue = g_rectImg.at<Vec3b>(i, j)[1];
				float fRed = g_rectImg.at<Vec3b>(i, j)[2];

				tmpImg.at<Vec3b>(i, j)[0] = saturate_cast<uchar>(fGreen * fAlpha + fBeta);
				tmpImg.at<Vec3b>(i, j)[1] = saturate_cast<uchar>(fBlue * fAlpha + fBeta);
				tmpImg.at<Vec3b>(i, j)[2] = saturate_cast<uchar>(fRed * fAlpha + fBeta);
			}
		}
	}

	// 保存调整亮度后的背景图
	g_brightImg = tmpImg.clone();

	imshow(g_szOutputWin, g_brightImg);
}

6.将美颜前景贴到模糊背景

代码如下(示例):

void SetROI(void)
{
	// 设定ROI区域
	int iPosX = (g_vagueBgImg.cols - g_beautyFgImg.cols) / 2;
	int iPosY = (g_vagueBgImg.rows - g_beautyFgImg.rows) / 2;
	g_roiImg = g_vagueBgImg.clone();
	Mat imageROI = g_roiImg(Rect(iPosX, iPosY, g_beautyFgImg.cols, g_beautyFgImg.rows));
	// 加载掩模(必须是灰度图)
	Mat mask;
	cvtColor(g_beautyFgImg, mask, COLOR_BGR2GRAY);
	g_beautyFgImg.copyTo(imageROI, mask);

	TrackbarRect(g_iRectValue, 0);
}


总结

该项目绝大部分API都是用到之前学过的,因为对API了解不是很深,写的有点乱;
如果只是单纯的熟悉某个API,那也太无趣了,所以结合PS的部分操作,做了一个实战小项目,虽然做完了,但是和预想的差太多了😥,等到后面基础扎实了,再完善做个效果好的

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐