最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++實(shí)現(xiàn)PatchMatch圖像修復(fù)算法

 更新時(shí)間:2021年04月21日 17:14:51   作者:周旋_  
這篇文章主要介紹了C++實(shí)現(xiàn)PatchMatch圖像修復(fù)算法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

PatchMatch算法出自Barnes的論文

PatchMatch: A Randomized Correspondence Algorithm for Structural Image Editing

PatchMatch 算法就是一個(gè)找近似最近鄰(Approximate Nearest neigbhor)的方法,要比其他ANN算法快上10倍+。

將下面的圖理解了,就基本理解了整個(gè)算法。

在這里插入圖片描述

看上圖時(shí),我們以藍(lán)色為主顏色。A代表原圖像,矩形框代表待修復(fù)的patch塊,要修復(fù)patch_A塊就需要在B(也是原圖)中搜索一個(gè)最合適的塊patch_B,而從patch_A到patch_B的偏移量,就是上圖箭頭,也就是offset。

藍(lán)色為主patch塊,紅色是藍(lán)色向左移一個(gè)像素,綠色是藍(lán)色向上移一個(gè)像素。

上圖 (a):隨機(jī)初始化 (b):傳播 ©:隨機(jī)擾動(dòng)搜索

PatchMatch 的核心思想是利用圖像的連續(xù)性(consistence), 一個(gè)圖像A的patch_A(藍(lán)色)附近的Patch塊(紅色綠色)的最近鄰(B中的紅色綠色框)最有可能出現(xiàn)在Patch_A的最近鄰(B中的藍(lán)色框)附近,利用這種圖像的連續(xù)性大量減少搜索的范圍,通過(guò)迭代的方式保證大多數(shù)點(diǎn)能盡快收斂。

PatchMatch算法是對(duì)所有待修復(fù)像素迭代修復(fù)的,而不是像Criminisi或FMM算法對(duì)待修復(fù)區(qū)域像素優(yōu)先級(jí)排序后進(jìn)行漸進(jìn)修復(fù)的。

來(lái)看算法步驟:

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-nffFeKnG-1618805820395)(D:\微信公眾號(hào)圖文\視覺\手撕算法\4月圖像修復(fù)\PatchMatch算法\截圖00.jpg)]

首先是建立圖像的下采樣金字塔模型,代碼中設(shè)定為五層,建立模型后

對(duì)A的待修復(fù)區(qū)域每個(gè)patch塊隨機(jī)在B已知區(qū)域中匹配一個(gè)patch塊,即初始化偏置地圖(上圖a步驟)。

/*********************************
函數(shù)聲明:初始化偏置圖像
參數(shù):NONE
注釋:NONE
測(cè)試:NONE
**********************************/
void PatchMatch::InitOff(Mat Mask, Mat &Off)
{
	//為方便起見,將所有的都附上,要求不能賦值到非搜索區(qū)域
	//初始化格式
	Off = Mat(Mask.size(), CV_32FC2, Scalar::all(0));//2維無(wú)符號(hào)32位精度浮點(diǎn)數(shù)

	for (int i = 0; i < Mask.rows; i++)
	{
		for (int j = 0; j < Mask.cols; j++)
		{
			//不考慮search區(qū)域,沒有破損,他們的最佳偏移向量當(dāng)然是0,自己
			if (Mask.at<uchar>(i, j) == search)
			{
				Off.at<Vec2f>(i, j)[0] = 0;  //<Vec2f> 向量,2維,浮點(diǎn)數(shù)
				Off.at<Vec2f>(i, j)[1] = 0;
			}
			else//處理hole,采用隨機(jī)偏置  
			{
				//先初始化2個(gè)偏置數(shù)r_col,r_row
				int r_col = rand() % Mask.cols; //rand()產(chǎn)生隨機(jī)數(shù),主要是產(chǎn)生一個(gè)偏置的初始值
				int r_row = rand() % Mask.rows;
				r_col = r_col + j < Mask.cols ? r_col : r_col - Mask.cols;//邊界檢測(cè)
				r_row = r_row + i < Mask.rows ? r_row : r_row - Mask.rows;

				//為什么要有這個(gè)循環(huán)?因?yàn)橐淮蔚碾S機(jī)賦值,很可能會(huì)出現(xiàn)偏置后的塊跑到破損區(qū)域,或者是超出限定搜索框的邊界
				while (
					!(Mask.at<uchar>(r_row + i, r_col + j) == search	//這里加上I,j,是因?yàn)樗茿投影到B中的搜索偏置
						&& abs(r_row) < searchrowratio*Mask.rows))	//searchrowratio=0.5,搜索的時(shí)候,確保r_row偏置不會(huì)太遠(yuǎn),一定是在原圖像的大小里	
				{
					r_col = rand() % Mask.cols;
					r_row = rand() % Mask.rows;

					//邊界檢測(cè)
					r_col = r_col + j < Mask.cols ? r_col : r_col - Mask.cols;
					r_row = r_row + i < Mask.rows ? r_row : r_row - Mask.rows;
				}

				//賦偏置值
				Off.at<Vec2f>(i, j)[0] = r_row;
				Off.at<Vec2f>(i, j)[1] = r_col;
			}
		}
	}
}

之后從低分辨率開始,對(duì)于每一層金字塔模型進(jìn)行迭代:

每一次迭代都會(huì)遍歷原圖A待修復(fù)區(qū)域所有像素。當(dāng)遍歷到當(dāng)前像素時(shí),執(zhí)行下面的步驟來(lái)進(jìn)行修復(fù):

步驟一:傳播(圖中b步驟)

傳播會(huì)計(jì)算原圖A當(dāng)前像素塊patch_A(藍(lán)色)對(duì)應(yīng)的B中的patch_B_1,patch_A上方(綠色)(奇數(shù)次迭代為下方)對(duì)應(yīng)的B中的patch_B_2,patch_A左側(cè)(紅色)(奇數(shù)次迭代為右側(cè))對(duì)應(yīng)的B中的patch_B_3這三個(gè)patch塊中與patch_A相似度最高的patch塊。

計(jì)算相似度函數(shù)為

//以塊為單位,用所有像素點(diǎn)的相同顏色通道的差平方來(lái)簡(jiǎn)單判斷相似度
float PatchMatch::Distance(Mat Dst, Mat Src)
{
	float distance = 0;

	for (int i = 0; i < Dst.rows; i++)
	{
		for (int j = 0; j < Dst.cols; j++)
		{
			for (int k = 0; k < 3; k++)//K=3個(gè)顏色通道
			{
				int tem = Src.at < Vec3b >(i, j)[k] - Dst.at < Vec3b >(i, j)[k];
				distance += tem * tem;//差平方
			}
		}
	}

	return distance;
}

傳播函數(shù):

//迭代第一步:傳播
//(now_row, now_col):patch里的像素
//odd:當(dāng)前迭代次
void PatchMatch::Propagation(Mat Dst, Mat Src, Mat Mask, Mat &Off, int row, int col,int odd)
{
	Mat DstPatch = GetPatch(Dst, row, col);//獲取長(zhǎng)度為 patchsize = 3 的邊界框, (row, col)代表的是中心像素點(diǎn)坐標(biāo)

	if (odd % 2 == 0)//偶次迭代
	{
		//提取(row, col)的match塊
		Mat SrcPatch = GetPatch(Src, row + Off.at < Vec2f >(row, col)[0],
			col + Off.at < Vec2f >(row, col)[1]);

		//提取(row, col-1)的match塊
		Mat LSrcPatch = GetPatch(Src, row + Off.at < Vec2f >(row, col - 1)[0],
			col - 1 + Off.at < Vec2f >(row, col - 1)[1]);

		//提取(row-1, col)的match塊
		Mat USrcPatch = GetPatch(Src,
			row - 1 + Off.at < Vec2f >(row - 1, col)[0],
			col + Off.at < Vec2f >(row - 1, col)[1]);

		//返回上面4個(gè)塊最相似的塊的代表數(shù)字,用于switch判斷
		int location = GetMinPatch1(DstPatch, SrcPatch, LSrcPatch, USrcPatch);

		//利用上面的信息更新像素點(diǎn)的偏置地圖
		switch (location)
		{
			//若是1則不更新
		case 2:
			Off.at < Vec2f >(row, col)[0] = Off.at < Vec2f >(row, col - 1)[0];
			Off.at < Vec2f >(row, col)[1] = Off.at < Vec2f >(row, col - 1)[1] - 1;
			break;
		case 3:
			Off.at < Vec2f >(row, col)[0] = Off.at < Vec2f >(row - 1, col)[0] - 1;
			Off.at < Vec2f >(row, col)[1] = Off.at < Vec2f >(row - 1, col)[1];
			break;
		}
	}

	else//奇數(shù)次迭代
	{
		Mat SrcPatch = GetPatch(Src, row + Off.at < Vec2f >(row, col)[0],
			col + Off.at < Vec2f >(row, col)[1]);
		Mat RSrcPatch = GetPatch(Src, row + Off.at < Vec2f >(row, col + 1)[0],
			col + 1 + Off.at < Vec2f >(row, col + 1)[1]);
		Mat DSrcPatch = GetPatch(Src,
			row + 1 + Off.at < Vec2f >(row + 1, col)[0],
			col + Off.at < Vec2f >(row + 1, col)[1]);

		int location = GetMinPatch1(DstPatch, SrcPatch, RSrcPatch, DSrcPatch);
		switch (location)
		{
		case 2:
			Off.at < Vec2f >(row, col)[0] = Off.at < Vec2f >(row, col + 1)[0];
			Off.at < Vec2f >(row, col)[1] = Off.at < Vec2f
			>(row, col + 1)[1] + 1;
			break;
		case 3:
			Off.at < Vec2f >(row, col)[0] = Off.at < Vec2f
			>(row + 1, col)[0] + 1;
			Off.at < Vec2f >(row, col)[1] = Off.at < Vec2f >(row + 1, col)[1];
			break;
		}
	}
}

步驟二:隨機(jī)擾動(dòng)搜索(圖中c步驟)

為了避免陷入局部極值,再額外再隨機(jī)生成幾個(gè)patch位置作為候選patch塊,若小于當(dāng)前patch,則更新。

隨機(jī)擾動(dòng)會(huì)在原圖A中,以當(dāng)前像素為中心點(diǎn),初始半徑區(qū)域?yàn)槿珗D,在此區(qū)域內(nèi)隨機(jī)找尋patch塊并與patch_A原本對(duì)應(yīng)的B中的patch塊對(duì)比,若更相似則更新對(duì)應(yīng)關(guān)系offset,然后以新的patch_B為中心,半徑縮小一倍,繼續(xù)搜索,直到半徑縮小為1,更新完畢。

//迭代第二步:隨機(jī)搜索
//(row,col)=(now_row, now_col):修復(fù)patch里的像素
void PatchMatch::RandomSearch(Mat Dst, Mat Src, Mat Mask, Mat &Off, int row, int col)
{
	Mat DstPatch = GetPatch(Dst, row, col);//獲取修復(fù)基準(zhǔn)框,在框內(nèi)操作

	//迭代指數(shù)
	int attenuate = 0;

	while (true)
	{
		//獲取隨機(jī)參數(shù),在 [-1;1] 間
		float divcol = rand() % 2000 / 1000.0f - 1.0f;
		float divrow = rand() % 2000 / 1000.0f - 1.0f;

		//減小框大小的公式,𝑢_𝑖=𝑣_0+𝑤*𝛼^𝑖*𝑅_𝑖
		//行列分別處理,MaxWindow:原始框?qū)挾龋籨ivcol:隨機(jī)系數(shù);pow(A,B):A的B次方。隨迭代次數(shù)而變小的縮小系數(shù);RandomAttenuation=0.5;
		float veccol = MaxWindow * pow(RandomAttenuation, attenuate)* divcol;
		float vecrow = MaxWindow * pow(RandomAttenuation, attenuate)* divrow;

		float length = sqrt(veccol * veccol + vecrow * vecrow);
		//如果低于1個(gè)像素,沒有意義,直接結(jié)束整個(gè)循環(huán),對(duì)下一個(gè)像素處理
		if (length < 1)
			break;

		//x方向,前2項(xiàng)指向(row, col)的match塊,后面是公式的后一項(xiàng)
		int nowrow = row + Off.at < Vec2f >(row, col)[0] + vecrow;
		//y方向
		int nowcol = col + Off.at < Vec2f >(row, col)[1] + veccol;

		//判斷隨機(jī)搜索的patch不越界,在search內(nèi)
		if (nowcol >= 0 && nowcol <= Off.cols - 1 && nowrow >= 0
			&& nowrow <= Off.rows - 1
			&& Mask.at < uchar >(nowrow, nowcol) == search
			&& abs(nowrow - row) < searchrowratio * Mask.rows)//abs:絕對(duì)值
		{
			//取出原來(lái)的match塊
			Mat SrcPatch1 = GetPatch(Src, Off.at < Vec2f >(row, col)[0] + row,
				Off.at < Vec2f >(row, col)[1] + col);
			//取出現(xiàn)在的隨機(jī)match塊
			Mat SrcPatch2 = GetPatch(Src, nowrow, nowcol);

			//對(duì)比相似性,找出最好的塊
			int location = GetMinPatch2(DstPatch, SrcPatch1, SrcPatch2);

			//結(jié)合最好的相似塊給像素新的偏置值
			switch (location)
			{
			case 2:
				Off.at < Vec2f >(row, col)[1] = nowcol - col;
				Off.at < Vec2f >(row, col)[0] = nowrow - row;
				break;
			}
		}

		//迭代指數(shù)增加
		attenuate++;
	}
}

經(jīng)過(guò)該兩個(gè)步驟,本次迭代完畢。

當(dāng)最終迭代完成后,就完成了整個(gè)修復(fù)過(guò)程。

算法效果

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

可以看到效果還是可以的,速度也比較快。

到此這篇關(guān)于C++實(shí)現(xiàn)PatchMatch圖像修復(fù)算法的文章就介紹到這了,更多相關(guān)C++ PatchMatch圖像修復(fù)算法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++解決回調(diào)地獄問(wèn)題的方法小結(jié)

    C++解決回調(diào)地獄問(wèn)題的方法小結(jié)

    “地獄回調(diào)”(Callback Hell)是指在編程中使用過(guò)多嵌套回調(diào)函數(shù),導(dǎo)致代碼難以閱讀和維護(hù),本文給大家介紹了C++解決回調(diào)地獄問(wèn)題的方法小結(jié),文中有相關(guān)的代碼示例供大家參考,需要的朋友可以參考下
    2024-07-07
  • 二叉樹中葉子節(jié)點(diǎn)的統(tǒng)計(jì)和樹高問(wèn)題

    二叉樹中葉子節(jié)點(diǎn)的統(tǒng)計(jì)和樹高問(wèn)題

    今天小編就為大家分享一篇關(guān)于二叉樹中葉子節(jié)點(diǎn)的統(tǒng)計(jì)和樹高問(wèn)題,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-03-03
  • C++超集C++/CLI模塊的基本用法

    C++超集C++/CLI模塊的基本用法

    這篇文章介紹了C++超集C++/CLI模塊的基本用法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • C語(yǔ)言中遞歸和排列組合詳解

    C語(yǔ)言中遞歸和排列組合詳解

    大家好,本篇文章主要講的是C語(yǔ)言中遞歸和排列組合詳解,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽
    2022-01-01
  • C/C++通過(guò)SQLite SDK實(shí)現(xiàn)數(shù)據(jù)庫(kù)增刪改查操作

    C/C++通過(guò)SQLite SDK實(shí)現(xiàn)數(shù)據(jù)庫(kù)增刪改查操作

    SQLite,作為一款嵌入式關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng),一直以其輕量級(jí)、零配置以及跨平臺(tái)等特性而備受青睞,本文主要介紹了C++如何通過(guò)SQLite SDK實(shí)現(xiàn)數(shù)據(jù)庫(kù)增刪改查操作,感興趣的可以了解下
    2023-11-11
  • C語(yǔ)言中的字符型數(shù)據(jù)與ASCII碼表

    C語(yǔ)言中的字符型數(shù)據(jù)與ASCII碼表

    這篇文章主要介紹了C語(yǔ)言中的字符型數(shù)據(jù)與ASCII碼表,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • 深入理解C/C++中的寫時(shí)拷貝

    深入理解C/C++中的寫時(shí)拷貝

    這篇文章主要給大家介紹了C/C++中寫時(shí)拷貝的相關(guān)資料,所謂寫時(shí)拷貝也就是拖延版的深拷貝,下面文章中介紹的非常清楚,需要的朋友可以參考學(xué)習(xí),下面來(lái)一起看看吧。
    2017-03-03
  • C++實(shí)現(xiàn)矩陣對(duì)稱正交化的示例代碼

    C++實(shí)現(xiàn)矩陣對(duì)稱正交化的示例代碼

    這篇文章主要介紹了C++實(shí)現(xiàn)矩陣對(duì)稱正交化,分為python代碼和C++的eigen庫(kù)實(shí)現(xiàn)代碼,代碼簡(jiǎn)單易懂,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-09-09
  • C++類URL編碼和解碼使用技巧

    C++類URL編碼和解碼使用技巧

    在項(xiàng)目開發(fā)過(guò)程中,經(jīng)常會(huì)使用到c++ 的url編碼和解碼,本文將以此問(wèn)題詳細(xì)介紹使用技巧,需要的朋友可以參考下
    2012-11-11
  • C++鏈表類的封裝詳情介紹

    C++鏈表類的封裝詳情介紹

    這篇文章主要介紹了C++鏈表類的封裝,文章基于C++的相關(guān)資料展開主題的詳細(xì)內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-04-04

最新評(píng)論

昭通市| 开化县| 江源县| 通化市| 盘锦市| 新余市| 始兴县| 祁阳县| 崇州市| 富源县| 布尔津县| 阿坝县| 黔江区| 孟州市| 启东市| 增城市| 启东市| 萨迦县| 柳江县| 常山县| 浠水县| 肃宁县| 普定县| 灌南县| 桦南县| 和静县| 土默特左旗| 广宗县| 乐清市| 中宁县| 茂名市| 定日县| 大名县| 柘荣县| 寿光市| 南投市| 平阳县| 宁波市| 云龙县| 马山县| 揭东县|