接着上一篇文章的热度,继续讲讲一些稍微简单的算法吧。

本文来讲讲碎片算法,先贴几个效果图吧:

           

这是个破坏性的滤镜,拿美女来说事是因为搞图像的人90%是男人,色色的男人。

关于碎片滤镜的原理,网络上可找到的资料为:将图像创建四个相互偏移的副本,产生类似重影的效果。

就凭上述一句话,我们就可以动手了。

分析:通过上述几幅图像的比较,特别是眼睛部位,可以看出处理的图应该看得出像是单眼变成了4个眼睛,因此,网络上的说法可靠。

那么偏移的中心在哪里,偏移的数量又是多少呢,4个偏移,分别是往那些方向偏移呢,这些问题也很简单,可以那PS做验证:

具体步骤如下:打开一幅图像,在图像颜色比较单调的地方(比如上述美女的手臂处)填充一处2*2像素的红色,然后复制图层,对复制后的图层进行碎片滤镜处理,并调整图层透明度为50%,局部放大可得到如下图像:

如此效果,则可轻易得出结论:

偏移的中心就是以每个像素为中心,4个偏移分别以中心对称,斜45度均匀圆周布置,水平和垂直偏移各45度,偏移量4个像素。

那么如何叠加的问题应该可以猜测,是取四次偏移后累加值的平均值。

针对如此思路,我写出如下算法:

private void CmdFragment_Click(object sender, EventArgs e)
{int X, Y, Z, XX, YY;int Width, Height, Stride;int Speed, Index;int SumR, SumG, SumB;Bitmap Bmp = (Bitmap)Pic.Image;if (Bmp.PixelFormat != PixelFormat.Format24bppRgb) throw new Exception("不支持的图像格式.");Width = Bmp.Width; Height = Bmp.Height; Stride = (int)((Bmp.Width * 3 + 3) & 0XFFFFFFFC);byte[] ImageData = new byte[Stride * Height];                                    // 用于保存图像数据,(处理前后的都为他)byte[] ImageDataC = new byte[Stride * Height];                                   // 用于保存克隆的图像数据int[] OffsetX = new int[] { 4, -4, -4, 4 };                                      // 每个点的偏移量int[] OffsetY = new int[] { -4, -4, 4, 4 };fixed (byte* P = &ImageData[0], CP = &ImageDataC[0]){byte* DataP = P, DataCP = CP;BitmapData BmpData = new BitmapData();BmpData.Scan0 = (IntPtr)DataP;                                              //  设置为字节数组的的第一个元素在内存中的地址BmpData.Stride = Stride;Bmp.LockBits(new Rectangle(0, 0, Bmp.Width, Bmp.Height), ImageLockMode.ReadWrite | ImageLockMode.UserInputBuffer, PixelFormat.Format24bppRgb, BmpData);Stopwatch Sw = new Stopwatch();                                             //  只获取计算用时Sw.Start();System.Buffer.BlockCopy(ImageData, 0, ImageDataC, 0, Stride * Height);     //  填充克隆数据        for (Y = 0; Y < Height; Y++){Speed = Y * Stride;for (X = 0; X < Width; X++){SumB = 0; SumG = 0; SumR = 0;for (Z = 0; Z < 4; Z++)                                           //  累积取样点的取样和{XX = X + OffsetX[Z];YY = Y + OffsetY[Z];if (XX < 0)                                                    //   注意越界XX = 0;else if (XX >= Width)XX = Width - 1;if (YY < 0)YY = 0;else if (YY >= Height)YY = Height - 1;Index = YY * Stride + XX * 3;SumB += DataCP[Index];SumG += DataCP[Index + 1];SumR += DataCP[Index + 2];}DataP[Speed] = (byte)((SumB+2) >> 2);    //  求平均值(Sum+2)/4,为什么要+2,就为了四舍五入。比如如果计算结果为108.6,则取像素109更为合理     DataP[Speed + 1] = (byte)((SumG + 2) >> 2);DataP[Speed + 2] = (byte)((SumR + 2) >> 2);Speed += 3;                                                     //  跳往下一个像素}}Sw.Stop();this.Text = "计算用时: " + Sw.ElapsedMilliseconds.ToString() + " ms";Bmp.UnlockBits(BmpData);                         //  必须先解锁,否则Invalidate失败 }Pic.Invalidate();
}

算法中,OffsetX 和 OffsetY分别为取样点像素的偏移量。同样,由于该滤镜涉及到了领域操作,在处理前需要做像素备份,但这里没有对备份数据进行扩展。因此,在内部代码里就需要对取样点的坐标进行验证,看是否超过其范围,如果超过范围,通常在图像滤镜算法范围内,有3种处理方式:

(1)超过了则认为是其最接近的边界值,即重复边缘像素,这部分代码即上述贴出的if ..... else if 部分。

(2)折回,可用如下代码来描述:

while (XX >= Width)XX = XX - Width;
while (XX < 0)XX = XX + Width;
while (YY >= Height)YY = YY - Height;
while (YY < 0)YY = YY + Height;

(3) 只计算在图像范围内的像素:

 if (XX >= 0 && XX < Width && YY >= 0 && YY < Height){// 累加计算}

当然这样做,就必须用一个变量记录下都做了多少次符合条件的计算。

有兴趣的朋友可以自己改改代码试一试。

上述代码段中DataP[Speed] = (byte)((SumB+2) >> 2);要对SumB加2的原因是为了让结果进行四舍五入的操作,这样才较为合理。

经过测试,上述代码和PS处理的效果100%的吻合。说明我们的猜测是完全正确的。

还可以对算法进一步扩展:  想的远一点,为什么非的是4个重影呢,非得是45度角度呢,非得是4个像素的水平和垂直偏移呢。我给出下图让有兴趣的读者自己研发吧。

图中,角度为32度,半径为10,碎片数为7,可产生类似下面的效果(可用我的Imageshop进行验证):

       

完整工程下载地址:http://files.cnblogs.com/Imageshop/Fragement.rar

************基本上我不提供源代码,但是我会尽量用文字把对应的算法描述清楚或提供参考文档**************

*************因为靠自己的努力和实践写出来的效果才真正是自己的东西,人一定要靠自己*****************

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

PhotoShop算法原理解析系列 - 像素化---》碎片。相关推荐

  1. PhotoShop算法原理解析系列 - 像素化---》碎片

    本篇博文来自博主Imageshop,打赏或想要查阅更多内容可以移步至Imageshop. 转载自:https://www.cnblogs.com/Imageshop/p/3173090.html    ...

  2. PhotoShop算法原理解析系列 - 风格化---》查找边缘

    本篇博文来自博主Imageshop,打赏或想要查阅更多内容可以移步至Imageshop. 转载自:https://www.cnblogs.com/Imageshop/p/3171425.html    ...

  3. PhotoShop算法原理解析系列 - 风格化---》查找边缘。

    之所以不写系列文章一.系列文章二这样的标题,是因为我不知道我能坚持多久.我知道我对事情的表达能力和语言的丰富性方面的天赋不高.而一段代码需要我去用心的把他从基本原理-->初步实现-->优化 ...

  4. 索引算法原理解析(B-tree以及磁盘存储原理)

    刚开始学习的时候,百度去查,但发现好多说得太复杂不好理解,结合各个文章总结一下(建议大概看文字,不理解不要紧,然后再看图的执行步骤然后在结合文字,这样一切就清晰好多) B-tree,B是balance ...

  5. python文件去重算法_使用Python检测文章抄袭及去重算法原理解析

    在互联网出现之前,"抄"很不方便,一是"源"少,而是发布渠道少:而在互联网出现之后,"抄"变得很简单,铺天盖地的"源"源 ...

  6. python去重算法_使用Python检测文章抄袭及去重算法原理解析

    在互联网出现之前,"抄"很不方便,一是"源"少,而是发布渠道少:而在互联网出现之后,"抄"变得很简单,铺天盖地的"源"源 ...

  7. p.563算法原理解析

    p.563算法原理解析 1.概览 ​ 下图展示了,人工主观语音评估mos-lqs,双端和单端客观语音评估mos-lqo这三种方法的差异. ​ p563算法可以被想象成一个专家使用测试设备如传统的听筒侦 ...

  8. LruCache算法原理解析

    本来想写关于LruCache算法的原理解析文章,但是看到卡神的作品,写的太好了.所以这里我还是转载一下吧. 史上最详细LrcCache算法解析:https://blog.csdn.net/carson ...

  9. 十分详细的diff算法原理解析

    本文我们总结一下有关diff算法的相关内容和实现原理 开门见山,直接先给出大家diff算法的概念 diff算法可以看作是一种对比算法,对比的对象是新旧虚拟Dom.顾名思义,diff算法可以找到新旧虚拟 ...

最新文章

  1. 10个机器学习的JavaScript示例
  2. 分布式session之token解决方案实现
  3. 架构师之路 — 部署架构 — 集群部署
  4. ACM一类方程问题的求解[最短路建模] bzoj2118
  5. 判断对象所有属性是否全部为空
  6. android 代码设置dialog 全屏,Android里把Dialog设置为全屏的方法
  7. linux 物理内存用完了_调整linux内核尽量用内存,而不用swap
  8. 【刷题】BZOJ 1124 [POI2008]枪战Maf
  9. C# DataTable.Rows.Add(DataRow) 该行已经属于另一个表
  10. libcurl代码示例
  11. warning: left shift count = width of type
  12. 互联网平台黑产解密(上)
  13. Mac “EdrawMax”已损坏,无法打开。 您应该将它移到废纸篓
  14. Android kernel中wakeup_sources解析
  15. Android——Timer停不下来的解决方法
  16. linux计时器命令,安装及使用Linux终端倒数计时器Countdown的方法
  17. Response响应详解
  18. c 语言提取左右声道数据
  19. 基于视觉导航机器人的快递分拣系统(开放源码附带论文和github仓库)
  20. 分布式高可靠:负载均衡

热门文章

  1. Linux软件安装管理---源码安装
  2. java 线程方法join的简单总结
  3. 潘建伟团队进行人类首次洲际量子通信 都发送了什么
  4. ASP.NET MVC5+EF6+EasyUI 后台管理系统(50)-Easyui 扁平化皮肤
  5. GPSInfoProvider定位
  6. 电脑启动后,没有桌面
  7. C#----DataGridView控件60招(一) [转]
  8. 查找字符串里面有没有相同的字符- -
  9. Spring多数据源配置和使用
  10. 大学录取通知书也越来越科技范儿