ColorMatrix और ColorMatrixColorFilter के उपयोग को समझने के लिए एक ड्रॉ का ह्यू संशोधित करने के लिए


114

मैं एक ऐप के लिए UI पर काम कर रहा हूं, और मैं ग्रेस्केल आइकन का उपयोग करने का प्रयास कर रहा हूं, और उपयोगकर्ता को थीम को उनके चयन के रंग में बदलने की अनुमति देता हूं। ऐसा करने के लिए, मैं ड्रॉबल के ऊपर एक रंग को ओवरले करने के लिए किसी प्रकार का एक ColorFilter लगाने की कोशिश कर रहा हूं। मैंने PorterDuff.Mode.MULTIPLY का उपयोग करने की कोशिश की है, और यह लगभग मेरी ज़रूरत के अनुसार काम करता है, सिवाय इसके कि गोरे रंग के साथ ओवरले हो जाते हैं। मैं जो आदर्श रूप से देख रहा हूं वह फ़ोटोशॉप में "कलर" सम्मिश्रण मोड की तरह है, जहां ग्राफिक अपनी पारदर्शिता और चमक बनाए रखता है, और केवल छवि के रंग को संशोधित करता है। उदाहरण के लिए:

वैकल्पिक शब्दबन जाता हैवैकल्पिक शब्द

कुछ शोध करने के बाद, ऐसा प्रतीत होता है कि ColorMatrixColorFilter वर्ग वह कर सकता है जिसकी मुझे आवश्यकता है, लेकिन मुझे कोई संसाधन खोजने की आवश्यकता नहीं है जो यह बताता है कि मैट्रिक्स का उपयोग कैसे किया जाता है। यह एक 4x5 मैट्रिक्स है, लेकिन मुझे यह जानने की आवश्यकता है कि मैं मैट्रिक्स को कैसे डिज़ाइन करता हूं। कोई विचार?

संपादित करें: तो ठीक है, जो मैंने इस पर अब तक पाया है वह इस प्रकार है:

1 0 0 0 0 //red
0 1 0 0 0 //green
0 0 1 0 0 //blue
0 0 0 1 0 //alpha

जहां यह मैट्रिक्स पहचान मैट्रिक्स है (जब लागू किया जाता है, कोई परिवर्तन नहीं करता है), और संख्या 0 से 1 (फ़्लोट्स) तक होती है। इस मैट्रिक्स को नए रंग में बदलने के लिए प्रत्येक पिक्सेल के साथ गुणा किया जाएगा। तो यह वह जगह है जहाँ यह मेरे लिए फजी होने लगता है। इसलिए मुझे लगता है कि प्रत्येक पिक्सेल एक 1 x 4 वेक्टर होगा जिसमें आरजीबी मान (जैसे 0.2, 0.5, 0.8, 1) होगा जो कि परिवर्तन मैट्रिक्स के साथ बिंदीदार होगा। तो एक छवि की लाल तीव्रता को दोगुना करने के लिए, आप एक मैट्रिक्स का उपयोग करेंगे जैसे:

2 0 0 0 0 
0 1 0 0 0 
0 0 1 0 0 
0 0 0 1 0 

जो आपको एक वेक्टर (रंग) देगा 0.4, 0.5, 0.8, 1। सीमित परीक्षण से, यह मामला प्रतीत होता है, और ठीक से काम करता है, लेकिन मैं वास्तव में अभी भी एक ही समस्या (यानी सफेद रंग प्राप्त करता है) के साथ समाप्त होता है। आगे पढ़ने से मुझे पता चलता है कि यह इसलिए है क्योंकि यह आरजीबी मूल्यों पर रूपांतरण कर रहा है, जबकि ह्यू शिफ्टिंग के लिए, मूल्यों को पहले एचएसडी मूल्यों में परिवर्तित किया जाना चाहिए। इसलिए संभवतः मैं एक ऐसा वर्ग लिख सकता था जो छवि को पढ़ेगा और रंगों को रूपांतरित करेगा, और नए रंगों के साथ छवि को फिर से प्रकाशित करेगा। यह स्टेटलाइडड्रैबल्स के साथ ANOTHER की समस्या पैदा करता है, क्योंकि मुझे यकीन नहीं है कि मैं इनमें से प्रत्येक को कोड में लाने और उन सभी को संशोधित करने के बारे में कैसे जाऊंगा, और यह कितना धीमा होगा। : /

हम्म, ठीक है, इसलिए मुझे लगता है कि एक और सवाल मुझे लगता है कि क्या मैट्रिक्स का उपयोग आरजीबी को चमकदार रंग की जानकारी के साथ दूसरे रंग के स्थान पर परिवर्तित करने के लिए किया जा सकता है, जैसे कि एल एक बी या एचएसएल? यदि हां, तो मैं उस अभिसरण के लिए केवल मैट्रिक्स को गुणा कर सकता हूं, फिर THAT मैट्रिक्स के लिए ह्यू समायोजन करें, फिर उस मैट्रिक्स को ColorFilter के रूप में लागू करें।


5
इस विषय पर मुझे जो सबसे अच्छा लेख मिला वह यहां है: active.tutsplus.com/tutorials/effects/…
रिचर्ड लैंसेट

जवाबों:


77

यही मैं अपने खेल के लिए उपयोग करता हूं। यह वेबसाइटों पर विभिन्न लेखों पर पाए गए विभिन्न भाग का संकलन है। क्रेडिट्स मूल लेखक से @see लिंक पर जाता है। ध्यान दें कि रंग मैट्रेस के साथ और भी बहुत कुछ किया जा सकता है। सहित inverting, आदि ...

public class ColorFilterGenerator
{
    /**
 * Creates a HUE ajustment ColorFilter
 * @see http://groups.google.com/group/android-developers/browse_thread/thread/9e215c83c3819953
 * @see http://gskinner.com/blog/archives/2007/12/colormatrix_cla.html
 * @param value degrees to shift the hue.
 * @return
 */
public static ColorFilter adjustHue( float value )
{
    ColorMatrix cm = new ColorMatrix();

    adjustHue(cm, value);

    return new ColorMatrixColorFilter(cm);
}

/**
 * @see http://groups.google.com/group/android-developers/browse_thread/thread/9e215c83c3819953
 * @see http://gskinner.com/blog/archives/2007/12/colormatrix_cla.html
 * @param cm
 * @param value
 */
public static void adjustHue(ColorMatrix cm, float value)
{
    value = cleanValue(value, 180f) / 180f * (float) Math.PI;
    if (value == 0)
    {
        return;
    }
    float cosVal = (float) Math.cos(value);
    float sinVal = (float) Math.sin(value);
    float lumR = 0.213f;
    float lumG = 0.715f;
    float lumB = 0.072f;
    float[] mat = new float[]
    { 
            lumR + cosVal * (1 - lumR) + sinVal * (-lumR), lumG + cosVal * (-lumG) + sinVal * (-lumG), lumB + cosVal * (-lumB) + sinVal * (1 - lumB), 0, 0, 
            lumR + cosVal * (-lumR) + sinVal * (0.143f), lumG + cosVal * (1 - lumG) + sinVal * (0.140f), lumB + cosVal * (-lumB) + sinVal * (-0.283f), 0, 0,
            lumR + cosVal * (-lumR) + sinVal * (-(1 - lumR)), lumG + cosVal * (-lumG) + sinVal * (lumG), lumB + cosVal * (1 - lumB) + sinVal * (lumB), 0, 0, 
            0f, 0f, 0f, 1f, 0f, 
            0f, 0f, 0f, 0f, 1f };
    cm.postConcat(new ColorMatrix(mat));
}

protected static float cleanValue(float p_val, float p_limit)
{
    return Math.min(p_limit, Math.max(-p_limit, p_val));
}
}

इसे पूरा करने के लिए मुझे एक उदाहरण जोड़ना चाहिए:

ImageView Sun = (ImageView)findViewById(R.id.sun);
Sun.setColorFilter(ColorFilterGenerator.adjustHue(162)); // 162 degree rotation

4
यह सुनिश्चित करता है कि यह बाध्य नहीं है और कलाकृतियों का कारण नहीं है।
रिचर्ड लैंकेट पैतृक

1
@RichardLalancette क्या आप बता सकते हैं कि matआपके कोड में मैट्रिक्स की 5 पंक्तियाँ क्यों हैं? क्या यह केवल 4 पंक्तियाँ नहीं होनी चाहिए (प्रत्येक RGBA के लिए)?
.लोमबम्बो

1
@RichardLalancette के सोर्स कोड को देखने के बाद ColorMatrix, मैं इसे वापस लेता हूं। में अंतिम पंक्ति का matउपयोग कभी नहीं किया जाता है। ColorMatrixनिर्माता केवल पहले 4 पंक्तियाँ (प्रतियां दिए गए स्रोत मैट्रिक्स के पहले 20 तैरता) लेता है।
इलोमैंबो

2
मैंने सिर्फ 5 वीं पंक्ति के बिना इसका परीक्षण किया और परिणाम समान प्रतीत होते हैं।
मिगेल

2
फ्लोट ल्यूमर = 0.213 एफ क्या हैं; फ्लोट एलएमजी = 0.715 एफ; फ्लोट ल्यूमब = 0.072 एफ; और आपने उन मूल्यों को क्यों चुना है?
सुजय यूएन

43

यदि आप उज्ज्वल, कंट्रास्ट, संतृप्ति और रंग को समायोजित करना चाहते हैं तो यहां पूरा कोड है। का आनंद लें! @RichardLalancette को बहुत बहुत धन्यवाद

public class ColorFilterGenerator {

private static double DELTA_INDEX[] = {
    0,    0.01, 0.02, 0.04, 0.05, 0.06, 0.07, 0.08, 0.1,  0.11,
    0.12, 0.14, 0.15, 0.16, 0.17, 0.18, 0.20, 0.21, 0.22, 0.24,
    0.25, 0.27, 0.28, 0.30, 0.32, 0.34, 0.36, 0.38, 0.40, 0.42,
    0.44, 0.46, 0.48, 0.5,  0.53, 0.56, 0.59, 0.62, 0.65, 0.68, 
    0.71, 0.74, 0.77, 0.80, 0.83, 0.86, 0.89, 0.92, 0.95, 0.98,
    1.0,  1.06, 1.12, 1.18, 1.24, 1.30, 1.36, 1.42, 1.48, 1.54,
    1.60, 1.66, 1.72, 1.78, 1.84, 1.90, 1.96, 2.0,  2.12, 2.25, 
    2.37, 2.50, 2.62, 2.75, 2.87, 3.0,  3.2,  3.4,  3.6,  3.8,
    4.0,  4.3,  4.7,  4.9,  5.0,  5.5,  6.0,  6.5,  6.8,  7.0,
    7.3,  7.5,  7.8,  8.0,  8.4,  8.7,  9.0,  9.4,  9.6,  9.8, 
    10.0
};

/**
 * @see http://groups.google.com/group/android-developers/browse_thread/thread/9e215c83c3819953
 * @see http://gskinner.com/blog/archives/2007/12/colormatrix_cla.html
 * @param cm
 * @param value
 */
public static void adjustHue(ColorMatrix cm, float value)
{
    value = cleanValue(value, 180f) / 180f * (float) Math.PI;
    if (value == 0){
        return;
    }

    float cosVal = (float) Math.cos(value);
    float sinVal = (float) Math.sin(value);
    float lumR = 0.213f;
    float lumG = 0.715f;
    float lumB = 0.072f;
    float[] mat = new float[]
    { 
            lumR + cosVal * (1 - lumR) + sinVal * (-lumR), lumG + cosVal * (-lumG) + sinVal * (-lumG), lumB + cosVal * (-lumB) + sinVal * (1 - lumB), 0, 0, 
            lumR + cosVal * (-lumR) + sinVal * (0.143f), lumG + cosVal * (1 - lumG) + sinVal * (0.140f), lumB + cosVal * (-lumB) + sinVal * (-0.283f), 0, 0,
            lumR + cosVal * (-lumR) + sinVal * (-(1 - lumR)), lumG + cosVal * (-lumG) + sinVal * (lumG), lumB + cosVal * (1 - lumB) + sinVal * (lumB), 0, 0, 
            0f, 0f, 0f, 1f, 0f, 
            0f, 0f, 0f, 0f, 1f };
    cm.postConcat(new ColorMatrix(mat));
}

public static void adjustBrightness(ColorMatrix cm, float value) {
    value = cleanValue(value,100);
    if (value == 0) {
        return;
    }

    float[] mat = new float[]
    { 
        1,0,0,0,value,
        0,1,0,0,value,
        0,0,1,0,value,
        0,0,0,1,0,
        0,0,0,0,1
    };
    cm.postConcat(new ColorMatrix(mat));
}

public static void adjustContrast(ColorMatrix cm, int value) {
    value = (int)cleanValue(value,100);
    if (value == 0) { 
        return; 
    }
    float x;
    if (value < 0) {
        x = 127 + (float) value / 100*127;
    } else {
        x = value % 1;
        if (x == 0) {
            x = (float)DELTA_INDEX[value];
        } else {
            //x = DELTA_INDEX[(p_val<<0)]; // this is how the IDE does it.
            x = (float)DELTA_INDEX[(value<<0)]*(1-x) + (float)DELTA_INDEX[(value<<0)+1] * x; // use linear interpolation for more granularity.
        }
        x = x*127+127;
    }

    float[] mat = new float[]
    { 
            x/127,0,0,0, 0.5f*(127-x),
            0,x/127,0,0, 0.5f*(127-x),
            0,0,x/127,0, 0.5f*(127-x),
            0,0,0,1,0,
            0,0,0,0,1
    };
    cm.postConcat(new ColorMatrix(mat));

}

public static void adjustSaturation(ColorMatrix cm, float value) {
    value = cleanValue(value,100);
    if (value == 0) {
        return;
    }

    float x = 1+((value > 0) ? 3 * value / 100 : value / 100);
    float lumR = 0.3086f;
    float lumG = 0.6094f;
    float lumB = 0.0820f;

    float[] mat = new float[]
    { 
        lumR*(1-x)+x,lumG*(1-x),lumB*(1-x),0,0,
        lumR*(1-x),lumG*(1-x)+x,lumB*(1-x),0,0,
        lumR*(1-x),lumG*(1-x),lumB*(1-x)+x,0,0,
        0,0,0,1,0,
        0,0,0,0,1
    };
    cm.postConcat(new ColorMatrix(mat));
}



protected static float cleanValue(float p_val, float p_limit)
{
    return Math.min(p_limit, Math.max(-p_limit, p_val));
}

public static ColorFilter adjustColor(int brightness, int contrast, int saturation, int hue){
    ColorMatrix cm = new ColorMatrix();
    adjustHue(cm, hue);
    adjustContrast(cm, contrast);
    adjustBrightness(cm, brightness);
    adjustSaturation(cm, saturation);

    return new ColorMatrixColorFilter(cm);
}
}

क्या यह केवल एक रंग (नीला) के लिए संतृप्ति को बदलने के लिए उपलब्ध है?
फ़िलिप

"मान << 0" "मान" के समान है
अमीर उवाल

बहुमूल्य कोड के लिए धन्यवाद। आपकी adjustContrastविधि के बारे में दो टिप्पणियां : (1) अभिव्यक्ति value<<0बेमानी लगती है, क्योंकि यह हमेशा (बस) के बराबर होगी value(२) जैसा valueकि एक पूर्णांक है, value % 1हमेशा 0 के बराबर नहीं होगा ?
ब्लिस

चमक के लिए possbile मान श्रेणी गलत है। यह -255 और 255 के बीच होना चाहिए या बाद में परिवर्तित होना चाहिए।
woodii

12

किसी के लिए भी जो ColorMatrixColorFilter का उपयोग करने में रुचि रखता है। मैंने यहाँ जो नमूना इस्तेमाल किया है, वह कैनवास पर बिटमैप खींचने पर हर पिक्सेल को लाल रंग में बदल देता है।

कक्षा में टिप्पणी इस प्रकार है: http://developer.android.com/reference/android/graphics/ColorMatrix.html यह आपको कुछ अंतर्दृष्टि देता है कि यह कैसे काम कर रहा है

@Override
protected void onDraw(Canvas canvas) {

    // The matrix is stored in a single array, and its treated as follows: [ a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t ]
    // When applied to a color [r, g, b, a], the resulting color is computed as (after clamping) ;
    //   R' = a*R + b*G + c*B + d*A + e; 
    //   G' = f*R + g*G + h*B + i*A + j; 
    //   B' = k*R + l*G + m*B + n*A + o; 
    //   A' = p*R + q*G + r*B + s*A + t; 

    Paint paint = new Paint();
    float[] matrix = { 
        1, 1, 1, 1, 1, //red
        0, 0, 0, 0, 0, //green
        0, 0, 0, 0, 0, //blue
        1, 1, 1, 1, 1 //alpha
    };
    paint.setColorFilter(new ColorMatrixColorFilter(matrix));

    Rect source = new Rect(0, 0, 100, 100);
    Rect dest = new Rect(0, 0, 100, 100);

    Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.sampleimage);
    canvas.drawBitmap(bitmap , source, dest, paint);
}

आपके कोड ने मेरे मामले के लिए पूरी तरह से काम किया, जहां मुझे कुछ पीएनजी को रंग देने की आवश्यकता थी: gist.github.com/puelocesar/9710910 - धन्यवाद!
पाउलो सेसर

9

निम्न वर्ग उन उत्तरों पर एक सुधार है जो पहले ही पोस्ट किए जा चुके हैं। इससे पढ़ने और बनाने में आसानी ColorFilterहोती है Bitmap

उदाहरण उपयोग:

ImageView imageView = ...;
Drawable drawable = imageView.getDrawable();
ColorFilter colorFilter = ColorFilterGenerator.from(drawable).to(Color.RED);
imageView.setColorFilter(colorFilter);

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.PictureDrawable;
import android.widget.ImageView;

/**
 * Creates a {@link ColorMatrixColorFilter} to adjust the hue, saturation, brightness, or
 * contrast of an {@link Bitmap}, {@link Drawable}, or {@link ImageView}.
 * <p/>
 * Example usage:
 * <br/>
 * {@code imageView.setColorFilter(ColorFilterGenerator.from(Color.BLUE).to(Color.RED));}
 *
 * @author Jared Rummler <jared.rummler@gmail.com>
 */
public class ColorFilterGenerator {

  // Based off answer from StackOverflow
  // See: http://stackoverflow.com/a/15119089/1048340

  private ColorFilterGenerator() {
    throw new AssertionError();
  }

  public static From from(Drawable drawable) {
    return new From(drawableToBitmap(drawable));
  }

  public static From from(Bitmap bitmap) {
    return new From(bitmap);
  }

  public static From from(int color) {
    return new From(color);
  }

  // --------------------------------------------------------------------------------------------

  private static final double DELTA_INDEX[] = {
      0, 0.01, 0.02, 0.04, 0.05, 0.06, 0.07, 0.08, 0.1, 0.11, 0.12, 0.14, 0.15, 0.16, 0.17, 0.18,
      0.20, 0.21, 0.22, 0.24, 0.25, 0.27, 0.28, 0.30, 0.32, 0.34, 0.36, 0.38, 0.40, 0.42, 0.44,
      0.46, 0.48, 0.5, 0.53, 0.56, 0.59, 0.62, 0.65, 0.68, 0.71, 0.74, 0.77, 0.80, 0.83, 0.86, 0.89,
      0.92, 0.95, 0.98, 1.0, 1.06, 1.12, 1.18, 1.24, 1.30, 1.36, 1.42, 1.48, 1.54, 1.60, 1.66, 1.72,
      1.78, 1.84, 1.90, 1.96, 2.0, 2.12, 2.25, 2.37, 2.50, 2.62, 2.75, 2.87, 3.0, 3.2, 3.4, 3.6,
      3.8, 4.0, 4.3, 4.7, 4.9, 5.0, 5.5, 6.0, 6.5, 6.8, 7.0, 7.3, 7.5, 7.8, 8.0, 8.4, 8.7, 9.0, 9.4,
      9.6, 9.8, 10.0
  };

  public static void adjustHue(ColorMatrix cm, float value) {
    value = cleanValue(value, 180f) / 180f * (float) Math.PI;
    if (value == 0) {
      return;
    }

    float cosVal = (float) Math.cos(value);
    float sinVal = (float) Math.sin(value);
    float lumR = 0.213f;
    float lumG = 0.715f;
    float lumB = 0.072f;
    float[] mat = new float[]{
        lumR + cosVal * (1 - lumR) + sinVal * (-lumR),
        lumG + cosVal * (-lumG) + sinVal * (-lumG),
        lumB + cosVal * (-lumB) + sinVal * (1 - lumB), 0, 0,
        lumR + cosVal * (-lumR) + sinVal * (0.143f),
        lumG + cosVal * (1 - lumG) + sinVal * (0.140f),
        lumB + cosVal * (-lumB) + sinVal * (-0.283f), 0, 0,
        lumR + cosVal * (-lumR) + sinVal * (-(1 - lumR)),
        lumG + cosVal * (-lumG) + sinVal * (lumG),
        lumB + cosVal * (1 - lumB) + sinVal * (lumB), 0, 0, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f,
        0f, 1f
    };
    cm.postConcat(new ColorMatrix(mat));
  }

  public static void adjustBrightness(ColorMatrix cm, float value) {
    value = cleanValue(value, 100);
    if (value == 0) {
      return;
    }

    float[] mat = new float[]{
        1, 0, 0, 0, value, 0, 1, 0, 0, value, 0, 0, 1, 0, value, 0, 0, 0, 1, 0, 0, 0, 0, 0,
        1
    };
    cm.postConcat(new ColorMatrix(mat));
  }

  public static void adjustContrast(ColorMatrix cm, int value) {
    value = (int) cleanValue(value, 100);
    if (value == 0) {
      return;
    }
    float x;
    if (value < 0) {
      x = 127 + value / 100 * 127;
    } else {
      x = value % 1;
      if (x == 0) {
        x = (float) DELTA_INDEX[value];
      } else {
        x = (float) DELTA_INDEX[(value << 0)] * (1 - x)
            + (float) DELTA_INDEX[(value << 0) + 1] * x;
      }
      x = x * 127 + 127;
    }

    float[] mat = new float[]{
        x / 127, 0, 0, 0, 0.5f * (127 - x), 0, x / 127, 0, 0, 0.5f * (127 - x), 0, 0,
        x / 127, 0, 0.5f * (127 - x), 0, 0, 0, 1, 0, 0, 0, 0, 0, 1
    };
    cm.postConcat(new ColorMatrix(mat));

  }

  public static void adjustSaturation(ColorMatrix cm, float value) {
    value = cleanValue(value, 100);
    if (value == 0) {
      return;
    }

    float x = 1 + ((value > 0) ? 3 * value / 100 : value / 100);
    float lumR = 0.3086f;
    float lumG = 0.6094f;
    float lumB = 0.0820f;

    float[] mat = new float[]{
        lumR * (1 - x) + x, lumG * (1 - x), lumB * (1 - x), 0, 0, lumR * (1 - x),
        lumG * (1 - x) + x, lumB * (1 - x), 0, 0, lumR * (1 - x), lumG * (1 - x),
        lumB * (1 - x) + x, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1
    };
    cm.postConcat(new ColorMatrix(mat));
  }

  // --------------------------------------------------------------------------------------------

  private static float cleanValue(float p_val, float p_limit) {
    return Math.min(p_limit, Math.max(-p_limit, p_val));
  }

  private static float[] getHsv(int color) {
    float[] hsv = new float[3];
    Color.RGBToHSV(Color.red(color), Color.green(color), Color.blue(color), hsv);
    return hsv;
  }

  /**
   * Converts a {@link Drawable} to a {@link Bitmap}
   *
   * @param drawable
   *     The {@link Drawable} to convert
   * @return The converted {@link Bitmap}.
   */
  private static Bitmap drawableToBitmap(Drawable drawable) {
    if (drawable instanceof BitmapDrawable) {
      return ((BitmapDrawable) drawable).getBitmap();
    } else if (drawable instanceof PictureDrawable) {
      PictureDrawable pictureDrawable = (PictureDrawable) drawable;
      Bitmap bitmap = Bitmap.createBitmap(pictureDrawable.getIntrinsicWidth(),
          pictureDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
      Canvas canvas = new Canvas(bitmap);
      canvas.drawPicture(pictureDrawable.getPicture());
      return bitmap;
    }
    int width = drawable.getIntrinsicWidth();
    width = width > 0 ? width : 1;
    int height = drawable.getIntrinsicHeight();
    height = height > 0 ? height : 1;
    Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);
    drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
    drawable.draw(canvas);
    return bitmap;
  }

  /**
   * Calculate the average red, green, blue color values of a bitmap
   *
   * @param bitmap
   *     a {@link Bitmap}
   * @return
   */
  private static int[] getAverageColorRGB(Bitmap bitmap) {
    int width = bitmap.getWidth();
    int height = bitmap.getHeight();
    int size = width * height;
    int[] pixels = new int[size];
    int r, g, b;
    r = g = b = 0;
    bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
    for (int i = 0; i < size; i++) {
      int pixelColor = pixels[i];
      if (pixelColor == Color.TRANSPARENT) {
        size--;
        continue;
      }
      r += Color.red(pixelColor);
      g += Color.green(pixelColor);
      b += Color.blue(pixelColor);
    }
    r /= size;
    g /= size;
    b /= size;
    return new int[]{
        r, g, b
    };
  }

  /**
   * Calculate the average color value of a bitmap
   *
   * @param bitmap
   *     a {@link Bitmap}
   * @return
   */
  private static int getAverageColor(Bitmap bitmap) {
    int[] rgb = getAverageColorRGB(bitmap);
    return Color.argb(255, rgb[0], rgb[1], rgb[2]);
  }

  // Builder
  // --------------------------------------------------------------------------------------------

  public static final class Builder {

    int hue;

    int contrast;

    int brightness;

    int saturation;

    public Builder setHue(int hue) {
      this.hue = hue;
      return this;
    }

    public Builder setContrast(int contrast) {
      this.contrast = contrast;
      return this;
    }

    public Builder setBrightness(int brightness) {
      this.brightness = brightness;
      return this;
    }

    public Builder setSaturation(int saturation) {
      this.saturation = saturation;
      return this;
    }

    public ColorFilter build() {
      ColorMatrix cm = new ColorMatrix();
      adjustHue(cm, hue);
      adjustContrast(cm, contrast);
      adjustBrightness(cm, brightness);
      adjustSaturation(cm, saturation);
      return new ColorMatrixColorFilter(cm);
    }
  }

  public static final class From {

    final int oldColor;

    private From(Bitmap bitmap) {
      oldColor = getAverageColor(bitmap);
    }

    private From(int oldColor) {
      this.oldColor = oldColor;
    }

    public ColorFilter to(int newColor) {
      float[] hsv1 = getHsv(oldColor);
      float[] hsv2 = getHsv(newColor);
      int hue = (int) (hsv2[0] - hsv1[0]);
      int saturation = (int) (hsv2[1] - hsv1[1]);
      int brightness = (int) (hsv2[2] - hsv1[2]);
      return new ColorFilterGenerator.Builder()
          .setHue(hue)
          .setSaturation(saturation)
          .setBrightness(brightness)
          .build();
    }
  }

}

8

ह्यू और आरजीबी के बीच कोई रैखिक संबंध नहीं है। Hue को 60 ° chunks ( http://en.wikipedia.org/wiki/HSL_color_space#General_approach ) में टुकड़ों के रूप में परिभाषित किया गया है , और इसलिए HSV और RGB के बीच एक सरल मैट्रिक्स रूपांतरण नहीं है। छवि का रंग बदलने के लिए, आप निम्न विधि का उपयोग कर सकते हैं:

public Bitmap changeHue( Bitmap source, double hue ) {
    Bitmap result = Bitmap.createBitmap( source.getWidth(), source.getHeight(), source.getConfig() );

    float[] hsv = new float[3];
    for( int x = 0; x < source.getWidth(); x++ ) {
        for( int y = 0; y < source.getHeight(); y++ ) {
            int c = source.getPixel( x, y );
            Color.colorToHSV( c, hsv );
            hsv[0] = (float) ((hsv[0] + 360 * hue) % 360);
            c = (Color.HSVToColor( hsv ) & 0x00ffffff) | (c & 0xff000000);
            result.setPixel( x, y, c );
        }
    }

    return result;
}

7

मुझे लगता है कि यह विधि आपको वही देगी जो आप चाहते हैं:

http://android.okhelp.cz/hue-color-colored-filter-bitmap-image-android-example/

bitmapOrg.setColorFilter(Color.RED, PorterDuff.Mode.MULTIPLY);

1
ध्यान देने के लिए, यह विधि उसी तरह से नहीं बदलेगी जैसे कि ऊपर दिखाए गए ColorFilterGenerator तरीके। यह देखने के लिए कि यह फ़ोटोशॉप या जीआईएमपी में आपके बिटमैप को क्या उत्पन्न कर सकता है। छवि के ऊपर एक परत बनाएं और इसे अपने इच्छित रंग से भरें। फिर ओवरले की परत मोड को गुणा करने के लिए सेट करें। ColorFilterGenerator तरीकों का पूर्वावलोकन करने के लिए ह्यू करने के लिए लेयर मोड को सी करें।
केविन मार्क

6

बाकी उत्तरों की तरह मैंने इस व्यवहार को लागू करने के लिए एक रंग मैट्रिक्स का उपयोग किया, लेकिन आप एक नियमित एंड्रॉइड रंग संसाधन में पास कर सकते हैं। मैट्रिक्स, छवि मान और सफेद के बीच की सीमा में रंग को मैप करता है।

/**
 * Color everything that isn't white, the tint color
 * @param tintColor the color to tint the icon
 */
public void setInverseMultiplyFilter(Drawable imgCopy, @ColorInt int tintColor) {

    Drawable imgCopy = imageView.getDrawable().getConstantState().newDrawable();

    float colorRed = Color.red(tintColor) / 255f;
    float colorGreen = Color.green(tintColor) / 255f;
    float colorBlue = Color.blue(tintColor) / 255f;

    imgCopy.setColorFilter(new ColorMatrixColorFilter(new ColorMatrix(new float[]{
            1 - colorRed, 0,              0,             0,     colorRed * 255,
            0,            1 - colorGreen, 0,             0,     colorGreen * 255,
            0,            0,              1 - colorBlue, 0,     colorBlue * 255,
            0,            0,              0,             Color.alpha(tintColor) / 255f, 0,
    })));

    imageView.setImageDrawable(imgCopy);
    imageView.invalidate();
}

हैलो बेंजामिन, उपरोक्त मैट्रिक्स का उपयोग करके हम ग्रीन को छोड़कर सब कुछ टिंट कर सकते हैं? और क्या हम एक से अधिक रंगों को संरक्षित करने के लिए जोड़ सकते हैं? उदाहरण सफेद और हरे, टिंट बाकी को संरक्षित करते हैं। कृपया अपने उत्तर में मेरी मदद करेंगे
user954299

2

मैंने निम्न स्निपेट के आधार पर थोड़ा ColorMatrixFilter टेस्टर बनाया:

private Bitmap setColorFilter(Bitmap drawable) {                
            Bitmap grayscale  = Bitmap.createBitmap(drawable.getWidth(), drawable.getHeight(), drawable.getConfig());
            //if(isRenderMode) bOriginal.recycle();
            Canvas c = new Canvas(grayscale );
            Paint p = new Paint();

            final ColorMatrix matrixA = new ColorMatrix();
            matrixA.setSaturation(sauturationValue/2);


            float[] mx = {
                    r1Value,  r2Value,  r3Value,  r4Value,  r5Value,
                    g1Value,  g2Value,  g3Value,  g4Value,  g5Value,
                    b1Value,  b2Value,  b3Value,  b4Value,  b5Value,
                    a1Value,  a2Value,  a3Value,  a4Value,  a5Value
                    };
                    final ColorMatrix matrixB = new ColorMatrix(mx);

            matrixA.setConcat(matrixB, matrixA);

            final ColorMatrixColorFilter filter = new ColorMatrixColorFilter(matrixA);
            p.setColorFilter(filter);
            c.drawBitmap(drawable, 0, 0, p);
            return grayscale;               
        } 

आप इसे यहां देख सकते हैं: https://play.google.com/store/apps/details?id=org.vaelostudio.colormatrixtester


1

भले ही ColorMatrixमैं व्यक्तिगत रूप से उपयोग करने ColorMap[]के साथ-साथ उपयोग करने पर विचार करके बहुत सारे उपयोगी प्रभाव प्राप्त कर सकता हूं ImageAttributes। ऐसा करने से हम यह परिभाषित कर सकते हैं कि कौन से रंगों को किन रंगों से बदला जाना चाहिए।


क्या है ColorMap? मुझे लगता है कि मानक java / android libs में ऐसा कोई वर्ग उपलब्ध नहीं है।
ılǝ

1

जिस तरह से मैंने इसे हल किया वह एक ग्रे स्केल छवि के साथ शुरू करना है।

मूल ---> ग्रेइमेज

आप इसे फ़ोटोशॉप में आसानी से कर सकते हैं, या यदि आपको इसे कोड में करने की आवश्यकता है तो आप निम्न विधि का उपयोग कर सकते हैं।

private fun changeImageToGreyScale() {
   val matrix = ColorMatrix()
   matrix.setSaturation(0f)

   val originalBitmap = BitmapFactory.decodeResource(resources, originalImageID)
   val bitmapCopy = Bitmap.createBitmap(originalBitmap.width, 
   originalBitmap.height, Bitmap.Config.ARGB_8888)
   val canvas = Canvas(bitmapCopy)

   val paint = Paint()
   val colorFilter = ColorMatrixColorFilter(matrix)
   paint.colorFilter = colorFilter
   canvas.drawBitmap(originalBitmap, 0f, 0f, paint)
   grayScaleImage = bitmapCopy
}

आपके पास अपनी ग्रेस्केल छवि होने के बाद आप वांछित रंग जोड़ने के लिए पोर्टरडफ ऑवरले मोड का उपयोग कर सकते हैं।

private fun applyFilterToImage() {

    val bitmapCopy = Bitmap.createBitmap(grayScaleImage.width, grayScaleImage.height, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(bitmapCopy)

    val rnd = java.util.Random()
    val randomColor = Color.rgb(rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256))

    val paint = Paint()
    val porterDuffMode = PorterDuff.Mode.OVERLAY
    paint.colorFilter = PorterDuffColorFilter(randomColor, porterDuffMode)

    val maskPaint = Paint()
    maskPaint. xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_ATOP)

    canvas.drawBitmap(grayScaleImage, 0f, 0f, paint) 

    /**
    Note OVERLAY will disregard the alpha channel and will turn transparent 
    pixels into the randomColor. To resolve this I clip out that transparent area by 
    drawing the image again with the DST_ATOP XferMode
    **/
    canvas.drawBitmap(grayScaleImage, 0f, 0f, maskPaint)

    imageView.setImageBitmap(bitmapCopy)
}

उपरोक्त परिणाम randomColorGif निम्नानुसार है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.