android图片模糊效果,Android下实现高效的模糊效果

本文详细介绍了如何在Android下实现图片的模糊效果,包括均值模糊和高斯模糊的原理,以及如何使用renderscript进行图片处理。通过示例代码展示了如何创建模糊效果,同时讨论了如何利用renderscript编写蒙版效果,增强图片模糊后的视觉呈现。文章还涉及了计算机处理透明度和颜色叠加的原理,以及如何优化模糊算法以提高性能。
摘要由CSDN通过智能技术生成

4abce9d7b347

其实有关 android 下实现图片模糊的文章有很多,大多都是使用 renderscript 内置的 ScriptIntrinsicBlur 来实现的,这篇文章中的例子也不例外,但如果仅仅是调用一下 api 的话就没必要去写了。所以接下来会介绍均值模糊以及高斯模糊的原理、什么是 renderscript 以及如何编写 renderscript。最终的例子是将图片高斯模糊处理后再调用自己编写的 rs 对其增加一层蒙版效果(这里会提到计算机是如何处理透明度以及颜色叠加的)。

系好安全带,开车了!

4abce9d7b347

上面这张图片是用于图像算法测试的国际标准图像,使用这张图片主要有两个原因:

图像包含了各种细节、平滑区域、阴影和纹理,这些对测试各种图像处理算法很有用。

图像里是一个很迷人的女子。而图像处理领域里的人大多为男性,可以吸引更多的人。

然而这张图片其实出自 1972 年的 《花花公子》,所以上面给出的图片并不完整,下面我们写一个小 demo 来展示一下完整的图片。

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

imageView = (ImageView) findViewById(R.id.image);

drag = (ImageView) findViewById(R.id.drag);

SeekBar progressBar = (SeekBar) findViewById(R.id.seek);

bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.rina);

imageView.setImageBitmap(bitmap);

imageView.post(new Runnable() {

@Override

public void run() {

float scale = bitmap.getWidth() * 1f / imageView.getWidth();

mosaic = Bitmap.createBitmap(bitmap, (int) (drag.getX() * scale), (int) (drag.getY() * scale),

(int) (drag.getWidth() * scale), (int) (drag.getHeight() * scale));

drag.setImageBitmap(BlurHelper.mosaic(mosaic, currentRadius));

}

});

progressBar.setProgress(currentRadius * 5);

progressBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {

@Override

public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

if (progress % 5 == 0) {

currentRadius = progress / 5;

drag.setImageBitmap(BlurHelper.mosaic(mosaic, currentRadius));

}

}

@Override

public void onStartTrackingTouch(SeekBar seekBar) {

}

@Override

public void onStopTrackingTouch(SeekBar seekBar) {

}

});

drag.setOnTouchListener(new View.OnTouchListener() {

@Override

public boolean onTouch(View v, MotionEvent event) {

switch (event.getAction()) {

case MotionEvent.ACTION_DOWN:

xDown = event.getX();

yDown = event.getY();

break;

case MotionEvent.ACTION_MOVE:

float targetX = event.getX() - xDown + v.getTranslationX();

float targetY = event.getY() - yDown + v.getTranslationY();

targetX = Math.min(Math.max(targetX, 0), imageView.getWidth() - drag.getWidth());

targetY = Math.min(Math.max(targetY, 0), imageView.getHeight() - drag.getHeight());

v.setTranslationX(targetX);

v.setTranslationY(targetY);

float scale = bitmap.getWidth() * 1f / imageView.getWidth();

b = Bitmap.createBitmap(bitmap, (int) (drag.getX() * scale), (int) (drag.getY() * scale),

(int) (drag.getWidth() * scale), (int) (drag.getHeight() * scale));

drag.setImageBitmap(BlurHelper.mosaic(mosaic, currentRadius));

break;

}

return true;

}

});

}

public static Bitmap mosaic(Bitmap bitmap, int radius) {

if (radius == 0) return bitmap;

final int width = bitmap.getWidth();

final int height = bitmap.getHeight();

final Bitmap outBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());

final int[] pixels = new int[width * height];

bitmap.getPixels(pixels, 0, width, 0, 0, width, height);

for (int i = 0; i < height; i++) {

for (int j = 0; j < width; j++) {

int x = j % radius;

int y = i % radius;

pixels[i * width + j] = pixels[(i - y) * width + j - x];

}

}

outBitmap.setPixels(pixels, 0, width, 0, 0, width, height);

return outBitmap;

}

4abce9d7b347

因为原图有点少儿不宜,所以我这边手动给打了个码,在原图上盖了一层马赛克后的图片,每次拖动后都会重新计算。其实马赛克算法也是一种模糊算法,首先图片其实是由很多像素点组成的一个二维数组(或者矩阵)。上面的马赛克算法只是遍历了图片的每一个像素,然后在这个过程中对于给定的半径将所有的像素都设置成第一个像素的值。

我们由此抛砖引玉引出均值模糊(box blur),和马赛克算法差不多,他是每一个像素都取周围像素的平均值。算法也比较简单,如下:

public static Bitmap boxBlur(Bitmap bitmap, int radius) {

final int width = bitmap.getWidth();

final int height = bitmap.getHeight();

final int[] pixels = new int[width * height];

final int[] outPixels = new int[width * height];

final Bitmap outBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());

bitmap.getPixels(pixels, 0, width, 0, 0, width, height);

//遍历bitmap每一个像素

for (int i = 0; i < width; i++) {

for (int j = 0; j < height; j++) {

//取半径为radius的矩形区域,并处理边界情况

final int left = i - radius < 0 ? 0 : i - radius;

final int top = j - radius < 0 ? 0 : j - radius;

final int right = i + radius > width ? width : i + radius;

final int bottom = j + radius > height ? height : j + radius;

//矩形区域总像素

final int count = (right - left) * (bottom - top);

//分别求出矩形区域内rgb的总值

int r = 0, g = 0, b = 0;

for (int m = left; m < right; m++) {

for (int n = top; n < bottom; n++) {

final int pixel = pixels[n * width + m];

r += Color.red(pixel);

g += Color.green(pixel);

b += Color.blue(pixel);

}

}

//设置新的像素为矩形区域内像素的均值

outPixels[j * width + i] = Color.rgb(r / count, g / count, b / count);

}

}

outBitmap.setPixels(outPixels, 0, width, 0, 0, width, height);

bitmap.recycle();

return outBitmap;

}

上面这么写是为了看起来更清楚,他的时间复杂度为 O(n^2 * m^2)效率是极低的。anyway 进行均值模糊之后的效果如下图(图像大小 300 * 260,模糊半径 5 )

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值