这个课题在很久以前就已经有所接触,不过一直没有用代码去实现过。最近买了一本《机器视觉算法与应用第二版》书,书中再次提到该方法:使用傅里叶变换进行滤波处理的真正好处是可以通过使用定制的滤波器来消除图像中某些特定频率,例如这些特定频率可能代表着图像中重复出现的纹理。

  在网络上很多的PS教程中,也有提到使用FFT来进行去网纹的操作,其中最为广泛的是使用PS小插件FOURIER TRANSFORM,使用过程为:打开图像--进行FFT RGB操作,然后定位到红色通道,选取通道中除了最中心处的之外的白点区域,然后填充黑色,在返回综合通道,点击IFFT RGB,就OK了,

      

               原图                            FFR RGB  频谱图

     

   用于消除与纹理对应的频率的滤波器                      IFFT RGB处理的结果图  

  针对这一幅,我曾尝试在PS中用其他的方法来去背景纹理,可是一般去网的同时也把相片模糊了,只有FFT去网纹插件能完美去掉相片的网纹而且不损伤画质。

  这个插件有个特性,他要求输入必须是3通道或者4通道的图,但是用他处理完成后的图虽然表面上看还是3通道还是4通道的,但是他已经失去了彩色信息了,我们注意到他在进行FFT RGB操作后,RGB三个通道中,R通道保存了频谱图,G通道了保存了相位图,B通道为固定值128,频谱和相位组合在一起,只能回复一个通道的信息,因此处理后的图也只能是一个颜色了,这是这个插件的缺陷或者说作为插件的必然性。

  按照这个思路,如果用户提供了用于消除与纹理对应的频率的滤波器,则该过程的一个大概算法流程如下所示:

int IM_TextureRemoval(unsigned char *Src, unsigned char *Mask, unsigned char *Dest, int Width, int Height, int Stride)
{
int Channel = Stride / Width;
if ((Src == NULL) || (Dest == NULL)) return IM_STATUS_NULLREFRENCE;
if ((Width <= ) || (Height <= )) return IM_STATUS_INVALIDPARAMETER;
if ((Channel != ) && (Channel != )) return IM_STATUS_INVALIDPARAMETER; if (Channel == )
{
Complex *Data = (Complex*)malloc(Width * Height * sizeof(Complex)); if (Data == NULL) return IM_STATUS_OUTOFMEMORY; for (int Y = ; Y < Height; Y++)
{
unsigned char *LinePS = Src + Y * Stride; // 填充FFT变换的复数数据
Complex *LinePD = Data + Y * Width;
for (int X = ; X < Width; X++)
{
LinePD[X].Real = LinePS[X];
LinePD[X].Imag = ;
}
}
IM_FFT2D(Data, Data, Width, Height, false, , ); // FFT变换
IM_FFTShift(Data, Data, Width, Height); // 平移中心到图像的中心
for (int Y = ; Y < Height; Y++) // FFT变换的结果乘以用于消除与纹理对应的频率的滤波器
{
unsigned char *LinePS = Mask + Y * Stride;
Complex *LinePD = Data + Y * Width;
for (int X = ; X < Width; X++)
{
LinePD[X].Real *= LinePS[X] * IM_INV255;
LinePD[X].Imag *= LinePS[X] * IM_INV255;
}
}
IM_IFFTShift(Data, Data, Width, Height); // 在反中心化
IM_FFT2D(Data, Data, Width, Height, true, , ); // FFT逆变换 for (int Y = ; Y < Height; Y++) // 转换成图像
{
Complex *LinePS = Data + Y * Width;
unsigned char *LinePD = Dest + Y * Stride;
for (int X = ; X < Width; X++)
{
LinePD[X] = IM_ClampToByte(LinePS[X].Real);
}
}
free(Data);
}
else
{ }
return IM_STATUS_OK; }

  这个过程也是非常简单的。

  对于彩色的图像,可以把他们先劈成3个独立的通道,然后调用上述单通道的处理方法,然后在合成。

  不过这个方法还是有限制的,他能处理的对象是有非常严重网纹的图像,我们测试过对于普通的身份证照片、摩尔纹等是起不到去除作用的,从频谱上来说,就是要在频谱上能看到分布在四周处有一些很明显的独立的亮点。这些亮点就对应着纹理的频率。

  上面的过程需要人工的参与,我们这里进行一下扩展,尝试下对这类图像进行自动的纹理去除。这里的核心是找到纹理的频率,也就是那些白色独立的亮点。

  我们看上面的FFT频谱图,这种显示基本上都是对直接进行FFT变换后的浮点数据进行对数变换后,在线性映射到0到255范围内的,有进行了log操作,数据压缩了很多,导致频谱图的对比度不是很强,也不利于我们分隔出那些亮点,如果我们不记性这种操作,而是直接绝对值Clamp显示,大概能得到下面的效果:

      

  这种效果的FFT图很明显更有利于纹理特征的提取。

  下面的步骤就是:OSTU二值化 -- 》膨胀  --》 腐蚀 -- 》 反色  ---》中心核保留  -- 》中值  得到纹理频率的滤波器。整个效果如下图:

  

          二值化                     膨胀(半径2)                腐蚀(半径2)

  

      反色                    保留中心区域                中值(半径1)

  稍微分析下原理吧(也不一定科学)。

  首先二值化,没啥好说的。 二值后,我们看到白色部分有很多零碎的部分,特别是图像的中心区域的零碎化对最后的效果有非常不好的影响(我们必须保持中心部分没啥变化),所以后续使用了开操作来改善效果,先膨胀后腐蚀。 接着我们反色一下,因为后续的滤波器是非中心区域的白色部分是要变为黑色的,第五步,也是比较核心的步骤,我们需要把中心部分的黑色部分变为白色,因为这部分保留着图像的大部分信息, 这里我们可以采用基于4领域的区域生长法,因为在频谱中的中心点,这一点二值后肯定是白色的,在反色后就是白色,就以这一点为种子点,向四周进行区域生长,这样就可以把中心处的黑色反色过来,而其他地方的黑色保持不变。

  第五步的中值,或者可以用其他模糊来代替,也是有点必要的,对于有些图像,经过前面的处理后,有些核心的线(垂直或者水平方向)也被标记为黑色的了,正在处理完成的图像中会带来原本没有的新条纹。

  

                原图                                     频谱图

            去除中值滤波后的滤波器                                  对应的结果(有瑕疵)

 

          增加中值后的滤波器                                    对应的结果

  上述过程先关的函数如下所示:

//    根据频谱图预估纹理的频谱蒙版区域,支持InPlace操作
int IM_GetTextureMask(unsigned char *Src, unsigned char *Dest, int Width, int Height, int Stride)
{
int Channel = Stride / Width;
if ((Src == NULL) || (Dest == NULL)) return IM_STATUS_NULLREFRENCE;
if ((Width <= ) || (Height <= )) return IM_STATUS_INVALIDPARAMETER;
if (Channel != ) return IM_STATUS_INVALIDPARAMETER;
int Status = IM_STATUS_OK;
unsigned char *Temp = (unsigned char *)malloc(Height * Stride * sizeof(unsigned char));
if (Temp == NULL){ Status = IM_STATUS_OUTOFMEMORY; goto FreeMemory; } int Threshold = ;
Status = IM_GetOSTUThreshold(Src, Width, Height, Stride, Threshold); // 使用OSTU方法二值化
if (Status != IM_STATUS_OK) goto FreeMemory;
Status = IM_Threshold(Src, Temp, Width, Height, Stride, Threshold); // 二值化
if (Status != IM_STATUS_OK) goto FreeMemory;
Status = IM_Dilate(Temp, Dest, Width, Height, Stride, , false); // 先膨胀下(最大值),注意膨胀和腐蚀函数不支持InPlace操作
if (Status != IM_STATUS_OK) goto FreeMemory;
Status = IM_Erode(Dest, Temp, Width, Height, Stride, , false); // 然后在腐蚀(最小值),恢复原来的差不多大小,但是这样中心区域不相邻的点就少了很多
if (Status != IM_STATUS_OK) goto FreeMemory;
Status = IM_Invert(Temp, Dest, Width, Height, Stride); // 这个时候的图,纹理的频谱和其他核心能量区域都还是白色,为后续的处理需要先反色
if (Status != IM_STATUS_OK) goto FreeMemory;
Status = IM_InvertCenter(Dest, Temp, Width, Height, Stride); // 把中心的能量区域保留(白色),其他的纹理的频谱删除(黑色)
if (Status != IM_STATUS_OK) goto FreeMemory;
Status = IM_MedianBlur(Temp, Dest, Width, Height, Stride, , ); // 执行半径为1的中值,这样可能可以减少部分垂直或者水平的核心能力被删除
if (Status != IM_STATUS_OK) goto FreeMemory; FreeMemory:
if (Temp != NULL) free(Temp);
return Status;
}

  我们注意到,上面的操作对纹理处频率处对应的滤波器系数都为0了,也就是这一块的信息全部被消除了,当然实际操作时也可以稍微羽化一下,对最后的结果影响不大。

《任何未通知的转载或转发,都是猪狗不如的作为》。

  根据上述的步骤,有选择性的处理了几幅图,结果如下所示:

   

   

   

  可以看出,虽然能再一定程度上去除网纹,但是也就有一些去除的不完全,这主要还是因为自动提取的滤波器还是不够准确,要想获取更为理想的结果,必须手动的予以修缮。

  对于常规的图片,或者说纹理信息不明显的图,及时执行了上面的去纹理,图片也基本上没有什么变化,因为按照上述方法得到的滤波器基本都为白色。

  本文算法的测试例程见 : http://files.cnblogs.com/files/Imageshop/SSE_Optimization_Demo.rar,位于菜单FFT-->TextureRemoval下。

【算法随记五】使用FFT变换自动去除图像中严重的网纹。的更多相关文章

  1. Matlab实现Hough变换检測图像中的直线

    Hough变换的原理: 将图像从图像空间变换至參数空间.变换公式例如以下: 变换以后,图像空间与參数空间存在下面关系: 图像空间中的一点在參数空间是一条曲线,而图像空间共线的各点相应于參数空间交于一点 ...

  2. 查找图像中椭圆轮廓的快速随机hough变换

    查找图像中椭圆轮廓的快速随机hough变换 图像中椭圆轮廓的查找在视频监控等领域有着广泛的应用,经典hough变换给我们提供了一种查找各种图形轮廓的方法,特别是在直线查找方面具有非常高的精确度.但是由 ...

  3. SSE图像算法优化系列十一:使用FFT变换实现图像卷积。

    本文重点主要不在于FFT的SSE优化,而在于使用FFT实现快速卷积的相关技巧和过程. 关于FFT变换,有很多参考的代码,特别是对于长度为2的整数次幂的序列,实现起来也是非常简易的,而对于非2次幂的序列 ...

  4. SENet(Squeeze-and-Excitation Networks)算法笔记---通过学习的方式来自动获取到每个特征通道的重要程度,然后依照这个重要程度去提升有用的特征并抑制对当前任务用处不大的特征

    Momenta详解ImageNet 2017夺冠架构SENet 转自机器之心专栏 作者:胡杰 本届 CVPR 2017大会上出现了很多值得关注的精彩论文,国内自动驾驶创业公司 Momenta 联合机器 ...

  5. java实现FFT变换(转)

    源:java实现FFT变换 /************************************************************************* * Compilati ...

  6. 安装fftw到window(vs2010)及使用fftw库函数实现4096点fft变换计算

    Windows下FFTW库的安装: 1. 从网站http://www.fftw.org/install/windows.html上下载最新的预编译文件:    32-bit version: fftw ...

  7. SpringBoot启动流程分析(五):SpringBoot自动装配原理实现

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  8. 搜索引擎算法研究专题五:TF-IDF详解

    搜索引擎算法研究专题五:TF-IDF详解 2017年12月19日 ⁄ 搜索技术 ⁄ 共 1396字 ⁄ 字号 小 中 大 ⁄ 评论关闭   TF-IDF(term frequency–inverse ...

  9. Java实现 蓝桥杯 算法训练 第五次作业:字符串排序

    试题 算法训练 第五次作业:字符串排序 问题描述 输入一个小写字符串,按从小到大的顺序输出. 输入格式 bcaed 输出格式 abcde 顶格输出,中间没有空格 样例输入 一个满足题目要求的输入范例. ...

随机推荐

  1. P3469 [POI2008]BLO-Blockade 割点 tarjan

    题意 给定一个无向图,问删掉点i,图中相连的有序对数.(pair<x, y> , x != y);求每个点对应的答案 思路 首先我们可以发现,如果这个点不是割点,那么答案就是n-1,如果是 ...

  2. hihocoder #1609 : 数组分拆II(思维)

    题目链接:http://hihocoder.com/problemset/problem/1609 题解:就先拿一个数组最多分成两部分来说吧 8 1 2 3 4 5 1 2 3 显然 输出时2 3 可 ...

  3. 【转 | 侵删】2D 绘图技术中的坐标系统与坐标变换

    本文介绍在 2D 绘图技术中的坐标系统和坐标变换的相关知识.同时介绍 Kity 在这方面提供的 API .希望这些知识对于需要进行图形应用开发的同学会有所帮助. 锤子的故事 很久以前,有一个画家,他很 ...

  4. 【Redis】主从复制

    一.概述 1.redis的复制功能是支持多个数据库之间的数据同步.一类是主数据库(master)一类是从数据库(slave),主数据库可以进行读写操作,当发生写操作的时候自动将数据同步到从数据库,而从 ...

  5. IDEA中的各种快捷键

    1.get.set快捷键: Alt+Insert 2.idea补全返回值快捷键 比如写了一个new User(),需要补全前面的User user ctrl+alt+V 3.idea全局搜索: Ctr ...

  6. WEB应用中普通java代码如何读取资源文件

    首先: 资源文件分两种:后缀.xml文件和.properties文件 .xml文件:当数据之间有联系时用.xml .properties文件:当数据之间没有联系时用.properties 正题:   ...

  7. 网络编程之Socket代码实例

    网络编程之Socket代码实例 一.基本Socket例子 Server端: # Echo server program import socket HOST = '' # Symbolic name ...

  8. Mysql使用SSL连接

    最近项目中用到了SSL连接,记录一下,环境为windows10,Mysql版本为5.6 查看是否支持 SSL 首先在 MySQL 上执行如下命令, 查询是否 MySQL 支持 SSL: mysql&g ...

  9. 实验吧CTF练习题---WEB---因缺思汀的绕过解析

    实验吧web之因缺思汀的绕过 地址:http://www.shiyanbar.com/ctf/1940 flag值:   解题步骤: 1.点开题目,观察题意 2.通过观察题目要求,判断此道题还有代码审 ...

  10. 玩转 SpringBoot 2 快速整合 | JSP 篇

    前言 JavaServer Pages(JSP)技术使Web开发人员和设计人员能够快速开发和轻松维护利用现有业务系统的信息丰富的动态Web页面. 作为Java技术系列的一部分,JSP技术可以快速开发独 ...