在图像算法的高层次处理中,有一类很典型的应用,就是图像修复算法。图像在采集、传输、预处理过程中,都可能会发生图像数据被修改、损失和缺失等问题(例如:部分图像内容被污染、雾霾等),另外,在实际室外拍照的时候,可能会将用户不想需要的对象(例如:路人甲等)也摄入照片影像中,需要将这多余图像内容去除。这一类的图像处理算法可以统称为 图像修复,对污染后的图像进行去噪、修补、变换等操作还原原始图像内容。在图像修复中最主要的一类处理就是 图像修补,就是将图像中一小块被污染的区域通过各种算法尽量还原成原始图像。

如果图像中需要修复的区域都比较小,一个常见的算法就是将需要修复区域的邻边像素进行扩散,填补需要修复的区域,从而达到图像修补的目的。

图像修补基本概念

在一幅需要修复的图像

中,我们将整幅图像用F表示,需要修复的区域块称之为靶区域,用符号D来表示,保留原始图像信息的区域(F-D)称之为源区域。

例如:在如下图像中,有一块被红色污损的区域,这里我们将红色区域称之为靶区域,除了红色区域以外的图像区域,称之为源区域。而我们的传统图像修复算法,就是利用靶区域附近的源像素数据,经过变换拟合来逐渐填充靶区域的像素,从而达到图像修补的效果。

污损图像

全变分模型原理

关于全变分模型的公式推断比较复杂,主要依据欧拉-拉格朗日方程,这里不再详述,直接提供手工推到过程。

欧拉-拉格朗日方程推导

算法步骤

全变分模型主要采用迭代的方式,逐步填充需要修补的区域,直至将所有靶区域像素全部填充完成。

是原始图像数据,

是每次迭代的图像数据

1、初始时

2、接下来每次迭代时:

这里

三个是迭代的参数

3、根据上面公式循环迭代操作 ,可以设置迭代的次数,最后一次的

是最终结果图像数据。

代码实现

这里提供一个简单的全变分图像修补算法。

int32_t XImage::DenoizeTotalVariation(
int32_t iterate_count,
double_t dt,
double_t epsilon,
double_t lambda,
XImage& out_img )
{
int32_t x, y, k;
int32_t ret = 0;
if (!image_valid_)
{
return XERR_BAD_STATE;
}

// 分配矩阵数据
int32_t pixel_count = width_ * height_;
std::unique_ptr<double_t[]> mtx_org_ptr = std::make_unique<double_t[]>(pixel_count);
std::unique_ptr<double_t[]> mtx_src_ptr = std::make_unique<double_t[]>(pixel_count);
std::unique_ptr<double_t[]> mtx_dst_ptr = std::make_unique<double_t[]>(pixel_count);
double_t* mtx_org = mtx_org_ptr.get( );
double_t* mtx_src = mtx_src_ptr.get( );
double_t* mtx_dst = mtx_dst_ptr.get( );

// 将原始图像数据转换成灰度图,再归一化到二维矩阵中
uint8_t* line_data = image_data_;
k = 0;
for (y = 0; y < height_; y++)
{
uint8_t* rgb_data = line_data;
for (x = 0; x < width_; x++)
{
uint32_t R = rgb_data[0] * 77;
uint32_t G = rgb_data[1] * 151;
uint32_t B = rgb_data[2] * 28;
uint32_t gray = (R + G + B) >> 8;
mtx_org[k] = (double_t)(gray / 255.0f);
mtx_src[k] = mtx_org[k];
mtx_dst[k] = mtx_org[k];

k++;
rgb_data += pixel_bytes_;
}

line_data += line_bytes_;
}

int32_t x_end = (width_ - 1);
int32_t y_end = (height_ - 1);
double_t epsilon_pwr2 = epsilon * epsilon;
double_t *org_data, *src_data, *dst_data;

for (k = 0; k < iterate_count; k++)
{
org_data = mtx_org;
src_data = mtx_src;
dst_data = mtx_dst;

// 进行一次迭代操作
for (y = 0; y < height_; y++)
{
for (x = 0; x < width_; x++)
{
double_t dbl_center_data = src_data[0] * 2.0f;
double_t fourfold_center_data = src_data[0] * 4.0f;
int32_t up = y - 1;
int32_t down = y + 1;
int32_t left = x - 1;
int32_t right = x + 1;
if (up < 0) up = 0;
if (down >= height_) down = y;
if (left < 0) left = 0;
if (right >= width_) right = x;

double_t* left_data = src_data - 1;
double_t* right_data = src_data + 1;
double_t* up_data = src_data - width_;
double_t* dn_data = src_data + width_;
if (x == 0) left_data = src_data;
if (x == x_end) right_data = src_data;
if (y == 0) up_data = src_data;
if (y == y_end) dn_data = src_data;

// 对x求一阶偏导
double_t pd_x = (right_data[0] - left_data[0]) / 2;

// 对y求一阶偏导
double_t pd_y = (dn_data[0] - up_data[0]) / 2;

// 对x求二阶偏导
double_t pd_xx = (right_data[0] + left_data[0]) - dbl_center_data;

// 对y求二阶偏导
double_t pd_yy = (up_data[0] + dn_data[0]) - dbl_center_data;

// 先对x再对y求二阶偏导
double_t pd_xy = (right_data[0] + left_data[0] + up_data[0] + dn_data[0]) - fourfold_center_data;

double_t pd_x_pwr2 = pd_x * pd_x;
double_t pd_y_pwr2 = pd_y * pd_y;
double_t temp_num = pd_yy * (pd_x_pwr2 + epsilon_pwr2) + pd_xx * (pd_y_pwr2 + epsilon_pwr2) - (2 * pd_x * pd_y * pd_xy);
double_t temp_den = (pd_x_pwr2 + pd_y_pwr2 + epsilon_pwr2);
//temp_den = pow(temp_den, 1.5);
temp_den = temp_den * temp_den * temp_den;
temp_den = sqrt(temp_den);

dst_data[0] += dt * (temp_num / temp_den + lambda*(org_data[0] - src_data[0]));

org_data++;
src_data++;
dst_data++;
}
}

// 当次迭代结果数据 作为下一次迭代的源数据
memcpy(mtx_src, mtx_dst, pixel_count*sizeof(double_t));

} // 迭代次数完成

//
// 将结果矩阵数据转换到图像数据中
//
if (!IsSameParameter(out_img))
{
out_img.Release( );
ret = out_img.Allocate(PXL_FORMAT_8BIT_GRAY, width_, height_);
XASSERT(ret == XOK);
}

uint8_t* gray_line = out_img.image_data_;
src_data = mtx_src;
for (y = 0; y < height_; y++)
{
uint8_t* gray_data = gray_line;
for (x = 0; x < width_; x++)
{
int32_t gray_val = static_cast<int32_t>(src_data[0]*255);
if (gray_val < 0) gray_val = 0;
if (gray_val > 255) gray_val = 255;
(*gray_data) = static_cast<uint8_t>(gray_val);

gray_data += out_img.pixel_bytes_;
src_data++;
}

gray_line += out_img.line_bytes_;
}

return XOK;
}

void Test()
{
XImage org_img, atdenoise_img;
org_img.LoadFromBmp("d:/input.bmp");

int32_t iterate_count = 40;
double_t epsilon = 0.1f;
double_t dt = epsilon / 5.0f;
double_t lambda = 0.01f;
ret = org_img.DenoizeTotalVariation(iterate_count, dt, epsilon, lambda, atdenoise_img);
atdenoise_img.SaveToBmp("d:/denoised.bmp");
}

总结

本章节主要描述全变分模型的图像去噪和修复效果,在正常应用中,如果对整个图像数据进行全变分迭代,则可以达到图像去噪的效果;如果仅仅对污损区域进行全变分迭代处理,则可以达到污损区域修复效果。不过在实际应用中,全变分模型仅仅适合非常细小区域的修补,对于大块污损区域的修补效果并不好,需要采用后续讲解到的其他的方法。

相关阅读:图像算法原理与实践——图像复原之噪声模型

作者:华叔-视觉魔术师

|关于深延科技|

深延科技成立于2018年,是深兰科技(DeepBlue)旗下的子公司,以“人工智能赋能企业与行业”为使命,助力合作伙伴降低成本、提升效率并挖掘更多商业机会,进一步开拓市场,服务民生。公司推出四款平台产品——深延智能数据标注平台、深延AI开发平台、深延自动化机器学习平台、深延AI开放平台,涵盖从数据标注及处理,到模型构建,再到行业应用和解决方案的全流程服务,一站式助力企业“AI”化。

图像算法原理与实践——图像修复之全变分模型相关推荐

  1. 图像算法原理与实践——图像修复之 全变分模型

    在图像算法的高层次处理中,有一类很典型的应用,就是图像修复算法.图像在采集.传输.预处理过程中,都可能会发生图像数据被修改.损失和缺失等问题(例如:部分图像内容被污染.雾霾等),另外,在实际室外拍照的 ...

  2. java图像识别算法_图像算法原理与实践——绪论

    本系列文章是写给程序源的数字图像处理教程,从最基础的知识来讲解数字图像处理专业知识,通过最基本的编码方式来实践相应的处理算法,从而使得大家掌握基础的图像处理知识. 关于图像处理知识,在高校课程中,比较 ...

  3. bmp文件头_图像算法原理与实践——图像文件存储

    图像数据在计算机储器设备中的存储形式是图像文件,图像必须按照某个公开的.规范约终结定的数据存储顺序和结构进行保存,才能使不同的程序对图像文件顺利进行打开或存盘操作,实现数据共享.图像数据在文件中的存储 ...

  4. 图像修复序列——BSCB模型

    1. 参考文献 2. BSCB模型代码 2.1 BSCB模型demo % demo_BSCB.m % Author: HSW % Date: 2015/3/25 % HARBIN INSTITUTE ...

  5. 图像修复序列——FFM模型

    1. 参考文献 2. FFM模型实现 2.1 FFM模型代码 %%%%%%%%%%%%%%%%%%%%%%%%%%% Demo of Fast March Method %%%%%%%%%%%%%%% ...

  6. fltk在UbuntuLinux中搭建和测试-《C++程序设计原理与实践》Chapter12:显示模型 环境构建...

    ====================Step1==================== 在Windows下参看 http://www.cnblogs.com/vincentfon/archive/ ...

  7. 图像修复序列——FOE模型

    1. 参考文献 2. FOE模型 2.1 FOE 模型实现 %demo_FOE.m % Author: HSW % Date: 2015/3/25 % HARBIN INSTITUTE OF TECH ...

  8. 图像修复 图像补全_图像修复简介

    图像修复 图像补全 In practical applications, images are often corroded by noise. These noises are dust or wa ...

  9. AIGC:Stable Diffusion(一项普通人就能实现的AI前沿科技)的简介、Stable Diffusion2.0的改进、安装、使用方法(文本到图像/图像修改/超分辨率/图像修复)之详细攻略

    AIGC:Stable Diffusion(一项普通人就能实现的AI前沿科技)的简介.Stable Diffusion2.0的改进.安装.使用方法(文本到图像/图像修改/超分辨率/图像修复)之详细攻略 ...

最新文章

  1. Mendix 披露低代码方法论,解读真实技术趋势
  2. rosdep init和rosdep update出错处理
  3. linux 将test.log中第1行的所有都替换成,【Linux面试题7】三剑客笔试题集合
  4. 基础篇verilog-‘timescale的解释
  5. AnkhSVN使用手册
  6. 浙江巨丰管业有限公司网站
  7. intellij idea操作maven时控制台中文乱码
  8. 命令注入_命令注入绕过方式总结
  9. cf#401(Div. 2)B. Game of Credit Card(田忌赛马类贪心)
  10. 【离散数学笔记】图的基本概念思维导图
  11. Django 国际化和本地化
  12. Mobile game forensics
  13. 如果你想提高创新,那么本书就是答案
  14. 每日英语:Targeting Grandpa: China’s Seniors Hunger for Ads
  15. Git配置信息相关命令
  16. silverlight3.0 怎么调试XAML对应的XAML.CS文件
  17. OOM框架AutoMapper基本使用(2)
  18. PHP-laravel框架一1
  19. NCU SEM 发文检索2015年
  20. Cocos2d-x面试题

热门文章

  1. Ubuntu下安装Lnmp
  2. sim卡热插拔检测原理
  3. 爱玩mc卡在更新java_爱玩mc火爆服务器ip与登陆机制
  4. 题目:编写函数fin,其功能是计算:(ln(1)+ln(2)+1n(3).....+ln(m))平方根值,s作为函数值返回。
  5. XEE漏洞任意文件读取
  6. http中的XFF(X-Forwarded-For)
  7. VMware下载与安装
  8. 还有两个月考国二的你,真的用对方法了吗?(附国二刷题软件)
  9. 用HTML+CSS做一个漂亮简单的音乐网站
  10. Rhyme/Intellij idea 工作窗口切换快捷键,摆脱鼠标的束缚