Can we find which color is dominant in an image using Java, ImageMagick, or JMagick?

- 18,032
- 13
- 118
- 133

- 1,383
- 4
- 18
- 34
-
Do you mean the most used shade in the image or the average color? – Alexis Dufrenoy Jun 21 '12 at 08:19
7 Answers
in java iterate on each pixel and determine color
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
public class ImageTester {
public static void main(String args[]) throws Exception {
File file = new File("C:\\Users\\Andrew\\Desktop\\myImage.gif");
ImageInputStream is = ImageIO.createImageInputStream(file);
Iterator iter = ImageIO.getImageReaders(is);
if (!iter.hasNext())
{
System.out.println("Cannot load the specified file "+ file);
System.exit(1);
}
ImageReader imageReader = (ImageReader)iter.next();
imageReader.setInput(is);
BufferedImage image = imageReader.read(0);
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.getRGB(i, j);
int[] rgbArr = getRGBArr(rgb);
// Filter out grays....
if (!isGray(rgbArr)) {
Integer counter = (Integer) m.get(rgb);
if (counter == null)
counter = 0;
counter++;
m.put(rgb, counter);
}
}
}
String colourHex = getMostCommonColour(m);
System.out.println(colourHex);
}
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 alpha = (pixel >> 24) & 0xff;
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];
// Filter out black, white and grays...... (tolerance within 10 pixels)
int tolerance = 10;
if (rgDiff > tolerance || rgDiff < -tolerance)
if (rbDiff > tolerance || rbDiff < -tolerance) {
return false;
}
return true;
}
}

- 4,236
- 3
- 19
- 30
I just released a very simple algorithm that can be translated in Java trivially. It is called color-finder and works in JavaScript.
The proposed solutions in this thread can be thrown off by a few white characters in the image, whereas mine really tries to find the most prominent color, even if all the pixels aren't really exactly of the same color.
Let me know if you find that useful.

- 999
- 7
- 15
-
Hi @pieroxy, this looks promising - yet the translation to Java doesn't feel that trivial to me - at least on first glimpse :-) – Jan May 06 '20 at 12:58
This is a tricky problem. For example, if you have a small area of exactly the same colour and a large area of slightly different shades of a different colour then simply looking for the colour that is used the most is unlikely to give you result you want. You would get a better result by defining a set of colours and, for each, the ranges of RGB values that you consider to 'be' that colour.
This topic is discussed at length on the ImageMagick discourse server, for example: http://www.imagemagick.org/discourse-server/viewtopic.php?f=1&t=12878

- 1
- 1

- 3,386
- 1
- 24
- 29
Using plain java you can just iterate over each pixel and count how often each color is contained...
pseudo-code:
Map<Color, Integer> color2counter;
for (x : width) {
for (y : height) {
color = image.getPixel(x, y)
occurrences = color2counter.get(color)
color2counter.put(color, occurrences + 1)
}
}

- 38,985
- 14
- 88
- 103
We can use Material color utilities library which is currently available for Java/Kotlin, C++, Dart, TypeScript.
The colors may not necessarily be the most frequent colors but dominant colors appropriate for Material 3 design system and appropriate to be used on light or dark themes in apps.
The library is primarily used on apps for Android 12 and above and also on the Material Design website itself but I tested it for myself and got good results.
To use it, copy-paste the code on the Material color utilities repository for your desired language to your project and then you can extract dominant colors and color schemes.
Here is an example for Java and Kotlin:
Java:
var MAX_DESIRED_COLOR_COUNT = 128;
var file = new File("my-image.jpg");
var image = ImageIO.read(file);
var pixels = image.getRGB(0, 0, image.getWidth(), image.getHeight(), null, 0, image.getWidth());
var colorFrequency = QuantizerCelebi.quantize(pixels, MAX_DESIRED_COLOR_COUNT);
var decentColors = Score.score(colorFrequency);
var desiredColor = decentColors.get(0);
// You can take the desiredColor or any other decentColors and forget the rest of code below
// Could also use Scheme.dark(desiredColor); to get colors suitable for dark themes
var colorScheme = Scheme.light(desiredColor);
System.out.println("Decent colors: " + decentColors);
System.out.println("Primary color (light theme): " + colorScheme.getPrimary());
Kotlin:
val MAX_DESIRED_COLOR_COUNT = 128
val file = File("my-image.jpg")
val image = ImageIO.read(file)
val pixels = image.getRGB(0, 0, image.width, image.height, null, 0, image.width)
val colorFrequency = QuantizerCelebi.quantize(pixels, MAX_DESIRED_COLOR_COUNT)
val decentColors = Score.score(colorFrequency)
val desiredColor = decentColors.first()
// You can take the desiredColor or any other decentColors and forget the rest of code below
// Could also use Scheme.dark(desiredColor) to get colors suitable for dark themes
val colorScheme = Scheme.light(desiredColor)
println("Decent colors: ${decentColors.joinToString { it.toHexString() }}")
println("Primary color (light theme): ${colorScheme.primary.toHexString()}")
fun Int.toHexString() = "#%06X".format(this and 0xFFFFFF)
Learn more about Material Design color system and color roles here (like colorScheme.primary
used in the above code snippets).

- 18,032
- 13
- 118
- 133
assuming your using additive color scheme, where (0,0,0) is black and (255, 255, 255) is white (correct me if i'm mistaken). Also, if you just want to find the dominant color out of RGB:
One idea I have, which any of you are free to scrutinize is to have 3 variables that each store one of the RGB values and add to each of them the appropriate value of every pixel in the image and then divide by (255*numOfPixels) to get a ratio of color. Then compare the 3 ratios: .60 for red and .5 for green would mean red is more dominant.
This is just an idea, and might need tweaking...

- 770
- 2
- 8
- 17
-
i used jamagick for which color is used as RGB type but with this way i only can find avarage clor of image. But i have an idea i can crop image of middle so i can find avarage color of that part it will give nearly same color again. I find dominant color only :/ – Erçin Akçay May 10 '12 at 09:00
-
@ErçinAkçay If you want to crop the image, surely you want the main colour at the borders. e.g. say you have a large square surrounded by white. You want to detect the colour of the white to crop that, not the square. – Peter Lawrey May 10 '12 at 09:57
In other way, we can done this job with Color Thief library. More information can be found here and here.
Credit to @svenwoltmann and @lokeshdhakar.

- 3,065
- 1
- 31
- 24