作者:翟天保Steven
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处

一、关于图像修补

图像修补的目的是基于已有的图像信息或数据库内信息,对缺失区域进行合理地修复。在诸多领域如电影、摄像、医疗等行业,有广泛的应用。

传统上,图像修补由专业的修复师进行,修复师凭借自身丰富的工作经验和生活阅历,不仅能基于客观信息对图像缺失进行填充,更能进行主观创作,使得二次修复的图片更加生动形象。

但在日益智能化的今天,针对数字图像的修补工作逐渐由人工转向了自动化,这不仅节省了大量人工成本,而且计算机凭借优越的算法和庞大的数据库,对图像的修复效果更高效且优质。通过近几个月风风火火的chatGPT,相信大家也看到了AI的魅力,这是未来的大趋势不可逆。

针对图像修补,本文提出了一种基于等照度线和窗口匹配的图像修补算法,接下来将简单介绍下算法原理和流程,并展示相关的效果图。

二、算法原理和流程

对图像缺失部分进行填充,首先要确定填充哪些内容,谁优先填充谁最后填充;其次要判断用什么数据来填充,能使得填充后的结果更贴近真实,显得不违和。做到了这两点,图像修补工作基本就完成了。

2.1 优先级计算

我们先来讨论填充的优先级,如下图所示,图像白色部分是手动绘制的掩膜区域,该区域的真实信息被擦除了,我们现在要对其进行复原。

在图中红线部分就是等照线,该线的两侧往往有较大的数值差异,因此它也与黑线所示的梯度线呈垂直关系;当等照线与掩膜边界呈垂直时,此时等照线上的像素点特征是非常强烈且明显的,通俗的讲,被填充的点极大可能和它那条等照线上的点类似,沿着这个等照线绘制下去,就可以了。

那我们怎么判断当前点是不是处于与掩膜边界垂直的等照线上呢?可以通过掩膜边界(黑线)的法线和红色等照度线这两个向量判断。等照线与掩膜边界垂直时,那与掩膜边界的法线自然平行,此时两个向量点乘可以使得值最大,因此该值可以作为填补优先级评判的指标,定义为D(x,y)。

除此之外,我们还需要用到一个指标,叫可信度,定义为C(x,y),就是被填补像素所在窗口内,源数据的占比,加入窗口为7*7的尺寸,里面有31个源数据,18个代填补数据,那它的可信度也就是31/49。可信度越高的像素,说明窗口内缺失的数据越少,对它们填补更容易且贴实。

综上,代填补像素的优先级可以定义为P(x,y)=C(x,y)*D(x,y),当然也可以定义为别的,比如乘法变加法等等,大家可以自行发挥。

2.2 数据填充

确认好代填补像素的优先级后,我们对优先级最高的像素所在窗口进行填充,填充基于窗口匹配实现。

窗口匹配顾名思义就是从全图中寻找一个最像要填补的窗口的源数据窗口,把它粘过去即可。如下图所示,黑色窗口的实心部分是代填补窗口中的源数据,空心部分是代填补的数据。我们将黑色窗口实心部分和红色窗口实心部分进行三通道数据减法,对差值平方和累加取平均,可以得到一个匹配误差matchError,寻找全图最小的误差作为最小误差minError,此时对应的红色窗口就是匹配好的源数据。

但是,当出现两个同样的匹配误差后该怎么取舍呢?这时需要用到第二个匹配的指标——最小窗内方差minVarience。即对源数据中空心部分三通道数值求方差,数值减去平均值后平方和累加。方差低则说明数据平稳,不容易出现异常突兀的噪声数据,这样可以让填补的数据更贴实。

2.3 算法流程图

综上,该算法的流程图可简化为:

三、填补效果图

3.1 干涉条纹图填补视频

该案例特征是图像黑白色系相对稳定,近似区域多,因此修补效果也是最好的。

图像修补算法示例视频1

3.2 地图填补视频

该案例特征是图像分为极大区域,如海洋、雪山、陆地、森林,色系复杂,图像细节多且杂。对其修补效果也是相对好的,因为本身糅杂的颜色系统中适当混入一些不和谐因素,凭借肉眼较难准确识别。

图像修补算法示例视频2

3.3 花卉修补

该案例特征是图像色彩相对单调,花瓣区域纹理明显。这类图像色彩简单又不简单,颜色相近又各有区分,修补难度极大。经过图像修补后,可以发现花的边缘修补较成功,但是肉眼还是能看出内部区间存在一定的修补痕迹。

3.4 房屋修补

该案例特征是房屋颜色与天空接近,此时填补区域如果是屋顶瓦砖,便补的很好,因为纹理缘故,匹配的数据也是瓦砖。

但如果填补区域是屋顶侧面,则易出问题,若天空是蓝色还好,但恰巧天空也是棕黄色系,所以填补痕迹就突出了。

该案例也是很不好找,特地找出来做评估。感兴趣的伙伴可以优化窗口匹配函数,比如全局和局部结合匹配等等。

四、代码分享

main.cpp

#include "Inpaint.h"// 全局变量
int thickness = 5;
cv::Point sPoint(-1, -1);
cv::Mat image, mask;// 鼠标事件
static void onMouse(int event, int x, int y, int flags, void*){if (event == cv::EVENT_LBUTTONUP || !(flags & cv::EVENT_FLAG_LBUTTON))sPoint = cv::Point(-1, -1);else if (event == cv::EVENT_LBUTTONDOWN)sPoint = cv::Point(x, y);else if( event == cv::EVENT_MOUSEMOVE && (flags & cv::EVENT_FLAG_LBUTTON)){cv::Point ePoint(x,y);if( sPoint.x < 0 )sPoint = ePoint;cv::line( mask, sPoint, ePoint, cv::Scalar::all(255), thickness);cv::line( image, sPoint, ePoint, cv::Scalar::all(255), thickness);sPoint = ePoint;cv::imshow("image", image);}
}// 主函数
int main(){cv::Mat originalImage = cv::imread("6.jpg", 1);// 无输入图像if(!originalImage.data){cout << "Error unable to open input image" << endl;return 0;}// 拷贝图像image=originalImage.clone();mask = cv::Mat::zeros(image.size(), CV_8U);// 设置鼠标事件cv::namedWindow("image", 1);cv::imshow("image", image);cv::setMouseCallback("image", onMouse, 0);// 循环处理while(true){// 键盘事件char key = (char)cv::waitKey();// 按'b'跳出循环,结束程序if (key == 'b')break;// 按'r'恢复原始图像if (key == 'r'){mask = cv::Scalar::all(0);image = originalImage.clone();cv::imshow("image", image);}// 按'空格'执行算法if (key == ' '){int r = 3;InpaintAlgorithm *m_algorithm = new InpaintAlgorithm(image, mask, 2 * r + 1, TEMPLATE_MATCHING);m_algorithm->executeInpaint();cv::namedWindow("result");cv::imshow("result", m_algorithm->m_outputImage);}// 按'w'增加画笔厚度if (key == 'w') {thickness++;if (thickness > 20)thickness = 20;cout << "Thickness = " << thickness << endl;}// 按's'减少画笔厚度if (key == 's') {thickness--;if (thickness < 1)thickness = 1;cout << "Thickness = " << thickness << endl;}}return 0;
}

Inpaint.h

#ifndef INPAINT_H
#define INPAINT_H
#include <iostream>
#include "opencv2/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/photo/photo.hpp"using namespace std;
using namespace cv;// 填补策略
enum INPAINT_METHOD {TEMPLATE_MATCHING,                              // 模板匹配
};// 错误类型
enum ERROR_TYPE {ERROR_TYPE_OK,                                  // OKERROR_TYPE_INPUT,                             // 输入图像异常ERROR_TYPE_MASK,                               // 掩膜异常ERROR_TYPE_WINDOWSIZE,                           // 窗尺寸异常
};// 定义图像填补接口
class Inpaint
{
public:// 构造函数Inpaint(cv::Mat inputImage, cv::Mat mask, int windowSize);// 检查异常void checkError();// 执行virtual void execute() = 0;public:ERROR_TYPE errorType;                           // 错误码int m_windowSize = 9;                           // 窗尺寸cv::Mat m_inputImage;                           // 输入图像cv::Mat m_mask;                                  // 掩膜cv::Mat m_outputImage;                         // 输出图像
};// 实现具体策略-模板匹配
class TemplateMatching :public Inpaint
{
public:// 构造函数TemplateMatching(cv::Mat inputImage, cv::Mat mask, int windowSize);// 执行virtual void execute();private:// 初始化void init();// 检查是否存在未填补信息bool checkUnfilled();// 寻找目标位置集合void findTargetPoints();// 计算可信度void calcConfidence();// 获取优先级void getPriority();// 寻找最佳匹配void findBestMatch();// 更新图像void updateImage();private:int targetIndex;                             // 目标点序号cv::Point2i m_bestMatchUL;                      // 最佳匹配点左上角位置cv::Mat m_updatedImage;                        // 更新中的图像cv::Mat m_updatedMask;                         // 更新中的掩膜cv::Mat m_confidence;                          // 可信度cv::Mat m_oriSourceRegion;                    // 原始源位置cv::Mat m_sourceRegion;                         // 源位置cv::Mat m_targetRegion;                           // 目标位置cv::Mat m_gradientX;                         // 梯度Xcv::Mat m_gradientY;                          // 梯度Yvector<cv::Point2i> targetPoints;               // 目标位置点集合vector<pair<float, float>> normals;            // 法线集合
};// 应用类-图像修补算法调用
class InpaintAlgorithm
{
public:// 构造函数InpaintAlgorithm(cv::Mat inputImage, cv::Mat mask, int windowSize, INPAINT_METHOD method);// 析构函数~InpaintAlgorithm();// 设置修补策略void setInpaintAlgorithm(INPAINT_METHOD method);// 执行图像修补void executeInpaint();public:int m_windowSize;                            // 窗尺寸cv::Mat m_inputImage;                         // 输入图像cv::Mat m_mask;                                  // 掩膜cv::Mat m_outputImage;                         // 输出图像private:Inpaint* m_inpaint;                              // 图像填补类实例
};#endif

C++完整代码不免费分享,有意获取者可以私我。算法不是魔法,不能解决一切问题。该算法的核心逻辑可用于工程开发,但仍有许多需要结合实际完善的地方,不建议直接拷贝使用。

注意:当缺失的面积过大或者没有近似的窗口源数据时,填补效果会相对失真,这也是合理的。

基于等照度线和窗口匹配的图像修补算法相关推荐

  1. 基于颜色布局描述符(CLD)图像特征提取算法使用Python实现简单的人脸检测功能并使用PyQt5构建简单的功能界面(数字图像处理课程实验)

    文章目录 一.环境准备 二.数据集准备 三.项目结构 四.完整参考代码 imgCode/testUI3.py imgCode/test2.py 五.运行结果 测试一: 测试二 六.参考链接 一.环境准 ...

  2. 基于历史K线数据比较的量化选股方法及其系统分享

    第0章 引言 最近量化交易火起来了. 前段时间看了一本书<乌合之众>,讲的是大众心理学.其实股市的本质就是大众心理博弈,通过买卖行为对外表现出股价的涨跌,股价波动反映的是一段时间内股市中的 ...

  3. 基于FPGA的线阵CCD实时图像采集系统

    基于FPGA的线阵CCD实时图像采集系统 2015年微型机与应用第13期 作者:章金敏,张 菁,陈梦苇 2016/2/8 20:52:00 关键词: 实时采集 电荷耦合器件 现场可编程逻辑器件 信号处 ...

  4. grads 相关系数_基于小波变换的多聚焦图像融合算法

    引用本文 孟强强, 杨桄, 童涛, 张俭峰. 基于小波变换的多聚焦图像融合算法[J]. 国土资源遥感, 2014,26(2): 38-42 MENG Qiangqiang, YANG Guang, T ...

  5. 基于预训练模型 ERNIE 实现语义匹配

    基于预训练模型 ERNIE 实现语义匹配 本案例介绍 NLP 最基本的任务类型之一 -- 文本语义匹配,并且基于 PaddleNLP 使用百度开源的预训练模型 ERNIE1.0 为基础训练效果优异的语 ...

  6. CVPR 2020丨基于并行点检测和点匹配的单阶段实时HOI Detection方法

    本文转载自知乎,为商汤科技CVPR 2020最新论文解读. https://zhuanlan.zhihu.com/p/144238209 在CVPR2020上,商汤团队联合北京航空航天大学Colab( ...

  7. 基于PCL库的通过ICP匹配多幅点云方法

    基于PCL库的通过ICP匹配多幅点云方法 前言 Code Result 前言 PCL库中有很多配准的方式,主要都是基于ICP ICP算法最初由Besl和Mckey提出,是一种基于轮廓特征的点配准方法. ...

  8. SLAM--PL-SLAM中基于线特征的初始化方法(LSD算法,LBD描述子,计算R和t)

    SLAM中基于线特征的初始化方法 线特征的初始化 直线段检测算法---LSD:a Line Segment Detector 描述子---LBD:Line detection and descript ...

  9. k-d树和基于k-d树的特征点匹配

    k-d树 首先它是一颗树.然后是二叉树,再然后是一颗带权的二叉树. 每个树节点的权拥有多维信息. 建立一套规则对不同维度信息进行左右空间的划分,比如信息为二维坐标(x,y),我们规定冀奇数层节点的左子 ...

最新文章

  1. 如何提升 CSS 选择器的性能?
  2. C语言中的const,volatile与restrict的使用
  3. Java7中的switch支持String的实现细节
  4. 【源码品读】深入了解FeignContract协议解析过程
  5. React开发(213):React在 DevTools 中显示自定义名称
  6. STL 容器简介:C++ 容器:顺序性容器、关联式容器和容器适配器
  7. [*转*] 开发B2C电子商务系统(ASP.NET)--多年前的老文章
  8. 百度EasyDL深度学习实战营,免费教你转型AI工程师!
  9. 太棒了!PyTorch 1.7发布,支持CUDA 11、Windows分布式训练
  10. apache代理weblogic集群办法
  11. cms的html调用,工作笔记三,phpcms几中HTML标签的调用
  12. SW2017学习笔记(一)基本的工作界面及鼠标操作
  13. power query时间函数(思维导图)
  14. hive sql教程
  15. HTML+CSS大学生个人网站作业模板~黑色的html5个人博客网站模板整站下载
  16. Oracle查询排列组合,Oracle SQL排列组合之组合问题
  17. 在win10上安装oracle10g
  18. 多因子模型水平测试题试答(因子部分)
  19. 计算机用户身份识别,计算机用户身份识别装置及使用方法与流程
  20. Java实现 蓝桥杯 历届试题 城市建设

热门文章

  1. R语言:for循环使用小结
  2. Chrome扩展插件数次审核被拒的惨痛经历
  3. 逐浪软件智图->全网发布∞面向企业级的智能图库
  4. unity_EasyTouch
  5. ftrace stack trace
  6. HTTPS 为什么会出现 ?HTTPS 解决了 HTTP 的什么问题?HTTPS 和 HTTP 的关系是什么?TLS 和 SSL 是什么?
  7. 使用vs2010创建MFC工程后,vs2010的bug,不知道你们有没有
  8. pandas模块之SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame
  9. “工艺等于零 ”宝瓷林论当代茶器
  10. 独显+集显设置三个显示器输出,其中两个副屏输出相同