PhotoShop算法原理解析系列 - 像素化---》碎片。
接着上一篇文章的热度,继续讲讲一些稍微简单的算法吧。
本文来讲讲碎片算法,先贴几个效果图吧:

这是个破坏性的滤镜,拿美女来说事是因为搞图像的人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算法原理解析系列 - 像素化---》碎片。的更多相关文章
- PhotoShop算法原理解析系列 - 风格化---》查找边缘。
之所以不写系列文章一.系列文章二这样的标题,是因为我不知道我能坚持多久.我知道我对事情的表达能力和语言的丰富性方面的天赋不高.而一段代码需要我去用心的把他从基本原理-->初步实现-->优化 ...
- 2. Attention Is All You Need(Transformer)算法原理解析
1. 语言模型 2. Attention Is All You Need(Transformer)算法原理解析 3. ELMo算法原理解析 4. OpenAI GPT算法原理解析 5. BERT算法原 ...
- 3. ELMo算法原理解析
1. 语言模型 2. Attention Is All You Need(Transformer)算法原理解析 3. ELMo算法原理解析 4. OpenAI GPT算法原理解析 5. BERT算法原 ...
- 4. OpenAI GPT算法原理解析
1. 语言模型 2. Attention Is All You Need(Transformer)算法原理解析 3. ELMo算法原理解析 4. OpenAI GPT算法原理解析 5. BERT算法原 ...
- 5. BERT算法原理解析
1. 语言模型 2. Attention Is All You Need(Transformer)算法原理解析 3. ELMo算法原理解析 4. OpenAI GPT算法原理解析 5. BERT算法原 ...
- FastText算法原理解析
1. 前言 自然语言处理(NLP)是机器学习,人工智能中的一个重要领域.文本表达是 NLP中的基础技术,文本分类则是 NLP 的重要应用.fasttext是facebook开源的一个词向量与文本分类工 ...
- LRU算法原理解析
LRU是Least Recently Used的缩写,即最近最少使用,常用于页面置换算法,是为虚拟页式存储管理服务的. 现代操作系统提供了一种对主存的抽象概念虚拟内存,来对主存进行更好地管理.他将主存 ...
- 最全排序算法原理解析、java代码实现以及总结归纳
算法分类 十种常见排序算法可以分为两大类: 非线性时间比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此称为非线性时间比较类排序. 线性时间非比较类排序:不通过 ...
- CGI原理解析系列之中的一个----CGI怎样获取WEBserver数据
//gcc get_post.c -o get_post.ums; #include <stdio.h> #include <stdlib.h> #include <un ...
随机推荐
- Solr3.6.1 在Tomcat6下的环境搭建
Solr3.6.1 在Tomcat6下的环境搭建 Tomcat路径:D:\prg\apache-tomcat-6-solr 简写为tomcat_home Solr文件下载保存路径为:F:\softwa ...
- SqlServer切换MySql总结
最近项目任务不多就琢磨着把SqlServer换成MySql(数据访问使用的ado.net),初步想了下方案有2种: 方案一:继续使用ado.net,重写所有的sql语句 优势:数据访问效率高,改写Sq ...
- linux系统下make & make install
make,make install都是典型的使用GNU的AUTOCONF和AUTOMAKE产生的程序的安装步骤. make是用来编译的,在命令行输入make命令之后,系统会在当前目录下搜索Makefi ...
- js自动切换图片
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- Python中三目计算符的正确用法及短路逻辑
今天在看别人代码时看到这样一种写法, 感觉是个挺容易踩到的坑, 搞清楚后写出来备忘. 短路逻辑 Python中进行逻辑运算的时候, 默认采用的是一种叫做短路逻辑的运算规则. 名字是很形象的, 下面直接 ...
- DDD开发框架ABP之本地化资源的数据库存储扩展
在上一篇<DDD开发框架ABP之本地化/多语言支持>中,我们知道,ABP开发框架中本地化资源存储可以采用XML文件,RESX资源文件,也提供了其他自定义的存储方式的扩展接口.ABP框架默认 ...
- JMeter专题系列(四)参数化
JMeter也有像LR中的参数化,本篇就来介绍下JMeter的参数化如何去实现. 参数化:录制脚本中有登录操作,需要输入用户名和密码,假如系统不允许相同的用户名和密码同时登录,或者想更好的模拟多个用户 ...
- 变通实现微服务的per request以提高IO效率
*:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...
- http cancelled状态与ajax 超时
在最近一周,我们的前端在测试某些批量超过的某个步骤时,发现请求好像发出来,但是后台状态没有变化,说是最近才出现的问题,以前一直都是正常的,两天连续出现两次之后,来找笔者,首先检查了下中间件的日志,发现 ...
- Netty(五)序列化protobuf在netty中的使用
protobuf是google序列化的工具,主要是把数据序列化成二进制的数据来传输用的.它主要优点如下: 1.性能好,效率高: 2.跨语言(java自带的序列化,不能跨语言) protobuf参考文档 ...