有2到3年没有逛CodeProject了,上班一时无聊,就翻翻这个比较有名的国外网站,在其Articles » Multimedia » General Graphics » Graphics一栏看到exture Transfer using Efros & Freeman's Image Quilting Algorithm顿感兴趣,其效果很有特色,又激起了我好久没写代码的心,想想在这个算法上大概前前后后思索了1个多星期,虽然最终还是没有得到我想要的结果,但并不全无收获,至此国庆佳节加班之际抽空总结一下,以便慰藉我孤独的心灵。

纹理图像的合成算法在早期的Photoshop中我记得是有一个单独的功能的,在后来的版本中不知道为什么被取消了,印象中他能将只有几颗小草的图片生长成很多小草,并且基本看不出什么瑕疵和不自然的地方,那么CodeProject上的这个Quilting算法也有类似的能力,首先贴几张处理的结果图欣赏一下。

                                            

    

      

    原始纹理图像                                 由小纹理合成的大纹理图像

那么简单的描述下这篇文章所使用的算法的过程吧。

算法需要的输入:原始的纹理图像(W * H),块的大小TileSize,重叠部分的大小Overlap。

  第一步:我们从原始的纹理图像中一个随机的抽取一个小块,放到目标图像的左上角。

无需解释,其中黑色的部分表示目标图像尚未处理的部分。

第二步:按照从左到右,从上到下,抽取出块重叠的部分的数据,并计算这部分数据和原始纹理图像中各块的相似度。

           

水平重叠                                   垂直重叠                         水平和垂直部分具有重叠

  要达到合成自然,在有了第一个块之后,其周边的块应该从原图中选择和其最相似的部位, 因此 ,我们从已经合成的块中抽取部分重叠的数据,如上图所示,红色方框内,没有红色网格线的部分即为重叠的内容,在整个的处理过程中,会有三种情况出现,分别如上图所示,即(1)只有垂直方向有部分重叠;(2)只有水平发方向有部分重叠;(3)水平和垂直方向都有重叠。

为了选择合适的下一个块,我们结算这些重叠的块和原图中的所有块的相似度,块和块之间的相似度可以有很多准则计算,最常用的莫过于SSD(Sum of Squared Distance),这里我们也采用这种准则。

  对于第一种只有垂直方向有部分重叠的情况,块的可能性有 (W - Overlap)* (H - TileSize)种,而只有水平发方向有部分重叠时,块的可能性有(W - TileSize)* (H - Overlap)种,当水平和垂直方向都有重叠时,只有(W - TileSize)* (H - TileSize)种块的选择方案。

对于水平和垂直有交叉的情况,需要分别计算水平重叠的相似性A,垂直重叠的相似性B以及交叉部位的相似性AB,最终的相似性由A + B - AB决定。

计算完相似性后,一般情况下,我们可取相似度最小的块为下一个块,当然为了随机性更强,也可以取相似性序列中前N个最小值种的某个块为选中的块。

第三步:如果对选中的块直接进行拼贴到目标图中,则很明显两个块之间由过渡不会太自然,一种较好的方式就是在选中的块和重叠的部分找到一条路径,在该路径的两侧像素的距离和最小,如果使用暴力的方式去寻找这条路径,则是非常耗时和不必要的,文章介绍使用了贪心算法来寻找这条路径。

我们拿水平重叠的块来说明问题,首先找到第一行最小距离和的像素的位置,假定为(x,1),接着我们搜索第二行的(x - 1, 2), (x, 2), (x + 1, 2)三个位置的距离和的最小值,假定是 (x - 1, 2)是第二行的最小值,则第三行需要搜索的位置为(x - 2, 3), (x - 1, 3), (x, 3),依类类推直到最后一行。

其实路径必然是连续的,因此这种只搜索向下的三领域的做法是完全合理的。

一般情况下,做图像算法会按照从左到右,从上到下的顺序进行处理,这样能够充分利用cache line的优势,如果按照从上到下,然后在从左到右的方式来处理,虽然逻辑和结果是一样的,通常会需要更多的时间,因此,在计算垂直的块的路径时,我们可以借用水平块的算法,只要对垂直的块的数据先进行转置,处理转置的数据得到对应的数据,然后在把这个数据转置就得到了垂直块的结果。注意这里是用的转置,而不是旋转,因为旋转对于该问题是的到的结果是镜像的,所以必须注意。

在水平和垂直部分具有重叠的块的计算时,我们是分别计算垂直和水平的路径,然后取两个路径的交集,计算过程分别如下图。

  

第四步: 按照路径的位置贴入新的数据。

编程技巧:

(1) 在整个的计算中,计算SSD是最为耗时的,因此对其优化是调高程序效率的关键。

  我们看一段matlab的代码,如下所示:

%function Z = ssd(X, Y)
%Computes the sum of squared distances between X and Y for each possible
% overlap of Y on X.  Y is thus smaller than X
%
%Inputs:
%   X - larger image
%   Y - smaller image
%
%Outputs:
%   Each pixel of Z contains the ssd for Y overlaid on X at that pixelfunction Z = ssd(X, Y)K = ones(size(Y,1), size(Y,2));for k=1:size(X,3),A = X(:,:,k);B = Y(:,:,k);a2 = filter2(K, A.^2, 'valid');b2 = sum(sum(B.^2));ab = filter2(B, A, 'valid').*2;if( k == 1 )Z = ((a2 - ab) + b2);elseZ = Z + ((a2 - ab) + b2);end;
end;

  这里的优化时通过卷积实现的,因为SSD的计算就是(a-b)^2的累积和,展开为a^2 + b^2 - 2ab,其中a为固定的图像,那么a^2则为一定值,b^2是不断变化的,但是也可以用积分图之类的算法实现快速效果,唯一的耗时时2ab项,可以用卷积来实现。

快速的卷积算法可以通过FFT来实现,也可以借鉴我在图像处理中任意核卷积(matlab中conv2函数)的快速实现 一文中提到的用SSE的方式实现,鉴于这里的卷积更有其特殊性,他是2幅图像之间的卷积,因此参与计算的都是byte类型,则可以通过选择更为合适的SSE函数来进一步提高效率,这里要感谢有关高手提供的一段SSE代码。

/// <summary>
/// 基于SSE的字节数据的乘法。
/// </summary>
/// <param name="Kernel">需要卷积的核矩阵。</param>
/// <param name="Conv">卷积矩阵。</param>
/// <param name="Length">矩阵所有元素的长度。</param>
/// <remarks> 1: 使用了SSE优化。
/// <remarks> 2: 感谢采石工(544617183)提供的SSE代码<。</remarks>
///    https://msdn.microsoft.com/zh-cn/library/t5h7783k(v=vs.90).aspxint MultiplySSE(unsigned char* Kernel, unsigned char * Conv, int Length)
{int Y, Sum;__m128i vsum = _mm_set1_epi32(0);__m128i vk0 = _mm_set1_epi8(0);for (Y = 0; Y <= Length - 16; Y += 16){__m128i v0 = _mm_loadu_si128((__m128i*)(Kernel + Y));                //    对应movdqu指令,不需要16字节对齐__m128i v0l = _mm_unpacklo_epi8(v0, vk0);                            __m128i v0h = _mm_unpackhi_epi8(v0, vk0);                            //    此两句的作用是把他们分别加载到两个128位寄存器中,供下面的_mm_madd_epi16的16位SSE函数调用(vk0的作用主要是把高8位置0)                __m128i v1 = _mm_loadu_si128((__m128i*)(Conv + Y));__m128i v1l = _mm_unpacklo_epi8(v1, vk0);__m128i v1h = _mm_unpackhi_epi8(v1, vk0);vsum = _mm_add_epi32(vsum, _mm_madd_epi16(v0l, v1l));                //    _mm_madd_epi16 可以一次性进行8个16位数的乘法,然后把两个16的结果在加起来,放到一个32数中, r0 := (a0 * b0) + (a1 * b1),详见 https://msdn.microsoft.com/zh-cn/library/yht36sa6(v=vs.90).aspxvsum = _mm_add_epi32(vsum, _mm_madd_epi16(v0h, v1h));}for (; Y <= Length - 8; Y += 8){__m128i v0 = _mm_loadl_epi64((__m128i*)(Kernel + Y));__m128i v0l = _mm_unpacklo_epi8(v0, vk0);__m128i v1 = _mm_loadl_epi64((__m128i*)(Conv + Y));__m128i v1l = _mm_unpacklo_epi8(v1, vk0);vsum = _mm_add_epi32(vsum, _mm_madd_epi16(v0l, v1l));}vsum = _mm_add_epi32(vsum, _mm_srli_si128(vsum, 8));vsum = _mm_add_epi32(vsum, _mm_srli_si128(vsum, 4));Sum = _mm_cvtsi128_si32(vsum);                                            //    MOVD函数,Moves the least significant 32 bits of a to a 32-bit integer:   r := a0for ( ; Y < Length; Y++){Sum += Kernel[Y] * Conv[Y];}return Sum;
}

以上代码在大数据量时可以一次性完成16个字节数据的乘法及累加,大大的提高了效率。

以上计算SSD的方式也可以帮助提高标准的模板匹配算法的速度,这个我想有心的人应该不难实现。

但是即使采用了这种快速的计算,整个纹理合成的速度还是相当的慢,要使得该算法具有实际的实用价值,还的寻找快速的块相似度平价方法。

由于程序速度问题,我对纹理传输的编写已经失去了信心,纹理传输过程总的和纹理合成和类似,只是在计算相似度时还要考虑目标的诸如亮度或者模糊只方面的信息,速度会比这个纹理合成还要慢,有兴趣的朋友可以看看我提供的一些链接,里面基本都有参考代码。

  不过纹理传输产生的效果有的时候确实比较酷:

那天心血来潮我还是去实现下这个效果吧。

纹理合成完整的工程下载:

http://files.cnblogs.com/files/Imageshop/ImageQuilting.rar

参考资料:

http://web.engr.illinois.edu/~vrgsslv2/cs498dwh/proj2/

http://www.codeproject.com/Articles/24172/Texture-Transfer-using-Efros-Freeman-s-Image-Quilt

http://mesh.brown.edu/dlanman/courses.html

****************************作者: laviewpbt   时间: 2015.10.1    联系QQ:  33184777 转载请保留本行信息**********************

转载于:https://www.cnblogs.com/Imageshop/p/4851969.html

图像纹理合成及纹理传输算法学习(附源码)。相关推荐

  1. MATLAB应用实战系列(五十三)-模拟退火算法(附源码)

    模拟退火算法 模拟退火算法在处理全局优化.离散变量优化等困难问题中,具有传统优化算法无可比拟的优势.这里描述模拟退火算法的原理及其基本框架结构,给出用模拟退火算法求解TSP问题的具体实现方法 以下是我 ...

  2. 4个数字计算24点java算法(附源码)

    今天看到一个帖子说程序员面试考24点算法,想为什么不用程序来实现呢.在网上没有找到非常完美的算法,包括那个24点计算器,给出的结果重复的也较多.所以自己写了一个.在这儿贴出来给大家分享一下.附源码. ...

  3. 深度强化学习之gym扫地机器人环境的搭建(持续更新算法,附源码,python实现)

    想要源码可以点赞关注收藏后评论区留下QQ邮箱 本次利用gym搭建一个扫地机器人环境,描述如下: 在一个5×5的扫地机器人环境中,有一个垃圾和一个充电桩,到达[5,4]即图标19处机器人捡到垃圾,并结束 ...

  4. 二值图像中封闭孔洞的高效填充算法(附源码)。

    写具体类容之前先吐槽一下. 我一直写技术文档,虽然水平不怎么样,但是基本上我写的都还是比较实际的东西,也是自己投入了很多精力做的东西.有些可能没有开源,有些人觉得对他没有什么帮助,而我认为真正做技术的 ...

  5. 模板匹配算法_计算机视觉方向简介 | 多目标跟踪算法(附源码)

    点击上方"计算机视觉life",选择"星标" 快速获得最新干货 || 前言 目标跟踪是计算机视觉领域中研究的热点之一,分为单目标跟踪与多目标跟踪.前者跟踪视频画 ...

  6. 计算机视觉方向简介 | 多目标跟踪算法(附源码)

    || 前言 目标跟踪是计算机视觉领域中研究的热点之一,分为单目标跟踪与多目标跟踪.前者跟踪视频画面中的单个目标,后者则同时跟踪视频画面中的多个目标,得到这些目标的运动轨迹. 基于视觉的多目标跟踪在近年 ...

  7. iOS图片精确提取主色调算法iOS-Palette(附源码)

    源码可见:[直接点击] 1.背景 图像提取主色调来增强浸入式交互体验的场景越来越常见,如知乎网页版的个人主页,Instagram的图片色调筛选.那如何去获得一张照片的主色调呢?Google在Andro ...

  8. Python图像识别实战(一):实现按数量随机抽取图像复制到另一文件夹(附源码和实现效果)

    前面我介绍了可视化的一些方法以及机器学习在预测方面的应用,分为分类问题(预测值是离散型)和回归问题(预测值是连续型)(具体见之前的文章). 从本期开始,我将做一个关于图像识别的系列文章,让读者慢慢理解 ...

  9. sm4算法(附源码、测试代码)

    from:http://blog.csdn.net/mao0514/article/details/52930944 SM4是我们自己国家的一个分组密码算法,是国家密码管理局于2012年发布的.网址戳 ...

  10. SM4密码算法(附源码)

    from:http://blog.csdn.net/mao0514/article/details/52930944 SM4是我们自己国家的一个分组密码算法,是国家密码管理局于2012年发布的.网址戳 ...

最新文章

  1. (18)打鸡儿教你Vue.js
  2. oracle 11gr2 bbed 安装,oracle11gR2 安装bbed工具
  3. PHP常用的正则表达式(有些需要调整)
  4. 使用Spring Boot和React进行Bootiful开发
  5. Python Flask服务同时接收单个、多个上传的文件
  6. redis——redis持久化处理
  7. ListView的刷新
  8. 数据库周刊45丨易鲸捷4.2亿订单创记录;10月Oracle补丁发布;巨杉SequoiaDB v5.0发布;MySQL卡死案例……
  9. Matlab资料汇总暨MATLAB中文论坛帖子整理(一)
  10. SAP MM组织结构及概念
  11. 无法启动 因为计算机丢失msvcp71,Win7丢失msvcp71.dll文件程序无法启动怎么办?
  12. 【二分答案】JZOJ_3337 wyl8899的TLE
  13. linux蜂鸣器驱动指令,Linux 设备驱动简析—PC蜂鸣器驱动
  14. 如何将Google表格电子表格插入Google文档
  15. GoldWave V5.55 绿色汉化版_声音编辑
  16. 武汉沃尔玛被曝出售不合格蜂蜜 糖水勾兑而成
  17. PPP协议的相关介绍
  18. Linuxer-Linux开发者自己的媒体第6月稿件和赠书名单
  19. 华为nova8se和vivoS7e的区别哪个好
  20. ASR项目实战-语音识别

热门文章

  1. 常用的键盘按键(一些小技巧)
  2. springboot使用rabbitMQ(带回调)
  3. 在DevExpress程序中使用GridView直接录入数据的时候,增加列表选择的功能
  4. PCL点云库:Kd树
  5. 1分钟快速生成用于网页内容提取的xslt
  6. JPA学习(6)JPQL
  7. 《面向模式的软件体系结构2-用于并发和网络化对象模式》读书笔记(12)--- 策略化加锁...
  8. 自己动手实现自旋锁(spinlock)
  9. MS CRM 2011 RC中的新特性(2)——销售自动化方面
  10. ASP.NET中验证控件的使用