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

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

           

这是个破坏性的滤镜,拿美女来说事是因为搞图像的人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 * + ) & 0XFFFFFFFC); byte[] ImageData = new byte[Stride * Height]; // 用于保存图像数据,(处理前后的都为他)
byte[] ImageDataC = new byte[Stride * Height]; // 用于保存克隆的图像数据
int[] OffsetX = new int[] { , -, -, }; // 每个点的偏移量
int[] OffsetY = new int[] { -, -, , };
fixed (byte* P = &ImageData[], CP = &ImageDataC[])
{
byte* DataP = P, DataCP = CP;
BitmapData BmpData = new BitmapData();
BmpData.Scan0 = (IntPtr)DataP; // 设置为字节数组的的第一个元素在内存中的地址
BmpData.Stride = Stride;
Bmp.LockBits(new Rectangle(, , Bmp.Width, Bmp.Height), ImageLockMode.ReadWrite | ImageLockMode.UserInputBuffer, PixelFormat.Format24bppRgb, BmpData); Stopwatch Sw = new Stopwatch(); // 只获取计算用时
Sw.Start();
System.Buffer.BlockCopy(ImageData, , ImageDataC, , Stride * Height); // 填充克隆数据 for (Y = ; Y < Height; Y++)
{
Speed = Y * Stride;
for (X = ; X < Width; X++)
{
SumB = ; SumG = ; SumR = ;
for (Z = ; Z < ; Z++) // 累积取样点的取样和
{
XX = X + OffsetX[Z];
YY = Y + OffsetY[Z];
if (XX < ) // 注意越界
XX = ;
else if (XX >= Width)
XX = Width - ;
if (YY < )
YY = ;
else if (YY >= Height)
YY = Height - ;
Index = YY * Stride + XX * ;
SumB += DataCP[Index];
SumG += DataCP[Index + ];
SumR += DataCP[Index + ];
} DataP[Speed] = (byte)((SumB+) >> ); // 求平均值(Sum+2)/4,为什么要+2,就为了四舍五入。比如如果计算结果为108.6,则取像素109更为合理
DataP[Speed + ] = (byte)((SumG + ) >> );
DataP[Speed + ] = (byte)((SumR + ) >> );
Speed += ; // 跳往下一个像素
}
}
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 < )
XX = XX + Width;
while (YY >= Height)
YY = YY - Height;
while (YY < )
YY = YY + Height;

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

 if (XX >=  && XX < Width && YY >=  && 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算法原理解析系列 - 风格化---》查找边缘。

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

  2. 2. Attention Is All You Need(Transformer)算法原理解析

    1. 语言模型 2. Attention Is All You Need(Transformer)算法原理解析 3. ELMo算法原理解析 4. OpenAI GPT算法原理解析 5. BERT算法原 ...

  3. 3. ELMo算法原理解析

    1. 语言模型 2. Attention Is All You Need(Transformer)算法原理解析 3. ELMo算法原理解析 4. OpenAI GPT算法原理解析 5. BERT算法原 ...

  4. 4. OpenAI GPT算法原理解析

    1. 语言模型 2. Attention Is All You Need(Transformer)算法原理解析 3. ELMo算法原理解析 4. OpenAI GPT算法原理解析 5. BERT算法原 ...

  5. 5. BERT算法原理解析

    1. 语言模型 2. Attention Is All You Need(Transformer)算法原理解析 3. ELMo算法原理解析 4. OpenAI GPT算法原理解析 5. BERT算法原 ...

  6. FastText算法原理解析

    1. 前言 自然语言处理(NLP)是机器学习,人工智能中的一个重要领域.文本表达是 NLP中的基础技术,文本分类则是 NLP 的重要应用.fasttext是facebook开源的一个词向量与文本分类工 ...

  7. LRU算法原理解析

    LRU是Least Recently Used的缩写,即最近最少使用,常用于页面置换算法,是为虚拟页式存储管理服务的. 现代操作系统提供了一种对主存的抽象概念虚拟内存,来对主存进行更好地管理.他将主存 ...

  8. 最全排序算法原理解析、java代码实现以及总结归纳

    算法分类 十种常见排序算法可以分为两大类: 非线性时间比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此称为非线性时间比较类排序. 线性时间非比较类排序:不通过 ...

  9. CGI原理解析系列之中的一个----CGI怎样获取WEBserver数据

    //gcc get_post.c -o get_post.ums; #include <stdio.h> #include <stdlib.h> #include <un ...

随机推荐

  1. LINQ to SQL语句(12)之Delete和使用Attach

    1.简单形式 说明:调用DeleteOnSubmit方法即可. OrderDetail orderDetail = db.OrderDetails.First (c => c.OrderID = ...

  2. 关于WebBrowser访问百度地图

    前段时间遇到一个困惑用WebBrowser访问百度地图的时候,百度会自动转至让下载sdk的页面,经过一个仁兄的点拨,可以改变WebBrowser的agent来骗过网站.经过试验成功.贴源码如下: st ...

  3. No.021:Merge Two Sorted Lists

    问题: Merge two sorted linked lists and return it as a new list. The new list should be made by splici ...

  4. PHP使用mysqli扩展库实现增删改查(面向对象版)

    mysqli扩展库是mysql扩展库的改进版本,在mysql扩展库的基础上提高了稳定性和效率,mysqli扩展库有两套东西,一套就是面向过程的mysqli另一套是面向对象的mysqli.操作方式大体和 ...

  5. 从零开始学 Java - Spring 使用 Quartz 任务调度定时器

    生活的味道 睁开眼看一看窗外的阳光,伸一个懒腰,拿起放在床一旁的水白开水,甜甜的味道,晃着尾巴东张西望的猫猫,在窗台上舞蹈.你向生活微笑,生活也向你微笑. 请你不要询问我的未来,这有些可笑.你问我你是 ...

  6. Disruptor-net 3.3.0

    Disruptor 介绍 Disruptor 是LMX开源出来的java编写的一个并发消息处理器,在队列中一边生产者放入消息,另外一边消费者并行取出处理,其核心是根据现代CPU硬件缓存特点发明不同于通 ...

  7. Elasticsearch索引(company)_Centos下CURL增删改

    目录 返回目录:http://www.cnblogs.com/hanyinglong/p/5464604.html 1.Elasticsearch索引说明 a. 通过上面几篇博客已经将Elastics ...

  8. HTML5 Canvas眨眼睛动画

    效果请看: http://keleyi.com/a/bjad/p9exlcwi.htm 请使用支持HTML5的浏览器查看效果. 以下是代码: <html> <body> < ...

  9. 程序员用HTML5制作的爱心树表白动画

    体验效果:http://keleyi.com/keleyi/phtml/html5/31.htm 推荐:http://hovertree.com/texiao/css3/18/ HTML代码如下: & ...

  10. 闲话js作用域

    js词法环境包括环境变量绑定及外部引用'函数创建的时候有个内部属性[[scope]],它指向当前函数的词法环境对象.而词法环境的外部引用一个词法环境'直到全局词法环境'它外部引用为null'这样就构成 ...