任意图片碎片化生成效果自动实现代码

88 篇文章 4 订阅
5 篇文章 0 订阅

首先展示一下效果,这里是原图,二次元图片效果更加。

接下来是实现效果,生成avi文件,我这里为了方便显示使用gif动画。

该实现的核心代码为:

	// TODO:  在此添加命令处理程序代码
#ifdef NEED_DIR
	CString strDir;
	GetDlgItemText(IDC_EDIT_DIR, strDir);

	if (!strDir.GetLength())
	{
		strDir = CMfcStrFile::BrowseDir();
		if (strDir.GetLength() > 0)
		{
			SetDlgItemText(IDC_EDIT_DIR, strDir);
		}
		else
		{
			return;
		}
	}
	_tstring sDir = CMfcStrFile::CString2string(strDir);
	m_cfg.vDirPaths.clear();
	m_cfg.vDirPaths.push_back(sDir);
#endif // NEED_DIR

#ifdef NEED_FILE
	CString strFile;
	GetDlgItemText(IDC_EDIT_FILE, strFile);
	if (!strFile.GetLength())
	{
		strFile = CMfcStrFile::OpenFile();
		if (strFile.GetLength() > 0)
		{
			SetDlgItemText(IDC_EDIT_FILE, strFile);
		}
		else
		{
			return;
		}
	}
	_tstring sFile = CMfcStrFile::CString2string(strFile);
	m_cfg.vFilePaths.clear();
	m_cfg.vFilePaths.push_back(sFile);
#endif // NEED_FILE

	//开始显示进度
	CTaskBarProgress tbp(m_hWnd);
	CProgressInterface* ppi = &tbp;
	ppi->Start();
	CElapsedTime et;
	
	//记录日志
	CLOG::Out("start task!");
	//记录耗时
	et.Begin();

	/*********************************这里增加主程序 开始***************************************/
	ppi->OutputInfo("something write here!");

	std::string sFilePath = CStdStr::ws2s(CMfcStrFile::CString2string(strFile));
	cv::Mat mSrcBGR = cv::imread(sFilePath.c_str());
	if (!mSrcBGR.data)
		return;

	//是否需要显示或者保存中间结果
	int nWinWidth = mSrcBGR.cols;
	int nWinHeight = mSrcBGR.rows;

	//屏幕边缘保留像素
	int nReserved = 40;
	int cx = GetSystemMetrics(SM_CXFULLSCREEN) - nReserved;
	int cy = GetSystemMetrics(SM_CYFULLSCREEN) - nReserved;

	if (nWinWidth > cx || nWinHeight > cy)
	{
		double dProp = MIN((double)cx / nWinWidth, (double)cy /nWinHeight);
		nWinWidth = int(dProp * nWinWidth + 0.5);
		nWinHeight = int(dProp * nWinHeight + 0.5);
		cv::resize(mSrcBGR, mSrcBGR, cv::Size(nWinWidth, nWinHeight));
	}

	double dCannyThresh1 = GetDlgItemInt(IDC_EDIT_CANNYTHRESH1);
	double dCannyThresh2 = GetDlgItemInt(IDC_EDIT_CANNYTHRESH2);
	int nGapTime = GetDlgItemInt(IDC_EDIT_GAPTIME);

	if (nGapTime < 0)
	{
		nGapTime = 500;
		SetDlgItemText(IDC_EDIT_GAPTIME, _T("500"));
	}

	//灰度化,滤波,Canny边缘检测
	Mat imageGray;
	cvtColor(mSrcBGR, imageGray, CV_BGR2GRAY);//灰度转换
	GaussianBlur(imageGray, imageGray, Size(5, 5), 2);   //高斯滤波

	if (dCannyThresh1 < 0 || dCannyThresh2 < 0)
	{
		AutoCanny(imageGray, imageGray, dCannyThresh1, dCannyThresh2);
	}
	else
	{
		if (dCannyThresh1 < 1.0)
		{
			dCannyThresh1 = 100.0;
			SetDlgItemText(IDC_EDIT_CANNYTHRESH1, _T("100"));
		}

		if (dCannyThresh2 < 1.0)
		{
			dCannyThresh2 = 200.0;
			SetDlgItemText(IDC_EDIT_CANNYTHRESH2, _T("200"));
		}
		cv::Canny(imageGray, imageGray, dCannyThresh1, dCannyThresh2);
	}

	//查找轮廓
	vector<vector<Point>> contours;
	vector<Vec4i> hierarchy;
	findContours(imageGray, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point());

	cv::Mat mCanvas = mSrcBGR.clone();
	for (int i = 0; i < contours.size(); ++i)
	{
		cv::drawContours(mCanvas, contours, i, cv::Scalar(0, 255, 0));
	}

	if (hierarchy.size() == 0)
	{
		//可能检测不到轮廓
		return;
	}

	Mat marks(mSrcBGR.size(), CV_32S);   //Opencv分水岭第二个矩阵参数
	marks = Scalar::all(0);
	int index = 0;
	int compCount = 0;
	for (; index >= 0; index = hierarchy[index][0], compCount++)
	{
		//对marks进行标记,对不同区域的轮廓进行编号,相当于设置注水点,有多少轮廓,就有多少注水点
		drawContours(marks, contours, index, Scalar::all(compCount + 1), 1, 8, hierarchy);
	}

	//末尾的图像需要保持5秒
	compCount += 5 * 1000 / nGapTime;
	int nSeconds = compCount * nGapTime /1000 ;
	int nMinutes = nSeconds / 60;
	nSeconds = nSeconds % 60;

	CString strTipPre;
	strTipPre.Format(_T("预计持续时间 %d分%d秒!是否继续?"), nMinutes, nSeconds);

	if (MessageBox(strTipPre, _T("提示"), MB_YESNO) == IDNO)
	{
		ppi->End();
		return;
	}

	watershed(mSrcBGR, marks);

	//显示每一个区域
	cv::Mat mMask, mCurArea(mSrcBGR.size(), CV_8UC3, cv::Scalar(255.0, 255.0, 255.0));
	cv::imshow("mCurArea", mCurArea);
	cv::moveWindow("mCurArea", cx / 2 - nWinWidth / 2, cy / 2 - nWinHeight / 2);

	double r = 1000.0 / nGapTime;
	//获得帧的宽高
	Size S(mSrcBGR.cols, mSrcBGR.rows);
	std::string strSavePath = CStdStr::ws2s(CStdStr::ReplaceSuffix(sFile, _T(".avi")));
	VideoWriter writer(strSavePath.c_str(), -1, r, S);
	cv::Mat frame, output;

	for (int i = 0; i < compCount; i++)
	{
		cv::inRange(marks, i + 1, i + 1, mMask);

		//膨胀避免缝隙
		int an = 1;
		cv::Mat element = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(an * 2 + 1, an * 2 + 1), cv::Point(an, an));
		cv::dilate(mMask, mMask, element);

		mSrcBGR.copyTo(mCurArea, mMask);
		cv::imshow("mCurArea", mCurArea);
		writer << mCurArea;
		cv::waitKey(10);
	}

	writer.release();
	/*********************************这里增加主程序 结束***************************************/

	//结束耗时
	int nMin = 0, nSecond = 0, nMilliSecond = 0;
	et.End(nMin, nSecond, nMilliSecond);
	//结束日志
	CLOG::Out("end task!");
	CLOG::Out(_T("This task costs %d min %d second %d millisecond!"), nMin, nSecond, nMilliSecond);
	CLOG::End();

	//结束进度显示
	ppi->End();
	FlashWindow(TRUE);
	WriteIniFile(GetIniPath(), m_cfg);

	CString strTips;
	strTips.Format(_T("本次耗时 %d分%d秒%d毫秒!"), nMin, nSecond, nMilliSecond);
	AfxMessageBox(strTips);

	CDialogEx::OnOK();
}

_tstring CDllTestorDlg::GetIniPath(const TCHAR* szFileExt /*= _T(".ini")*/)
{
	TCHAR chpath[MAX_PATH];
	GetModuleFileName(NULL, chpath, sizeof(chpath));

	_tstring strModulePath = CMfcStrFile::CString2string(chpath);
	_tstring strIniPath = CStdStr::ReplaceSuffix(strModulePath, szFileExt);

	return strIniPath;

这样就可以对于任意图片实现该效果了,有点类似于看一幅画完成的过程,当然了,仅供娱乐。

更多的交流,欢迎留言。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值