【问题标题】:How to programmatically change contrast of a bitmap in android?如何以编程方式更改 android 中位图的对比度?
【发布时间】:2012-10-05 04:26:00
【问题描述】:

我想以编程方式更改位图的对比度。到现在我都试过了。

private Bitmap adjustedContrast(Bitmap src, double value)
    {
        // image size
        int width = src.getWidth();
        int height = src.getHeight();
        // create output bitmap
        Bitmap bmOut = Bitmap.createBitmap(width, height, src.getConfig());
        // color information
        int A, R, G, B;
        int pixel;
        // get contrast value
        double contrast = Math.pow((100 + value) / 100, 2);

        // scan through all pixels
        for(int x = 0; x < width; ++x) {
            for(int y = 0; y < height; ++y) {
                // get pixel color
                pixel = src.getPixel(x, y);
                A = Color.alpha(pixel);
                // apply filter contrast for every channel R, G, B
                R = Color.red(pixel);
                R = (int)(((((R / 255.0) - 0.5) * contrast) + 0.5) * 255.0);
                if(R < 0) { R = 0; }
                else if(R > 255) { R = 255; }

                G = Color.green(pixel);
                G = (int)(((((G / 255.0) - 0.5) * contrast) + 0.5) * 255.0);
                if(G < 0) { G = 0; }
                else if(G > 255) { G = 255; }

                B = Color.blue(pixel);
                B = (int)(((((B / 255.0) - 0.5) * contrast) + 0.5) * 255.0);
                if(B < 0) { B = 0; }
                else if(B > 255) { B = 255; }

                // set new pixel color to output bitmap
                bmOut.setPixel(x, y, Color.argb(A, R, G, B));
            }
        }
        return bmOut;
    }

但这并没有按预期工作。请帮助我或提供任何其他解决方案来实现这一目标。提前致谢。

【问题讨论】:

  • 什么不能按预期工作?请详细说明哪些有效,哪些无效。

标签: android image-processing bitmap contrast


【解决方案1】:

这里是完整的方法:

/**
 * 
 * @param bmp input bitmap
 * @param contrast 0..10 1 is default
 * @param brightness -255..255 0 is default
 * @return new bitmap
 */
public static Bitmap changeBitmapContrastBrightness(Bitmap bmp, float contrast, float brightness)
{
    ColorMatrix cm = new ColorMatrix(new float[]
            {
                contrast, 0, 0, 0, brightness,
                0, contrast, 0, 0, brightness,
                0, 0, contrast, 0, brightness,
                0, 0, 0, 1, 0
            });

    Bitmap ret = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), bmp.getConfig());

    Canvas canvas = new Canvas(ret);

    Paint paint = new Paint();
    paint.setColorFilter(new ColorMatrixColorFilter(cm));
    canvas.drawBitmap(bmp, 0, 0, paint);

    return ret;
}

【讨论】:

  • 这是迄今为止我发现的最快的解决方案。可能只有基于渲染脚本的会更快......
  • 太棒了,这个方法处理我的图像大约需要一秒钟,上面的方法大约需要 20 秒。
  • 对比度和亮度的最大值和最小值是多少。我使用 -255 t0 255 作为亮度,使用 -100 到 100 作为对比度,但我得到了错误的结果。我也尝试使用值 0 来表示对比度,而亮度值则为黑色图像。请帮帮我。我知道这是最快的方法,但它给了我错误的结果,肯定我做错了什么,如果有人纠正我会很好。
  • 由于 bmp.getConfig 的不断中断,只是对代码的改进... Bitmap.Config config = src.getConfig(); if (config == null) { config = Bitmap.Config.ARGB_8888; } 位图 ret = Bitmap.createBitmap(src.getWidth(), src.getHeight(), config);
  • 如果我们通过 silder 改变亮度,这将创建 OutOfMemory
【解决方案2】:

试试这个。您的代码不起作用,因为您只创建了一个可变位图,并且如果我没记错的话,并没有将源位图的图像复制到可变位图。

希望对你有帮助:)

private Bitmap adjustedContrast(Bitmap src, double value)
{
    // image size
    int width = src.getWidth();
    int height = src.getHeight();
    // create output bitmap

    // create a mutable empty bitmap
    Bitmap bmOut = Bitmap.createBitmap(width, height, src.getConfig());

    // create a canvas so that we can draw the bmOut Bitmap from source bitmap
    Canvas c = new Canvas();
    c.setBitmap(bmOut);

    // draw bitmap to bmOut from src bitmap so we can modify it
    c.drawBitmap(src, 0, 0, new Paint(Color.BLACK));


    // color information
    int A, R, G, B;
    int pixel;
    // get contrast value
    double contrast = Math.pow((100 + value) / 100, 2);

    // scan through all pixels
    for(int x = 0; x < width; ++x) {
        for(int y = 0; y < height; ++y) {
            // get pixel color
            pixel = src.getPixel(x, y);
            A = Color.alpha(pixel);
            // apply filter contrast for every channel R, G, B
            R = Color.red(pixel);
            R = (int)(((((R / 255.0) - 0.5) * contrast) + 0.5) * 255.0);
            if(R < 0) { R = 0; }
            else if(R > 255) { R = 255; }

            G = Color.green(pixel);
            G = (int)(((((G / 255.0) - 0.5) * contrast) + 0.5) * 255.0);
            if(G < 0) { G = 0; }
            else if(G > 255) { G = 255; }

            B = Color.blue(pixel);
            B = (int)(((((B / 255.0) - 0.5) * contrast) + 0.5) * 255.0);
            if(B < 0) { B = 0; }
            else if(B > 255) { B = 255; }

            // set new pixel color to output bitmap
            bmOut.setPixel(x, y, Color.argb(A, R, G, B));
        }
    }
    return bmOut;
}

【讨论】:

  • 谢谢,但我认为我们在这里不需要Canvas -- 我们正在直接写入位图bmOut
  • 什么是最大值和最小值可以用这个值更新你的答案
【解决方案3】:

我们可以使用seek bar来调整对比度。

MainActivity.java:

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    ImageView imageView;
    SeekBar seekbar;
    TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imageView = (ImageView) findViewById(R.id.image);
        textView = (TextView) findViewById(R.id.label);

        seekbar = (SeekBar) findViewById(R.id.seekbar);
        seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean b) {
                imageView.setImageBitmap(changeBitmapContrastBrightness(BitmapFactory.decodeResource(getResources(), R.drawable.lhota), (float) progress / 100f, 1));
                textView.setText("Contrast: "+(float) progress / 100f);
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {}

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {}
        });

        seekbar.setMax(200);
        seekbar.setProgress(100);
    }

    public static Bitmap changeBitmapContrastBrightness(Bitmap bmp, float contrast, float brightness) {
        ColorMatrix cm = new ColorMatrix(new float[]
                {
                        contrast, 0, 0, 0, brightness,
                        0, contrast, 0, 0, brightness,
                        0, 0, contrast, 0, brightness,
                        0, 0, 0, 1, 0
                });

        Bitmap ret = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), bmp.getConfig());

        Canvas canvas = new Canvas(ret);

        Paint paint = new Paint();
        paint.setColorFilter(new ColorMatrixColorFilter(cm));
        canvas.drawBitmap(bmp, 0, 0, paint);

        return ret;
    }
}

activity_main.java:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/image"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/label"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="8dp"
        android:textAppearance="@android:style/TextAppearance.Holo.Medium" />

    <SeekBar
        android:id="@+id/seekbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

【讨论】:

    【解决方案4】:

    这是一个 Renderscript 实现 (from the Gradle Example Projects)

    ip.rsh

    #pragma version(1)
    #pragma rs java_package_name(your.app.package)
    

    对比.rs

    #include "ip.rsh"
    
    static float brightM = 0.f;
    static float brightC = 0.f;
    
    void setBright(float v) {
        brightM = pow(2.f, v / 100.f);
        brightC = 127.f - brightM * 127.f;
    }
    
    void contrast(const uchar4 *in, uchar4 *out)
    {
    #if 0
        out->r = rsClamp((int)(brightM * in->r + brightC), 0, 255);
        out->g = rsClamp((int)(brightM * in->g + brightC), 0, 255);
        out->b = rsClamp((int)(brightM * in->b + brightC), 0, 255);
    #else
        float3 v = convert_float3(in->rgb) * brightM + brightC;
        out->rgb = convert_uchar3(clamp(v, 0.f, 255.f));
    #endif
    }
    

    Java

    private Bitmap changeBrightness(Bitmap original RenderScript rs) {
        Allocation input = Allocation.createFromBitmap(rs, original);
        final Allocation output = Allocation.createTyped(rs, input.getType());
        ScriptC_contrast mScript = new ScriptC_contrast(rs);
        mScript.invoke_setBright(50.f);
        mScript.forEach_contrast(input, output);
        output.copyTo(original);
        return original;
    }
    

    【讨论】:

    • 你能发布更多完整的例子吗?
    • 该示例非常完整,要集成它,请参见页面底部的完整项目链接
    • 无论如何你可以发布完整项目的直接链接吗? :) 我只找到一个链接,它不可用
    • 他们好像把项目的链接去掉了,随便搜一下如何用renderscript创建app,剩下的应该都清楚了
    【解决方案5】:

    假设 - ImageView 用于显示位图

    我在 Ruslan 的回答中做了更多的改进

    我们可以在 ImageView 的 Color Filter 上工作,而不是每次都替换 bitmap(如果您使用搜索栏会变慢)。

    float contrast;
    float brightness = 0;
    ImageView imageView;
    
    // SeekBar ranges from 0 to 90
    // contrast ranges from 1 to 10  
    mSeekBarContrast.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
                contrast = (float) (i + 10) / 10;
                // Changing the contrast of the bitmap
                imageView.setColorFilter(getContrastBrightnessFilter(contrast,brightness));
            }
    
            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
    
            }
    
            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
    
            }
    });
    
    ColorMatrixColorFilter getContrastBrightnessFilter(float contrast, float brightness) {
        ColorMatrix cm = new ColorMatrix(new float[]
                {
                        contrast, 0, 0, 0, brightness,
                        0, contrast, 0, 0, brightness,
                        0, 0, contrast, 0, brightness,
                        0, 0, 0, 1, 0
                });
        return new ColorMatrixColorFilter(cm);
    }
    

    P.S - 使用此方法也可以更改亮度和对比度

    【讨论】:

      【解决方案6】:

      我刚遇到同样的问题,最终使用了 Ruslan Yanchyshyn 描述的Color Matrix。我需要根据图像自动调整亮度,因此我使用 BoofCV 从图像的缩放版本创建直方图 - 处理整个图像需要很长时间。然后我分析了直方图 - 查看最暗和最亮的颜色,然后创建一个颜色矩阵来转换颜色,使最暗的颜色为 0,最亮的颜色为 255。这样,新图像使用了从黑暗开始的整个光谱现在/黑色到浅色/白色。

      如果有人感兴趣的话,最后在我们公司的博客上写了一篇关于我是如何做到的小帖子。 http://appdictive.dk/blog/projects/2016/07/26/levels_with_color_matrix/

      【讨论】:

        【解决方案7】:

        也许你可以试试这个:

        http://xjaphx.wordpress.com/2011/06/21/image-processing-contrast-image-on-the-fly/

        希望对您有所帮助! :)

        【讨论】:

        • 感谢您的回复。我试过这个。但是此代码仅适用于画布,我无法从画布中检索更改的图像。那么有没有其他办法呢。
        • 我编辑了上面的链接。我希望这对您的情况更有帮助。 :)
        • 我上面给出的代码是一样的。它总是使我的图像变成黑白的,并且不会恢复到原来的颜色。请提供其他任何内容。
        【解决方案8】:

        http://android.okhelp.cz/bitmap-set-contrast-and-brightness-android/

        看看这个,这可能会解决你的问题

        【讨论】:

          猜你喜欢
          • 2011-03-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-08-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-11-21
          相关资源
          最近更新 更多