Я хотел бы получить наиболее распространенный цвет изображения. Я использую Java, и я хочу иметь самый преобладающий цвет. Есть ли библиотека cbir java для этого?Получение наиболее распространенного цвета изображения
Благодаря
Я хотел бы получить наиболее распространенный цвет изображения. Я использую Java, и я хочу иметь самый преобладающий цвет. Есть ли библиотека cbir java для этого?Получение наиболее распространенного цвета изображения
Благодаря
Вы можете мертвую BufferedImage
(две петли - один от 0 до ширины, и один от 0 до высоты), и получить вызов getRgb(x, y)
. Затем подсчитайте каждое другое значение. Вы можете использовать для этого Map
(key = color, value = количество вхождений).
Насколько вы хотите, чтобы это было так? Вы можете использовать подход Bozhos и цикл по всему изображению, но это может быть медленным для больших изображений. Есть 16777216 возможных значений RGB и сохранение счетчиков для них на карте не очень эффективно.
Альтернативой является повторная выборка изображения с использованием getScaledInstance
, чтобы уменьшить масштаб до меньшей версии, например. изображение 1x1, а затем используйте getRGB
, чтобы получить цвет этого пикселя. Вы можете поэкспериментировать с различными алгоритмами передискретизации, такими как SCALE_REPLICATE и SCALE_AREA_AVERAGING, чтобы увидеть, что лучше всего подходит для вас.
Обратите внимание, что этот подход дал бы другой результат, чем подход Божоса. В последнем случае цвет, который появляется наиболее часто на изображении, определяется, когда ваш подход пытается найти что-то вроде «среднего цвета» - нечеткое понятие, но ясно, что возвращенный цвет может даже не появляться нигде в оригинале образ.Я не говорю, что один подход лучше, чем другой, я думаю, что оригинальный плакат должен уточнить, что он/она ищет. – Thomas
Да, я так понимаю, поэтому я спросил, сколько требуется точности. Если вы используете «ReplicateScaleFilter», вы получите цвет, который появляется в исходном изображении, потому что он «пропускает строки и столбцы пикселей для уменьшения масштаба». Он не делает «смешивания», как «AreaAveragingScaleFilter». – dogbane
Откуда у вас номер 16581375? Если мы говорим о 8 бит на канал, есть 2^24 = 16777216 возможных значений RGB. – Jesper
Что делать, если вы рассматриваете свое изображение как большой линейный массив пикселей, и после этого все, что вам нужно сделать, это просто его сортировать? Когда вы его сортируете, вы можете считать самую длинную часть одних и тех же значений.
В зависимости от того, насколько точным вам нужно значение цвета, вы можете рассмотреть «цветовые ведра», собирающие похожие цвета, чтобы избежать проблем с памятью. Это означало бы разделение цветового пространства на «интервалы» цветов, где все цвета, которые похожи (например, близко друг к другу), считаются одним и тем же цветом. Изменяя размер интервала, вы имеете возможность напрямую манипулировать компромиссом между точностью и потреблением памяти.
Редактировать: То, что вы хотите, в основном представляет собой гистограмму (идите посмотреть вверх). Есть, скорее всего, хорошо зарекомендовавшие себя стандартные решения для эффективного расчета одного из них.
Да, просто подсчитайте каждый цвет (довольно легко использовать значение цвета как индекс для массива целых чисел), которое вы можете быстро увеличить. Массив будет меньше, чем анализируемое изображение, и приращение целого числа довольно дешево на большинстве языков программирования (всего?). – Eno
Я бы вычислил оттенок каждого пикселя, а затем мощность каждого оттенка (создает гистограмму). Возможно, взвешивание насыщения. Затем примените фильтр нижних частот и найдите максимум. Наконец, конвертируйте из оттенка обратно в RGB.
Это предполагает, что если бы у вас была только красная плоскость изображения, вы бы хотели, чтобы результат был «красным», а не оттенком розового.
Спасибо за ответы. Вот практический пример метода Божо. Он также отфильтровывает белый/серый/черный.
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;
}
}
выглядит как дорогой способ сделать, повторяя каждый пиксель. Он легко умрет за 5-мегапиксельное фото. – Taranfx
Если изображение массивное, сначала измените его размер. –
Эндрю Dyster код работает отлично, Быстрый отклик в андроиде
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import android.graphics.Bitmap;
public class ImageTester {
public interface ImageColor {
void onImageColor(int r, int g, int b);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public static void getMostCommonColour(final Bitmap image,
final ImageColor heColor) {
new Thread(new Runnable() {
private int rgb;
@Override
public void run() {
int height = image.getHeight();
int width = image.getWidth();
Map m = new HashMap();
int boderWid = width/4;
int borderHeigh = height/4;
for (int i = boderWid; i < width - boderWid;) {
for (int j = borderHeigh; j < height - borderHeigh;) {
try {
rgb = image.getPixel(i, j);
} catch (Exception e) {
continue;
}finally{
i += 20;
j += 20;
}
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);
}
}
}
List list = new LinkedList(m.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());
heColor.onImageColor(rgb[0], rgb[1], rgb[2]);
}
}).start();
}
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;
}
}
Что именно вы имеете в виду под "доминирующим"? – Thomas
Самый распространенный цвет на картинке? –