图像处理------移动模糊

简介: <p style="color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px;">卷积模糊或者卷积平滑滤波,可以消除图像噪声,也可以产生一些常见的图像模糊特效,但</p><p style="color: rgb(51, 51, 51); font-family: Arial; font-siz

卷积模糊或者卷积平滑滤波,可以消除图像噪声,也可以产生一些常见的图像模糊特效,但

是移动模糊特效也是基于卷积,相比于Box Blur, Gaussian Blur的算法,移动模糊只需要完成

一次的一维卷积,所不同的是一维卷积的完成,要基于一定的角度,而不是只是在水平和垂

直两个方向上。移动模糊的一维卷积要考虑一下三个因素:

                     a. 操作数的多少 - 即距离(Distance)

                     b.一维操作数在像素数组中的移动方向 – 即角度(Angle)

                     c.一维操作数的拉影效应 – 即Scale(放大和缩小程度)(Zoom/Scale)

距离和角度的关系可以用三角几何表示如下:


假设距离和角度已知的情知道中心点(目标像素点)则可以求出每个操作数的像素点坐标,假

设中心点坐标为Base(x0, y0) 则操作数P(a, b)坐标公式可以表示如下:

             a = sinx * c +y0

             b = cosx * c +x0

放缩功能其实是在XY两个方向对图像计算得到一个一维像素结合,再求这些像素的平均值

即可,假设中心点像素为x0, y0, 防缩比率为s0则每个操作数像素点坐标可以表示为:

         a= x0-x0 * s0 + a

         b= y0-y0*so + b

 

原理部分的解释大概如此,下面来看一下,实际图像处理效果和源代码详细解释。

程序运行效果如下– 距离50个像素,角度 0 时:

 

角度30时候的滤镜运行结果:


放缩模糊效果:


角度,距离,放缩三个参数综合效果:


关键代码解释:

计算三角几何角度sin与cos值的代码如下:

[java]  view plain copy
  1. // calculate the trianglegeometry value  
  2. float sinAngle = (float)Math.sin(angle/180.0f * onePI);  
  3. float coseAngle = (float)Math.cos(angle/180.0f * onePI);  

 计算距离半径代码如下:

[java]  view plain copy
  1. // calculate the distance,same as box blur  
  2. float imageRadius = (float)Math.sqrt(cx*cx + cy*cy);  
  3. float maxDistance = distance + imageRadius * zoom;  

计算操作数像素坐标的代码如下:

 

[java]  view plain copy
  1. // calculate the operatorsource pixel  
  2. if(distance > 0) {  
  3. newY = (int)Math.floor((newY+ i*sinAngle));  
  4. newX = (int)Math.floor((newX + i*coseAngle));  
  5. }  

完成Scale的代码如下:

[java]  view plain copy
  1. // scale the pixels  
  2. float scale = 1-zoom*f;  
  3. m11 = cx - cx*scale;  
  4. m22 = cy - cy*scale;  
  5. newY = (int)(newY * scale +m22);  
  6. newX = (int)(newX * scale + m11);  

求取像素平均值,完成一维卷积的代码如下:

[java]  view plain copy
  1. // blur the pixels, here  
  2. count++;  
  3. int rgb= inPixels[newY*width+newX];  
  4. ta += (rgb >> 24) & 0xff;  
  5. tr += (rgb >> 16) & 0xff;  
  6. tg += (rgb >> 8) & 0xff;  
  7. tb += rgb & 0xff;  

重新填充目标像素的代码如下:

[java]  view plain copy
  1. ta = clamp((int)(ta/count));  
  2. tr = clamp((int)(tr/count));  
  3. tg = clamp((int)(tg/count));  
  4. tb = clamp((int)(tb/count));  
  5. outPixels[index] = (ta << 24) | (tr<< 16) | (tg << 8) | tb;  

移动模糊算法的完全源代码如下(不包含测试代码):

[java]  view plain copy
  1. package com.gloomyfish.process.blur.study;  
  2.   
  3. import java.awt.image.BufferedImage;  
  4.   
  5. public class MotionFilter {  
  6.   
  7.     private float distance = 0;// default;  
  8.     private float onePI = (float)Math.PI;  
  9.     private float angle = 0.0f;  
  10.     private float zoom = 0.4f;  
  11.   
  12.     public float getDistance() {  
  13.         return distance;  
  14.     }  
  15.   
  16.     public void setDistance(float distance) {  
  17.         this.distance = distance;  
  18.     }  
  19.   
  20.     public float getAngle() {  
  21.         return angle;  
  22.     }  
  23.   
  24.     public void setAngle(float angle) {  
  25.         this.angle = angle;  
  26.     }  
  27.   
  28.     public BufferedImage filter(BufferedImage src, BufferedImage dst) {  
  29.         int width = src.getWidth();  
  30.         int height = src.getHeight();  
  31.   
  32.         if ( dst == null )  
  33.             dst = createCompatibleDestImage( src, null );  
  34.   
  35.         int[] inPixels = new int[width*height];  
  36.         int[] outPixels = new int[width*height];  
  37.         getRGB( src, 00, width, height, inPixels );  
  38.         int index = 0;  
  39.         int cx = width/2;  
  40.         int cy = height/2;  
  41.           
  42.         // calculate the triangle geometry value  
  43.         float sinAngle = (float)Math.sin(angle/180.0f * onePI);  
  44.         float coseAngle = (float)Math.cos(angle/180.0f * onePI);  
  45.           
  46.         // calculate the distance, same as box blur  
  47.         float imageRadius = (float)Math.sqrt(cx*cx + cy*cy);  
  48.         float maxDistance = distance + imageRadius * zoom;  
  49.           
  50.         int iteration = (int)maxDistance;  
  51.         for(int row=0; row<height; row++) {  
  52.             int ta = 0, tr = 0, tg = 0, tb = 0;  
  53.             for(int col=0; col<width; col++) {  
  54.                 int newX= col, count = 0;  
  55.                 int newY = row;  
  56.                   
  57.                 // iterate the source pixels according to distance  
  58.                 float m11 = 0.0f, m22 = 0.0f;  
  59.                 for(int i=0; i<iteration; i++) {  
  60.                     newX = col;  
  61.                     newY = row;  
  62.                       
  63.                     // calculate the operator source pixel  
  64.                     if(distance > 0) {  
  65.                         newY = (int)Math.floor((newY + i*sinAngle));  
  66.                         newX = (int)Math.floor((newX + i*coseAngle));  
  67.                     }  
  68.                     float f = (float)i/iteration;  
  69.                     if (newX < 0 || newX >= width) {  
  70.                         break;  
  71.                     }  
  72.                     if (newY < 0 || newY >= height) {  
  73.                         break;  
  74.                     }  
  75.                       
  76.                     // scale the pixels  
  77.                     float scale = 1-zoom*f;  
  78.                     m11 = cx - cx*scale;  
  79.                     m22 = cy - cy*scale;  
  80.                     newY = (int)(newY * scale + m22);  
  81.                     newX = (int)(newX * scale + m11);  
  82.                       
  83.                     // blur the pixels, here  
  84.                     count++;  
  85.                     int rgb = inPixels[newY*width+newX];  
  86.                     ta += (rgb >> 24) & 0xff;  
  87.                     tr += (rgb >> 16) & 0xff;  
  88.                     tg += (rgb >> 8) & 0xff;  
  89.                     tb += rgb & 0xff;  
  90.                 }  
  91.                   
  92.                 // fill the destination pixel with final RGB value  
  93.                 if (count == 0) {  
  94.                     outPixels[index] = inPixels[index];  
  95.                 } else {  
  96.                     ta = clamp((int)(ta/count));  
  97.                     tr = clamp((int)(tr/count));  
  98.                     tg = clamp((int)(tg/count));  
  99.                     tb = clamp((int)(tb/count));  
  100.                     outPixels[index] = (ta << 24) | (tr << 16) | (tg << 8) | tb;  
  101.                 }  
  102.                 index++;  
  103.             }  
  104.         }  
  105.   
  106.         setRGB( dst, 00, width, height, outPixels );  
  107.         return dst;  
  108.     }  
  109.       
  110.     public int clamp(int c) {  
  111.         if (c < 0)  
  112.             return 0;  
  113.         if (c > 255)  
  114.             return 255;  
  115.         return c;  
  116.     }  
  117.   
  118. }  
相关文章
|
机器学习/深度学习 人工智能 自然语言处理
探索AI在文本生成中的应用
【8月更文挑战第31天】本文深入探讨了人工智能(AI)在文本生成领域的应用,包括自动写作、聊天机器人和内容创作。我们将分析AI技术如何改变我们创建和消费文本的方式,并讨论其对传统写作行业的影响。通过实例演示,我们将展示如何使用Python编程语言和自然语言处理库来实现一个简单的文本生成模型。
|
Java Android开发
Android如何通过Gradle发布Android依赖库(aar)到 jitpack 公共仓库
Android如何通过Gradle发布Android依赖库(aar)到 jitpack 公共仓库
816 0
|
网络协议 网络安全 数据安全/隐私保护
windocs连接麒麟桌面---vnc软件
windocs连接麒麟桌面---vnc软件
534 0
|
缓存 监控 算法
软件测试中的性能瓶颈分析与优化策略
【10月更文挑战第6天】 性能测试是确保软件系统在高负载条件下稳定运行的重要手段。本文将深入探讨性能测试的常见瓶颈,包括硬件资源、网络延迟和代码效率等问题。通过具体案例分析,我们将展示如何识别并解决这些问题,从而提升软件的整体性能。最后,文章还将分享一些实用的性能优化技巧,帮助读者在日常开发和测试中更好地应对性能挑战。
637 3
|
9月前
|
运维 网络协议 Linux
网络故障排除的7个关键维度
网络故障排除是确保网络稳定运行的关键,能减少停机时间、提升服务质量。本文介绍7个排查步骤:1. 检查硬件连接;2. 使用ipconfig检查IP配置;3. 进行DNS检查;4. 验证网络配置;5. 用其他设备测试;6. 检查IP冲突;7. 测试网络带宽和延迟。通过这些方法,可快速定位并解决问题,保障网络顺畅运行。
900 5
|
11月前
|
供应链 物联网 区块链
《新技术趋势与应用:区块链、物联网与虚拟现实的未来发展》###
本文探讨了区块链技术、物联网(IoT)和虚拟现实(VR)的发展趋势和应用场景。区块链技术以其去中心化特点,在金融、供应链和版权保护等领域展现出巨大潜力;物联网通过设备互联和数据驱动,正革新智能家居、智慧城市和工业自动化等行业;虚拟现实则凭借沉浸式体验和增强交互性,在游戏娱乐、教育培训和医疗健康等领域得到广泛应用。这些新兴技术不仅独立发展,还在相互融合中催生更多创新应用,预示着未来社会的深刻变革和无限可能。 ###
244 1
|
小程序 数据可视化 JavaScript
微信小程序:轻松实现时间轴组件
本文介绍了如何在微信小程序中实现一个可视化时间轴组件。该组件适用于展示用户资金流动、投资结算等时间节点,帮助用户直观了解资金去向。时间轴支持自定义节点形状、显示序号、倒序排列等功能,并通过插槽灵活定义动态内容。文中详细介绍了组件的设计与使用方法,以及如何结合动态 slot 实现自定义操作。该组件为展示用户资金信息提供了美观、易用的解决方案。
555 1
微信小程序:轻松实现时间轴组件
|
传感器 监控 物联网
新技术趋势与应用在科技日新月异的今天,新兴技术如物联网、虚拟现实等正以前所未有的速度改变着我们的生活。本文将深入探讨这些技术的发展趋势和应用场景,揭示它们如何塑造未来。
本文聚焦于物联网和虚拟现实等新兴技术的发展动态及其广泛应用。通过分析当前技术进展、实际应用案例以及未来发展的可能性,本文揭示了这些技术如何深刻影响各行各业,并对未来的趋势进行了展望。
|
SQL 消息中间件 存储
小象超市(原美团买菜) 的大屏图表
小象超市(原美团买菜) 的大屏图表
588 0
|
缓存 Java API
【Azure 服务总线】详解Azure Service Bus SDK中接收消息时设置的maxConcurrentCalls,prefetchCount参数
【Azure 服务总线】详解Azure Service Bus SDK中接收消息时设置的maxConcurrentCalls,prefetchCount参数
199 0