BufferedImage и createScreenCapture выдают неправильные цвета

В моей программе на Java мне нужно проанализировать цвет пикселя в заданных координатах. Из-за того, что мне нужно это делать часто, я сначала захватываю часть экрана, а потом получаю цвет пикселя. Я делаю это с помощью:

BufferedImage bi = robot.createScreenCapture(new Rectangle(0,0,100,100));
...
pxcolor = GetPixelColor(bi,x,y);
...
ImageIO.write(bi, "bmp", new File("myScreenShot.bmp"));

Функция GetPixelColor довольно очевидна:

public Color GetPixelColor(BufferedImage b, int x, int y)
{
    int pc = b.getRGB(x, y);
    Color ccc = new Color(pc,true);
    int  red = (pc & 0x00ff0000) >> 16;   // for testing
    int  green = (pc & 0x0000ff00) >> 8;  // for testing
    int  blue = pc & 0x000000ff;          // for testing
    return ccc;     
}

Для тестирования я создал чисто-розовое изображение (RGB(255,0,255)). Проблема в том, что даже если пиксель чисто розовый, функция возвращает что-то вроде RGB(250,61,223), а также тестирует там переменные красный, зеленый и синий. Кроме того, сохраненный файл (myScreenShot.bmp) выглядит совсем иначе.

Что я делаю неправильно. Может ли это быть как-то связано с ColorModel?

UPD: получение DataBuffer из bi не дает правильных результатов - первый элемент полученного DataBuffer равен "-2105371". Не знаю, откуда взялся знак минус, но если преобразовать в HEX, то получится что-то вроде "FFFFFFFFFFDFDFE5". Реальный пиксель RGB равен (E5,E5,EB), а буфер уже поврежден, вместо него имеется RGB(DF,DF,E5). Это уже сводит меня с ума.


person Quest    schedule 29.06.2011    source источник
comment
@Quest: getRGB не только удивительно ssllooww (до 3 порядков, да... до 1000 раз медленнее!!!, неоднократно измерялось на MacMini с OS X 10.5), но и неправильно в том, что он пытается быть умным с цветовыми моделями. Я действительно советую вам работать с BufferedImage, поддерживаемым int[], и управлять пикселями непосредственно из int[] вместо использования getRGB / setRGB. . Затем вы будете считывать точные пиксели, захваченные с помощью createScreenCapture робота, и читать их быстро. Был там, сделал это.   -  person SyntaxT3rr0r    schedule 29.06.2011
comment
@Quest: в дополнение к этому, если вы собираетесь анализировать множество захваченных вами пикселей (например, при проверке каждого пикселя экрана 1920x1200), вам придется иметь дело с миллионами пикселей, и вы будете видите, что вся концепция Объекта просто не сокращает его по скорости. Color на самом деле очень хромая абстракция объекта для чего-то очень простого: быстрый, компактный, элегантный примитив int (обычно представляющий значение ARGB вашего пикселя, каждый на 8 битах ).   -  person SyntaxT3rr0r    schedule 29.06.2011
comment
@СинтаксисT3rr0r. Как я писал в разделе обновления, в буфере, кажется, уже есть неверные значения, поэтому, если я беру из него первый байт, он уже неверен. Хорошо, не первый байт, потому что это альфа, а второй. Не могли бы вы дать мне пример кода, потому что, возможно, я неправильно извлекаю буфер.   -  person Quest    schedule 29.06.2011
comment
@Quest: если src — это BufferedImage, поддерживаемый int[] (эксперимент/Google), тогда int[] srcbuf = ((DataBufferInt) src.getRaster( ).getDataBuffer()).getData(); даст вам и int[]. Тогда это просто: srcbuf[0] = 0xFFFF00FF поместит чисто розовый (как вы его назвали) в пиксель (0,0). Затем int p = srcbuf[0] вернет вам ваш чистый розовый пиксель. Кроме того, проголосуйте и добавьте в избранное следующий вопрос (он содержит нужный вам пример): stackoverflow.com/questions/2825837   -  person SyntaxT3rr0r    schedule 29.06.2011
comment
Похоже, что он не поддерживается int, даже если я не уверен, что вы имеете в виду, но int[] srcbuf = ((DataBufferInt) src.getRaster().getDataBuffer()).getData(); выдает ошибку о том, что DataBuffer не может быть преобразован в DataBufferInt. Если я отлаживаю и останавливаюсь на строке, где вызывается createScreenCapture, в окне переменных я вижу, что в буфере уже есть неверные значения. Кроме того, на моей машине с Windows все в порядке, на моем Mac - неправильные цвета.   -  person Quest    schedule 30.06.2011
comment
@Quest: но обычно вы можете заставить свой BufferedImage иметь DataBufferInt. Да, правильные цвета Windows и неправильные цвета цветовой модели Mac типичны: обработка изображений Java была полностью и излишне продумана (серьезно, сколько серьезных программ обработки изображений написано на Java?). Я чувствую твою боль. Мне нужно манипулировать большими картинками в Java, и это королевская PITA.   -  person SyntaxT3rr0r    schedule 30.06.2011


Ответы (1)


Скорее всего, это связано с цветовой моделью.

Согласно этому code он использует DirectColorModel (см. ниже) независимо от глубины цвета вашего экрана.

/*
 * Fix for 4285201
 * Create a DirectColorModel equivalent to the default RGB ColorModel,
 * except with no Alpha component.
 */
screenCapCM = new DirectColorModel(24,
                 /* red mask */    0x00FF0000,
                 /* green mask */  0x0000FF00,
                 /* blue mask */   0x000000FF);
person aioobe    schedule 29.06.2011
comment
Я только что попытался изменить цветовую модель с помощью отражения, и, к сожалению, похоже, что проблема глубже; RobotPeer.getRGBPixels возвращает неверные значения RGB. Таким образом, проблема не связана с используемым ColorModel. - person Roman Nurik; 10.02.2012