图像算法原理与实践——图像修复之 全变分模型
在图像算法的高层次处理中,有一类很典型的应用,就是图像修复算法。图像在采集、传输、预处理过程中,都可能会发生图像数据被修改、损失和缺失等问题(例如:部分图像内容被污染、雾霾等),另外,在实际室外拍照的时候,可能会将用户不想需要的对象(例如:路人甲等)也摄入照片影像中,需要将这多余图像内容去除。这一类的图像处理算法可以统称为 图像修复,对污染后的图像进行去噪、修补、变换等操作还原原始图像内容。在图像修复中最主要的一类处理就是 图像修补,就是将图像中一小块被污染的区域通过各种算法尽量还原成原始图像。
如果图像中需要修复的区域都比较小,一个常见的算法就是将需要修复区域的邻边像素进行扩散,填补需要修复的区域,从而达到图像修补的目的。
一、图像修补基本概念
在一幅需要修复的图像中,我们将整幅图像用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");
}
总结
本章节主要描述全变分模型的图像去噪和修复效果,在正常应用中,如果对整个图像数据进行全变分迭代,则可以达到图像去噪的效果;如果仅仅对污损区域进行全变分迭代处理,则可以达到污损区域修复效果。不过在实际应用中,全变分模型仅仅适合非常细小区域的修补,对于大块污损区域的修补效果并不好,需要采用后续讲解到的其他的方法。
图像算法原理与实践——图像修复之 全变分模型相关推荐
- 图像算法原理与实践——图像修复之全变分模型
在图像算法的高层次处理中,有一类很典型的应用,就是图像修复算法.图像在采集.传输.预处理过程中,都可能会发生图像数据被修改.损失和缺失等问题(例如:部分图像内容被污染.雾霾等),另外,在实际室外拍照的 ...
- java图像识别算法_图像算法原理与实践——绪论
本系列文章是写给程序源的数字图像处理教程,从最基础的知识来讲解数字图像处理专业知识,通过最基本的编码方式来实践相应的处理算法,从而使得大家掌握基础的图像处理知识. 关于图像处理知识,在高校课程中,比较 ...
- bmp文件头_图像算法原理与实践——图像文件存储
图像数据在计算机储器设备中的存储形式是图像文件,图像必须按照某个公开的.规范约终结定的数据存储顺序和结构进行保存,才能使不同的程序对图像文件顺利进行打开或存盘操作,实现数据共享.图像数据在文件中的存储 ...
- 图像修复序列——BSCB模型
1. 参考文献 2. BSCB模型代码 2.1 BSCB模型demo % demo_BSCB.m % Author: HSW % Date: 2015/3/25 % HARBIN INSTITUTE ...
- 图像修复序列——FFM模型
1. 参考文献 2. FFM模型实现 2.1 FFM模型代码 %%%%%%%%%%%%%%%%%%%%%%%%%%% Demo of Fast March Method %%%%%%%%%%%%%%% ...
- fltk在UbuntuLinux中搭建和测试-《C++程序设计原理与实践》Chapter12:显示模型 环境构建...
====================Step1==================== 在Windows下参看 http://www.cnblogs.com/vincentfon/archive/ ...
- 图像修复序列——FOE模型
1. 参考文献 2. FOE模型 2.1 FOE 模型实现 %demo_FOE.m % Author: HSW % Date: 2015/3/25 % HARBIN INSTITUTE OF TECH ...
- 图像修复 图像补全_图像修复简介
图像修复 图像补全 In practical applications, images are often corroded by noise. These noises are dust or wa ...
- AIGC:Stable Diffusion(一项普通人就能实现的AI前沿科技)的简介、Stable Diffusion2.0的改进、安装、使用方法(文本到图像/图像修改/超分辨率/图像修复)之详细攻略
AIGC:Stable Diffusion(一项普通人就能实现的AI前沿科技)的简介.Stable Diffusion2.0的改进.安装.使用方法(文本到图像/图像修改/超分辨率/图像修复)之详细攻略 ...
最新文章
- 龙芯2h芯片不能进入pmon_国产处理器龙芯地址空间详解
- 第46讲:遇到动态页面怎么办?详解渲染页面爬取
- Python程序输入一个字符串并查找总数的大写和小写字母
- android 用年月日初始化date_Android 系统自带api选择年月日 日历
- java menu单击事件_TinyMCE自定义工具栏menuItem单击触发所有父项的单击事件
- Spring的消息 Java Message Service (JMS)
- Codeforce842D Vitya and Strange Lesson
- vscode开发ExtJs安装插件以及破解方法
- [VSX.002]VS开发环境模型
- SPSS篇—方差分析
- android edittext删除文本框,Android EditText 文本框实现搜索和清空效果
- 中国与外国互免签证协定一览表(更新至2022年7月8日)
- 技术经理、架构师、技术总监、VP、CTO,这些岗位都是如何挣出来
- 学习打印机,了解打印命令
- workbench设置单元坐标系_浅谈Ansys中的几种坐标系
- 控件、组件和插件的区别
- css超出显示...(单行、多行)
- 360浏览器 | 如何从360浏览器中恢复你的密码
- Java 对图片进行大小转换
- 揭秘:蓝光光碟“造”太阳能电池的神奇之处
热门文章
- MOD09A1数据下载与预处理-地表干湿度指数的计算
- 2017070506嵌入式开发系统概述和开发工具的使用
- 评课用计算器计算机,【用计算器探索规律评课稿】_用计算器探索规律评课稿...
- LeetCode(89)GrayCode
- 深度体验特斯拉新Model S:游戏体验翻车,方向盘让人又爱又恨
- 资料员报考建筑八大员报考建筑资料员工程竣工资料整理的举措
- i5 6600 HD530联想扬天S5250黑苹果
- 回顾(JavaScript)Js正则表达式
- afm原子力分析软件_【干货】原子力显微镜(AFM)的使用和成像技巧
- 【无代码体验】用鲸智搭替换Excel表管理数据