Windows 7を使用している場合、なぜ画像で主要な色を見つけようとしているのか理解できます。タスクバーのプログラムにマウスを合わせると、アイコンの最も主要な色に基づいてそのプログラムの背景が変わります。私はこの手法が他のプログラムでも使用されていることに気付きましたが、私の頭上でそれらを思い出すことはできません。
これは、アプリケーションの開発に使用している多くのUIテクニックで役立つことがわかります。最も一般的な色を見つけるには、Android描画可能リソース.
Android 5.0 Lollipopでは、ビットマップから有用な色を抽出するのに役立つクラスが追加されました。Android.support.v7.graphicsにある Palette クラスは、抽出できます次の色:
このAndroidトレーニングページには、クラスを使用するために必要なすべての詳細が記載されています(私は自分でAndroid Studioで試しましたが、非常に簡単でした): http://developer.Android.com/training/material/drawables.html#ColorExtract
引用するには:
Android Support Library r21以降には、画像から顕著な色を抽出できる Palette クラスが含まれています。これらの色を抽出するには、ビットマップオブジェクトをパレットに渡します画像をロードするバックグラウンドスレッドの.generate()静的メソッド。そのスレッドを使用できない場合は、Palette.generateAsync()メソッドを呼び出して、代わりにリスナーを提供します。
Palette.getVibrantColorなどのPaletteクラスのゲッターメソッドを使用して、画像から目立つ色を取得できます。
プロジェクトでPaletteクラスを使用するには、次のGradle依存関係をアプリのモジュールに追加します。
dependencies { ... implementation 'com.Android.support:palette-v7:21.0.+' }
または、androidxを使用している場合:
implementation 'androidx.palette:palette:1.0.0'
generateAsync()を使用する必要がある場合の方法は次のとおりです:
Palette.generateAsync(bitmap, new Palette.PaletteAsyncListener() {
public void onGenerated(Palette palette) {
// Do something with colors...
}
});
編集:質問はドロウアブルリソースから色を抽出する方法を尋ねるので、最初に説明した手法を使用するには、ドロウアブルをビットマップに変換する必要があります。幸いなことに、BitmapFactoryを使用するのは非常に簡単です。
Bitmap icon = BitmapFactory.decodeResource(context.getResources(),
R.drawable.icon_resource);`
別の解決策もあります。これはより近似的な方法ですが、色の検索に長い遅延を与えたくない場合は、仕事をすることができます。
public static int getDominantColor(Bitmap bitmap) {
Bitmap newBitmap = Bitmap.createScaledBitmap(bitmap, 1, 1, true);
final int color = newBitmap.getPixel(0, 0);
newBitmap.recycle();
return color;
}
このクラスはビットマップを反復処理し、最も支配的な色を返します。必要に応じて、コードを自由にクリーンアップしてください。
_public class ImageColour {
String colour;
public ImageColour(Bitmap image) throws Exception {
int height = image.getHeight();
int width = image.getWidth();
Map m = new HashMap();
for(int i=0; i < width ; i++){
for(int j=0; j < height ; j++){
int rgb = image.getPixel(i, j);
int[] rgbArr = getRGBArr(rgb);
if (!isGray(rgbArr)) {
Integer counter = (Integer) m.get(rgb);
if (counter == null)
counter = 0;
counter++;
m.put(rgb, counter);
}
}
}
String colourHex = getMostCommonColour(m);
}
public static String getMostCommonColour(Map map) {
List list = new LinkedList(map.entrySet());
Collections.sort(list, new Comparator() {
public int compare(Object o1, Object o2) {
return ((Comparable) ((Map.Entry) (o1)).getValue())
.compareTo(((Map.Entry) (o2)).getValue());
}
});
Map.Entry me = (Map.Entry )list.get(list.size()-1);
int[] rgb= getRGBArr((Integer)me.getKey());
return Integer.toHexString(rgb[0])+" "+Integer.toHexString(rgb[1])+" "+Integer.toHexString(rgb[2]);
}
public static int[] getRGBArr(int pixel) {
int red = (pixel >> 16) & 0xff;
int green = (pixel >> 8) & 0xff;
int blue = (pixel) & 0xff;
return new int[]{red,green,blue};
}
public static boolean isGray(int[] rgbArr) {
int rgDiff = rgbArr[0] - rgbArr[1];
int rbDiff = rgbArr[0] - rgbArr[2];
int tolerance = 10;
if (rgDiff > tolerance || rgDiff < -tolerance)
if (rbDiff > tolerance || rbDiff < -tolerance) {
return false;
}
return true;
}
public String returnColour() {
if (colour.length() == 6) {
return colour.replaceAll("\\s", "");
} else {
return "ffffff";
}
}
_
16進数を取得するには、単にreturnColour();
を呼び出します
支配的な色を得るために独自のメソッドを作成しました。
方法1(私のテクニック)
ARGB_4444
色空間に縮小最大値と支配的なRGBカラーの組み合わせ
public int getDominantColor1(Bitmap bitmap) {
if (bitmap == null)
throw new NullPointerException();
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int size = width * height;
int pixels[] = new int[size];
Bitmap bitmap2 = bitmap.copy(Bitmap.Config.ARGB_4444, false);
bitmap2.getPixels(pixels, 0, width, 0, 0, width, height);
final List<HashMap<Integer, Integer>> colorMap = new ArrayList<HashMap<Integer, Integer>>();
colorMap.add(new HashMap<Integer, Integer>());
colorMap.add(new HashMap<Integer, Integer>());
colorMap.add(new HashMap<Integer, Integer>());
int color = 0;
int r = 0;
int g = 0;
int b = 0;
Integer rC, gC, bC;
for (int i = 0; i < pixels.length; i++) {
color = pixels[i];
r = Color.red(color);
g = Color.green(color);
b = Color.blue(color);
rC = colorMap.get(0).get(r);
if (rC == null)
rC = 0;
colorMap.get(0).put(r, ++rC);
gC = colorMap.get(1).get(g);
if (gC == null)
gC = 0;
colorMap.get(1).put(g, ++gC);
bC = colorMap.get(2).get(b);
if (bC == null)
bC = 0;
colorMap.get(2).put(b, ++bC);
}
int[] rgb = new int[3];
for (int i = 0; i < 3; i++) {
int max = 0;
int val = 0;
for (Map.Entry<Integer, Integer> entry : colorMap.get(i).entrySet()) {
if (entry.getValue() > max) {
max = entry.getValue();
val = entry.getKey();
}
}
rgb[i] = val;
}
int dominantColor = Color.rgb(rgb[0], rgb[1], rgb[2]);
return dominantColor;
}
方法2(古い手法)
ARGB_4444
色空間に縮小各色の出現を計算し、最大の色を支配的な色として見つける
public int getDominantColor2(Bitmap bitmap) {
if (bitmap == null)
throw new NullPointerException();
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int size = width * height;
int pixels[] = new int[size];
Bitmap bitmap2 = bitmap.copy(Bitmap.Config.ARGB_4444, false);
bitmap2.getPixels(pixels, 0, width, 0, 0, width, height);
HashMap<Integer, Integer> colorMap = new HashMap<Integer, Integer>();
int color = 0;
Integer count = 0;
for (int i = 0; i < pixels.length; i++) {
color = pixels[i];
count = colorMap.get(color);
if (count == null)
count = 0;
colorMap.put(color, ++count);
}
int dominantColor = 0;
int max = 0;
for (Map.Entry<Integer, Integer> entry : colorMap.entrySet()) {
if (entry.getValue() > max) {
max = entry.getValue();
dominantColor = entry.getKey();
}
}
return dominantColor;
}
すべてのピクセルのカラーデータをループし、カラー値を平均します。グレーの陰影または透明なものはすべて無視します。これは、最近のブログ投稿に基づいて、MicrosoftがWindows 7で行っていることだと思います。
編集
ブログの投稿: http://blogs.msdn.com/b/oldnewthing/archive/2011/12/06/10244432.aspx
Chromeが支配的な色を選択する方法を示すこのリンクも役立ちます。 http://www.quora.com/Google-Chrome/How-does-Chrome-pick-the -最も頻繁にアクセスされたページのサムネイル上の色のストライプ
Dominant/ Vibrant/Mutedを見つけるには画像の色、 パレット を使用:
import:
implementation 'androidx.palette:palette:1.0.0'
使用法:
val bitmap = BitmapFactory.decodeResource(resources, R.drawable.image)
Palette.Builder(bitmap).generate { it?.let { palette ->
val dominantColor = palette.getDominantColor(ContextCompat.getColor(context!!, R.color.defaultColor))
// TODO: use dominant color
} }
他の答えのどれも私のために仕事をしなかったし、問題の原因を除外しなかった。
これは私が最終的に使用したものです:
public static int getDominantColor(Bitmap bitmap) {
if (bitmap == null) {
return Color.TRANSPARENT;
}
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int size = width * height;
int pixels[] = new int[size];
//Bitmap bitmap2 = bitmap.copy(Bitmap.Config.ARGB_4444, false);
bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
int color;
int r = 0;
int g = 0;
int b = 0;
int a;
int count = 0;
for (int i = 0; i < pixels.length; i++) {
color = pixels[i];
a = Color.alpha(color);
if (a > 0) {
r += Color.red(color);
g += Color.green(color);
b += Color.blue(color);
count++;
}
}
r /= count;
g /= count;
b /= count;
r = (r << 16) & 0x00FF0000;
g = (g << 8) & 0x0000FF00;
b = b & 0x000000FF;
color = 0xFF000000 | r | g | b;
return color;
}
依存関係に追加
implementation 'androidx.palette:palette:1.0.0'
そして..
Bitmap bitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
Palette.from(bitmap).generate(palette -> {
int vibrant = palette.getVibrantColor(0x000000); // <=== color you want
int vibrantLight = palette.getLightVibrantColor(0x000000);
int vibrantDark = palette.getDarkVibrantColor(0x000000);
int muted = palette.getMutedColor(0x000000);
int mutedLight = palette.getLightMutedColor(0x000000);
int mutedDark = palette.getDarkMutedColor(0x000000);
});