Android Bitmap 加载与像素操作

简介: Android Bitmap 加载与像素操作

Android Bitmap 加载与像素操作

一:加载与像素读写

在Android SDK中,图像的像素读写可以通过getPixel与setPixel两个Bitmap的API实现。Bitmap API读取像素的代码如下:

int pixel = bitmap.getPixel(col, row);// ARGB
int red = Color.red(pixel); // same as (pixel >> 16) &0xff
int green = Color.green(pixel); // same as (pixel >> 8) &0xff
int blue = Color.blue(pixel); // same as (pixel & 0xff)
int alpha = Color.alpha(pixel); // same as (pixel >>> 24)

得到像素pixel是32位的整数,四个字节分别对应透明通道、红色、绿色、蓝色通道。Bitmap API 写入像素,代码如下:

bm.setPixel(col, row, Color.argb(alpha, red, green, blue));

通过Color.argb重新组装成一个int的像素值。

使用BitmapFactory.decodeFile或者decodeResource等方法实现加载图像的Bitmap对象时,这些方法就会为要构建的Bitmap对象分配合适大小的内存,如果原始的图像文件数据很大,就会导致DVM不能分配请求的内存大小,从而导致OOM(out of memory)问题。而通过配置BitmapFactory.Option预先读取图像高度与宽带,图像进行适当的下采样,就可以避免OOM问题的发生。预先只获取图像高度与宽带的代码如下:

        // 获取Bitmap图像大小与类型属性
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(getResources(), 
                                        R.drawable.shar_03, options);
        int height = options.outHeight;
        int width = options.outWidth;
        String imageType = options.outMimeType;

基于下采样加载超大Bitmap图像的缩小版本:

        // 下采样
        int inSampleSize = 1;
        if (height > reqHeight || width > reqWidth) {

            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            // Calculate the largest inSampleSize value 
            // that is a power of 2 and keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) > reqHeight
                    && (halfWidth / inSampleSize) > reqWidth) {
                inSampleSize *= 2;
            }
        }
        // 获取采样后的图像显示,避免OOM问题
        options.inJustDecodeBounds = false;
        srcImage = BitmapFactory.decodeResource(getResources(), R.drawable.shar_03, options);

二:像素操作

android彩色图像灰度化的三个简单方法

灰度化方法一:

灰度值GRAY = (max(red, green, blue) + min(red, green, blue))/2

灰度化方法二:

灰度值GRAY = (red + green + blue)/3

灰度化方法三:

灰度值GRAY = red*0.3 + green*0.59 + blue*0.11

代码实现如下:

public Bitmap gray(Bitmap bitmap, int schema)
{
    Bitmap bm = Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(), bitmap.getConfig());
    int width = bitmap.getWidth();
    int height = bitmap.getHeight();
    for(int row=0; row<height; row++){
       for(int col=0; col<width; col++){
          int pixel = bitmap.getPixel(col, row);// ARGB
          int red = Color.red(pixel); // same as (pixel >> 16) &0xff
          int green = Color.green(pixel); // same as (pixel >> 8) &0xff
          int blue = Color.blue(pixel); // same as (pixel & 0xff)
          int alpha = Color.alpha(pixel); // same as (pixel >>> 24)
          int gray = 0;
          if(schema == 0)
          {
              gray = (Math.max(blue, Math.max(red, green)) + 
                          Math.min(blue, Math.min(red, green))) / 2;
          }
          else if(schema == 1)
          {
              gray = (red + green + blue) / 3;
          }
          else if(schema == 2)
          {
              gray = (int)(0.3 * red + 0.59 * green + 0.11 * blue);
          }
          bm.setPixel(col, row, Color.argb(alpha, gray, gray, gray));
       }
    }
    return bm;
}

Bitmap图像镜像映射与亮度调整的代码实现如下:

public Bitmap brightness(Bitmap bitmap, double depth)
{
    Bitmap bm = Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(), bitmap.getConfig());
    int width = bitmap.getWidth();
    int height = bitmap.getHeight();
    for(int row=0; row<height; row++){
       for(int col=0; col<width; col++){
          int pixel = bitmap.getPixel(col, row);// ARGB
          int red = Color.red(pixel); // same as (pixel >> 16) &0xff
          int green = Color.green(pixel); // same as (pixel >> 8) &0xff
          int blue = Color.blue(pixel); // same as (pixel & 0xff)
          int alpha = Color.alpha(pixel); // same as (pixel >>> 24)
          double gray = (0.3 * red + 0.59 * green + 0.11 * blue);
          red += (depth * gray);
          if(red > 255) { red = 255; }

          green += (depth * gray);
          if(green > 255) { green = 255; }

          blue += (depth * gray);
          if(blue > 255) { blue = 255; }
          bm.setPixel(col, row, Color.argb(alpha, red, green, blue));
       }
    }
    return bm;
}

public Bitmap flip(Bitmap bitmap)
{
    Bitmap bm = Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(), bitmap.getConfig());
    int width = bitmap.getWidth();
    int height = bitmap.getHeight();
    for(int row=0; row<height; row++){
       for(int col=0; col<width; col++){
          int pixel = bitmap.getPixel(col, row);// ARGB
          int red = Color.red(pixel); // same as (pixel >> 16) &0xff
          int green = Color.green(pixel); // same as (pixel >> 8) &0xff
          int blue = Color.blue(pixel); // same as (pixel & 0xff)
          int alpha = Color.alpha(pixel); // same as (pixel >>> 24)
          int ncol = width - col - 1;
          bm.setPixel(ncol, row, Color.argb(alpha, red, green, blue));
       }
    }
    return bm;
}

运行截图:

布局XML文件内容如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.imageprocess1.MainActivity" >
    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <Button
            android:id="@+id/button_gray_3"
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:text="@string/process" />

        <Button
            android:id="@+id/button_inverse"
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:layout_toRightOf="@+id/button_gray_3"
            android:layout_alignTop="@+id/button_gray_3"
            android:text="@string/inverse" />

        <Button
            android:id="@+id/button_gray_1"
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:layout_toRightOf="@+id/button_inverse"
            android:layout_alignTop="@+id/button_gray_3"
            android:text="@string/nored" />

        <Button
            android:id="@+id/button_gray_2"
            android:layout_width="100dp"
            android:layout_below="@+id/button_gray_3"
            android:layout_height="wrap_content"
            android:text="@string/noblue" />

        <Button
            android:id="@+id/button_flip"
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:layout_below="@+id/button_inverse"
            android:layout_toRightOf="@+id/button_gray_2"
            android:text="@string/flip" />
        <Button
            android:id="@+id/button_save"
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:layout_below="@+id/button_gray_3"
            android:layout_toRightOf="@+id/button_flip"
            android:text="@string/save" />
    </RelativeLayout>

    <ImageView
        android:id="@+id/image_content"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:scaleType="fitCenter"
        android:src="@drawable/ic_launcher" />

</LinearLayout>

MainActivity中的onCreate方法的代码如下:

super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView iView = (ImageView) this.findViewById(R.id.image_content);
Bitmap b = Bitmap.createBitmap(400, 400, Bitmap.Config.ARGB_8888);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.BLACK);
Canvas c = new Canvas(b);
c.drawText("Load Image from here...", 50, 200, paint);
iView.setImageBitmap(b);
Button saveBtn = (Button) this.findViewById(R.id.button_save);
saveBtn.setOnClickListener(new OnClickListener() {

    @Override
    public void onClick(View view) {
        Toast toast = Toast.makeText(getApplicationContext(), "Please load the image firstly...", Toast.LENGTH_SHORT);
        toast.show();
        loadImage();
        ImageView iView = (ImageView) findViewById(R.id.image_content);
        iView.setImageBitmap(srcImage);
        if(srcImage != null)
        {
            //saveFile(srcImage);
        }
    }

});
Button processBtn = (Button) this.findViewById(R.id.button_gray_3);
processBtn.setOnClickListener(new OnClickListener() {

    @Override
    public void onClick(View view) {
        if(srcImage == null)
        {
            loadImage();
        }
        ImagePixelsProcessor processor = new ImagePixelsProcessor();
        Bitmap bm = processor.gray(srcImage, 2); // 有不同的灰度化策略
        final ImageView iView = (ImageView) findViewById(R.id.image_content);
        iView.setImageBitmap(bm);
    }

});

Button inverseBtn = (Button) this.findViewById(R.id.button_inverse);
inverseBtn.setOnClickListener(new OnClickListener() {

    @Override
    public void onClick(View view) {
        if(srcImage == null)
        {
            loadImage();
        }
        ImagePixelsProcessor processor = new ImagePixelsProcessor();
        Bitmap bm = processor.brightness(srcImage, 0.3);
        final ImageView iView = (ImageView) findViewById(R.id.image_content);
        iView.setImageBitmap(bm);
    }
});

Button noRedBtn = (Button) this.findViewById(R.id.button_gray_1);
noRedBtn.setOnClickListener(new OnClickListener() {

    @Override
    public void onClick(View view) {
        if(srcImage == null)
        {
            loadImage();
        }
        ImagePixelsProcessor processor = new ImagePixelsProcessor();
        Bitmap bm = processor.gray(srcImage, 0); // 有不同的灰度化策略
        final ImageView iView = (ImageView) findViewById(R.id.image_content);
        iView.setImageBitmap(bm);
    }
});

Button gray2Btn = (Button) this.findViewById(R.id.button_gray_2);
gray2Btn.setOnClickListener(new OnClickListener() {

    @Override
    public void onClick(View view) {
        if(srcImage == null)
        {
            loadImage();
        }
        ImagePixelsProcessor processor = new ImagePixelsProcessor();
        Bitmap bm = processor.gray(srcImage, 1); // 有不同的灰度化策略
        final ImageView iView = (ImageView) findViewById(R.id.image_content);
        iView.setImageBitmap(bm);
    }
});

Button flipBtn = (Button) this.findViewById(R.id.button_flip);
flipBtn.setOnClickListener(new OnClickListener() {

    @Override
    public void onClick(View view) {
        if(srcImage == null)
        {
            loadImage();
        }
        ImagePixelsProcessor processor = new ImagePixelsProcessor();
        Bitmap bm = processor.flip(srcImage);
        final ImageView iView = (ImageView) findViewById(R.id.image_content);
        iView.setImageBitmap(bm);
    }
});

-第一次尝试用CSDN-markdown编辑器写文章,发现这个东西真好用!赞!!!

-gloomyfish@2015-07-02

相关文章
|
6月前
|
Java 数据库 Android开发
【专栏】Kotlin在Android开发中的多线程优化,包括线程池、协程的使用,任务分解、避免阻塞操作以及资源管理
【4月更文挑战第27天】本文探讨了Kotlin在Android开发中的多线程优化,包括线程池、协程的使用,任务分解、避免阻塞操作以及资源管理。通过案例分析展示了网络请求、图像处理和数据库操作的优化实践。同时,文章指出并发编程的挑战,如性能评估、调试及兼容性问题,并强调了多线程优化对提升应用性能的重要性。开发者应持续学习和探索新的优化策略,以适应移动应用市场的竞争需求。
162 5
|
6月前
|
Java Android开发
Android系统 获取用户最后操作时间回调实现和原理分析
Android系统 获取用户最后操作时间回调实现和原理分析
188 0
|
4月前
|
Java Android开发
Android面试题经典之Glide取消加载以及线程池优化
Glide通过生命周期管理在`onStop`时暂停请求,`onDestroy`时取消请求,减少资源浪费。在`EngineJob`和`DecodeJob`中使用`cancel`方法标记任务并中断数据获取。当网络请求被取消时,`HttpUrlFetcher`的`cancel`方法设置标志,之后的数据获取会返回`null`,中断加载流程。Glide还使用定制的线程池,如AnimationExecutor、diskCacheExecutor、sourceExecutor和newUnlimitedSourceExecutor,其中某些禁止网络访问,并根据CPU核心数动态调整线程数。
133 2
|
23天前
|
Android开发 UED
Android 中加载 Gif 动画
【10月更文挑战第20天】加载 Gif 动画是 Android 开发中的一项重要技能。通过使用第三方库或自定义实现,可以方便地在应用中展示生动的 Gif 动画。在实际应用中,需要根据具体情况进行合理选择和优化,以确保用户体验和性能的平衡。可以通过不断的实践和探索,进一步掌握在 Android 中加载 Gif 动画的技巧和方法,为开发高质量的 Android 应用提供支持。
|
2月前
|
存储 缓存 编解码
Android经典面试题之图片Bitmap怎么做优化
本文介绍了图片相关的内存优化方法,包括分辨率适配、图片压缩与缓存。文中详细讲解了如何根据不同分辨率放置图片资源,避免图片拉伸变形;并通过示例代码展示了使用`BitmapFactory.Options`进行图片压缩的具体步骤。此外,还介绍了Glide等第三方库如何利用LRU算法实现高效图片缓存。
65 20
Android经典面试题之图片Bitmap怎么做优化
|
3月前
|
存储 缓存 Java
Android项目架构设计问题之优化业务接口数据的加载效率如何解决
Android项目架构设计问题之优化业务接口数据的加载效率如何解决
45 0
|
3月前
|
Java Android开发 Kotlin
Android项目架构设计问题之要在Glide库中加载网络图片到ImageView如何解决
Android项目架构设计问题之要在Glide库中加载网络图片到ImageView如何解决
36 0
|
5月前
|
存储 Java Android开发
Android上在两个Activity之间传递Bitmap对象
Android上在两个Activity之间传递Bitmap对象
39 2
|
5月前
|
XML 前端开发 API
Android中实现Bitmap在自定义View中的放大与拖动
Android中实现Bitmap在自定义View中的放大与拖动
150 1
|
4月前
|
Android开发
Android kernel 操作gpio
Android kernel 操作gpio
43 0