返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >使用C++如何实现PatchMatch图像修复算法
  • 903
分享到

使用C++如何实现PatchMatch图像修复算法

2023-06-14 18:06:28 903人浏览 薄情痞子
摘要

今天小编给大家分享的是使用c++如何实现PatchMatch图像修复算法,相信很多人都不太了解,为了让大家更加了解,所以给大家总结了以下内容,一起往下看吧。一定会有所收获的哦。PatchMatch算法出自Barnes的论文PatchMatc

今天小编给大家分享的是使用c++如何实现PatchMatch图像修复算法,相信很多人都不太了解,为了让大家更加了解,所以给大家总结了以下内容,一起往下看吧。一定会有所收获的哦。

PatchMatch算法出自Barnes的论文

PatchMatch: A Randomized Correspondence AlGorithm for Structural Image Editing

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

将下面的图理解了,就基本理解了整个算法。

使用C++如何实现PatchMatch图像修复算法

看上图时,我们以蓝色为主颜色。A代表原图像,矩形框代表待修复的patch块,要修复patch_A块就需要在B(也是原图)中搜索一个最合适的块patch_B,而从patch_A到patch_B的偏移量,就是上图箭头,也就是offset。

蓝色为主patch块,红色是蓝色向左移一个像素,绿色是蓝色向上移一个像素。

上图 (a):随机初始化 (b):传播 ©:随机扰动搜索

PatchMatch 的核心思想是利用图像的连续性(consistence), 一个图像A的patch_A(蓝色)附近的Patch块(红色绿色)的最近邻(B中的红色绿色框)最有可能出现在Patch_A的最近邻(B中的蓝色框)附近,利用这种图像的连续性大量减少搜索的范围,通过迭代的方式保证大多数点能尽快收敛。

PatchMatch算法是对所有待修复像素迭代修复的,而不是像Criminisi或FMM算法对待修复区域像素优先级排序后进行渐进修复的。

来看算法步骤:

使用C++如何实现PatchMatch图像修复算法

首先是建立图像的下采样金字塔模型,代码中设定为五层,建立模型后

对A的待修复区域每个patch块随机在B已知区域中匹配一个patch块,即初始化偏置地图(上图a步骤)。

void PatchMatch::InitOff(Mat Mask, Mat &Off){//为方便起见,将所有的都附上,要求不能赋值到非搜索区域//初始化格式Off = Mat(Mask.size(), CV_32FC2, Scalar::all(0));//2维无符号32位精度浮点数for (int i = 0; i < Mask.rows; i++){for (int j = 0; j < Mask.cols; j++){//不考虑search区域,没有破损,他们的最佳偏移向量当然是0,自己if (Mask.at<uchar>(i, j) == search){Off.at<Vec2f>(i, j)[0] = 0;  //<Vec2f> 向量,2维,浮点数Off.at<Vec2f>(i, j)[1] = 0;}else//处理hole,采用随机偏置  {//先初始化2个偏置数r_col,r_rowint r_col = rand() % Mask.cols; //rand()产生随机数,主要是产生一个偏置的初始值int r_row = rand() % Mask.rows;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;//为什么要有这个循环?因为一次的随机赋值,很可能会出现偏置后的块跑到破损区域,或者是超出限定搜索框的边界while (!(Mask.at<uchar>(r_row + i, r_col + j) == search//这里加上I,j,是因为他是A投影到B中的搜索偏置&& abs(r_row) < searchrowratio*Mask.rows))//searchrowratio=0.5,搜索的时候,确保r_row偏置不会太远,一定是在原图像的大小里{r_col = rand() % Mask.cols;r_row = rand() % Mask.rows;//边界检测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;}}}}

之后从低分辨率开始,对于每一层金字塔模型进行迭代:

每一次迭代都会遍历原图A待修复区域所有像素。当遍历到当前像素时,执行下面的步骤来进行修复:

步骤一:传播(图中b步骤)

传播会计算原图A当前像素块patch_A(蓝色)对应的B中的patch_B_1,patch_A上方(绿色)(奇数次迭代为下方)对应的B中的patch_B_2,patch_A左侧(红色)(奇数次迭代为右侧)对应的B中的patch_B_3这三个patch块中与patch_A相似度最高的patch块。

计算相似度函数为

//以块为单位,用所有像素点的相同颜色通道的差平方来简单判断相似度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个颜色通道{int tem = Src.at < Vec3b >(i, j)[k] - Dst.at < Vec3b >(i, j)[k];distance += tem * tem;//差平方}}}return distance;}

传播函数:

//迭代第一步:传播//(now_row, now_col):patch里的像素//odd:当前迭代次void PatchMatch::Propagation(Mat Dst, Mat Src, Mat Mask, Mat &Off, int row, int col,int odd){Mat DstPatch = GetPatch(Dst, row, col);//获取长度为 patchsize = 3 的边界框, (row, col)代表的是中心像素点坐标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个块最相似的块的代表数字,用于switch判断int location = GetMinPatch2(DstPatch, SrcPatch, LSrcPatch, USrcPatch);//利用上面的信息更新像素点的偏置地图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//奇数次迭代{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 = GetMinPatch2(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;}}}

步骤二:随机扰动搜索(图中c步骤)

为了避免陷入局部极值,再额外再随机生成几个patch位置作为候选patch块,若小于当前patch,则更新。

随机扰动会在原图A中,以当前像素为中心点,初始半径区域为全图,在此区域内随机找寻patch块并与patch_A原本对应的B中的patch块对比,若更相似则更新对应关系offset,然后以新的patch_B为中心,半径缩小一倍,继续搜索,直到半径缩小为1,更新完毕。

//迭代第二步:随机搜索//(row,col)=(now_row, now_col):修复patch里的像素void PatchMatch::RandomSearch(Mat Dst, Mat Src, Mat Mask, Mat &Off, int row, int col){Mat DstPatch = GetPatch(Dst, row, col);//获取修复基准框,在框内操作//迭代指数int attenuate = 0;while (true){//获取随机参数,在 [-1;1] 间float divcol = rand() % 2000 / 1000.0f - 1.0f;float divrow = rand() % 2000 / 1000.0f - 1.0f;//减小框大小的公式,?_?=?_0+?*?^?*?_?//行列分别处理,MaxWindow:原始框宽度;divcol:随机系数;pow(A,B):A的B次方。随迭代次数而变小的缩小系数;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个像素,没有意义,直接结束整个循环,对下一个像素处理if (length < 1)break;//x方向,前2项指向(row, col)的match块,后面是公式的后一项int nowrow = row + Off.at < Vec2f >(row, col)[0] + vecrow;//y方向int nowcol = col + Off.at < Vec2f >(row, col)[1] + veccol;//判断随机搜索的patch不越界,在search内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:绝对值{//取出原来的match块Mat SrcPatch2 = GetPatch(Src, Off.at < Vec2f >(row, col)[0] + row,Off.at < Vec2f >(row, col)[1] + col);//取出现在的随机match块Mat SrcPatch3 = GetPatch(Src, nowrow, nowcol);//对比相似性,找出最好的块int location = GetMinPatch3(DstPatch, SrcPatch2, SrcPatch3);//结合最好的相似块给像素新的偏置值switch (location){case 2:Off.at < Vec2f >(row, col)[1] = nowcol - col;Off.at < Vec2f >(row, col)[0] = nowrow - row;break;}}//迭代指数增加attenuate++;}}

经过该两个步骤,本次迭代完毕。

当最终迭代完成后,就完成了整个修复过程。

算法效果

使用C++如何实现PatchMatch图像修复算法
使用C++如何实现PatchMatch图像修复算法
使用C++如何实现PatchMatch图像修复算法

可以看到效果还是可以的,速度也比较快。

关于使用C++如何实现PatchMatch图像修复算法就分享到这里了,希望以上内容可以对大家有一定的参考价值,可以学以致用。如果喜欢本篇文章,不妨把它分享出去让更多的人看到。

--结束END--

本文标题: 使用C++如何实现PatchMatch图像修复算法

本文链接: https://lsjlt.com/news/274243.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 使用C++如何实现PatchMatch图像修复算法
    今天小编给大家分享的是使用C++如何实现PatchMatch图像修复算法,相信很多人都不太了解,为了让大家更加了解,所以给大家总结了以下内容,一起往下看吧。一定会有所收获的哦。PatchMatch算法出自Barnes的论文PatchMatc...
    99+
    2023-06-14
  • C++实现PatchMatch图像修复算法
    PatchMatch算法出自Barnes的论文 PatchMatch: A Randomized Correspondence Algorithm for Structural I...
    99+
    2024-04-02
  • C++ OpenCV如何实现图像修复功能
    本篇文章给大家分享的是有关C++ OpenCV如何实现图像修复功能,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。前言下面将使用OpenCV C++ 对有瑕疵的图像进行...
    99+
    2023-06-26
  • C++OpenCV实现图像修复功能
    目录前言一、OpenCV inpaint二、源码三、效果显示前言 本文将使用OpenCV C++ 对有瑕疵的图像进行修复。OpenCV 提供了inpaint API可进行图像修复。 ...
    99+
    2024-04-02
  • C++ OpenCV如何实现图像双三次插值算法
    本篇内容主要讲解“C++ OpenCV如何实现图像双三次插值算法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C++ OpenCV如何实现图像双三次插值算法”吧!一、图像双三...
    99+
    2023-06-21
  • OpenCV如何实现图像去噪算法
    今天小编给大家分享一下OpenCV如何实现图像去噪算法的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。一、函数参考1、Prim...
    99+
    2023-07-02
  • 如何使用Python实现图像融合及加法运算
    这篇文章主要介绍“如何使用Python实现图像融合及加法运算”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“如何使用Python实现图像融合及加法运算”文章能帮助大家解决问题。一.图像加法运算1.Nu...
    99+
    2023-06-30
  • OpenCV中图像如何实现分割与修复
    这篇文章给大家分享的是有关OpenCV中图像如何实现分割与修复的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。背景图像分割本质就是将前景目标从背景中分离出来。在当前的实际项目中,应用传统分割的并不多,大多是采用深度...
    99+
    2023-06-29
  • c语言图像识别算法怎么实现
    要实现图像识别算法,可以使用以下步骤: 数据预处理:首先,将图像转换为数字矩阵表示。可以使用图像处理库(例如OpenCV)读取图...
    99+
    2023-10-24
    c语言
  • C++ opencv如何利用grabCut算法实现抠图
    今天小编给大家分享一下C++ opencv如何利用grabCut算法实现抠图的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解...
    99+
    2023-06-30
  • 使用Python实现图像融合及加法运算
    目录一.图像加法运算1.Numpy库加法2.OpenCV加法运算二.图像融合三.图像类型转换一.图像加法运算 1.Numpy库加法 其运算方法是:目标图像 = 图像1 + 图像2,运...
    99+
    2024-04-02
  • Python中图像边缘检测算法如何实现
    这篇“Python中图像边缘检测算法如何实现”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Python中图像边缘检测算法如何...
    99+
    2023-06-30
  • 如何使用C/C++实现马踏棋盘算法
    这篇文章主要介绍如何使用C/C++实现马踏棋盘算法,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!具体内容如下问题描述:将马随机放在国际象棋的8&times;8棋盘Board[0~7][0~7]的某个方格中,马...
    99+
    2023-06-29
  • 如何使用OpenCV实现图像增强
    本篇内容介绍了“如何使用OpenCV实现图像增强”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!本期将介绍如何通过图像处理从低分辨率/模糊/低...
    99+
    2023-06-20
  • 如何使用Python实现图像识别?
            在当今的数字化时代,图像识别技术已经成为了人工智能领域中的一个热门话题。图像识别技术可以将数字图像转换为可供计算机程序理解的数据,并对图像内容进行分析和处理。Python是目前最受欢迎的编程语言之一,也是图像识别技术中最常用...
    99+
    2023-09-01
    python
  • C++中实现OpenCV图像分割与分水岭算法
    分水岭算法是一种图像区域分割法,在分割的过程中,它会把跟临近像素间的相似性作为重要的参考依据,从而将在空间位置上相近并且灰度值相近的像素点互相连接起来构成一个封闭的轮廓,封闭性是分水...
    99+
    2024-04-02
  • C++OpenCV实现图像双三次插值算法详解
    目录前言一、图像双三次插值算法原理二、C++ OpenCV代码1.计算权重矩阵2.遍历插值3. 测试及结果前言 近期在学习一些传统的图像处理算法,比如传统的图像插值算法等。传统的图像...
    99+
    2024-04-02
  • 如何使用纯CSS实现圆形图像?
    小编给大家分享一下如何使用纯CSS实现圆形图像?,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!   SS可以实现网页中的很多效...
    99+
    2024-04-02
  • Java如何使用Tess4J实现图像识别
    这篇文章主要为大家展示了“Java如何使用Tess4J实现图像识别”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Java如何使用Tess4J实现图像识别”这篇文章吧。Java Tess4J实现图...
    99+
    2023-06-25
  • 如何利用C++ OpenCV 实现从投影图像恢复仿射特性
    如何利用C++ OpenCV 实现从投影图像恢复仿射特性,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。原理我们通过相机拍摄的图片存在各种畸变,其中投影畸...
    99+
    2023-06-21
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作