GetPixel возвращает неверные значения

Это мой первый пост на этом форуме, пожалуйста, не ругайте меня, если я разместил его не в том месте или сделал что-то не так, я очень редко пишу на форумах. Итак, у меня есть проблема с функцией GetPixel. По сути, он должен возвращать десятичное значение цвета в точках x, y. Код, который я собираюсь опубликовать, отлично работает на 32-битной Windows 7, но недавно я купил новый ноутбук y50-70 с 64-битной Windows 8.1, и тот же код работает совершенно по-другому. Не могу найти решения проблемы, даже описать не могу. Я думаю, это может иметь какое-то отношение к дескриптору рабочего стола, HDC, GetDC(), GetPixel(), может быть, даже к разрешению моего компьютера, частоте обновления или чему-то подобному... Я даже записал несколько видеороликов, которые могут помочь вам понять у меня проблема, потому что я даже не могу ее правильно описать. Это похоже на то, что настоящий цвет - это x = 219, y = 407 от того места, куда указывает моя мышь. Новому ноутбуку 3 недели, я даже пытался 1 раз сделать восстановление системы, но это не решило проблему.

Не стесняйтесь использовать этот код, надеюсь, он будет работать нормально для вас:

#include <iostream>
#include <Windows.h>
using namespace std;

void Detect();

int main()
{
    Detect();

    return 0;
}

void Detect()
{
    POINT p;
    HDC hDC = GetDC(0);
    int x, y;

    while (!GetAsyncKeyState(VK_INSERT)) // Press insert to stop
    {
        GetCursorPos(&p);
        x = p.x;
        y = p.y;
        hDC = GetDC(0);
        cout << x << " " << y << " " << GetPixel(hDC, x, y) << endl;
        Sleep(50);
    }
    ReleaseDC(0, hDC);
}

Ссылки на проблему ниже: https://youtu.be/q2H2M8WLHVI https://youtu.be/UcneHwXaGoM

Если бы кто-нибудь мог хоть как-то помочь или подсказать, что делать, куда идти, я был бы очень и очень признателен. Одна из основных причин, по которой я начал программировать, заключается в том, что что-то вроде этого, работа с цветами, условиями и т. д., и теперь я не могу продвинуться дальше, что очень печально. Надеюсь услышать ответ. Спасибо.


person Sakire Sileteik    schedule 16.04.2015    source источник
comment
Я не думаю, что это проблема, но вы должны удалить GetDC из-за пределов цикла и переместить ReleaseDC в цикл.   -  person Mark Ransom    schedule 16.04.2015
comment
Спасибо. Я добавлю ReleaseDC в цикл, и причина, по которой я добавил GetDC снаружи, заключалась в том, что он был неопределенным, используя VisualStudio 2013, но это не решение основной проблемы.   -  person Sakire Sileteik    schedule 16.04.2015


Ответы (2)


Вероятно, это проблема с масштабированием DPI.

Если ваш новый монитор имеет количество точек на дюйм выше среднего, то Windows по умолчанию будет растягивать графику. По умолчанию Windows предполагает, что программы игнорируют DPI. Если бы Windows не растягивала графику, то программы, не настроенные на DPI, имели бы крошечный текст в крошечных окнах на дисплеях с высокой плотностью.

Это немного взломать. Некоторые из API-интерфейсов и сообщений Windows, которые позволяют вам спрашивать о дисплее и окнах, будут переводить координаты между «средними» 96 пикселями на дюйм и любым фактическим DPI для монитора. Точно так же API, которые позволяют вам измерять вещи, делают обратное преобразование. Так что это все в значительной степени прозрачно для программы. Но это не идеально, потому что не все API-интерфейсы могут выполнять масштабирование согласованным образом.

Итак, я предполагаю, что у вашего ноутбука дисплей с высоким разрешением, GetPixel не преобразует координаты для масштабирования DPI, а положение мыши преобразуется для масштабирования DPI. В результате вы запрашиваете пиксель, который на самом деле не совпадает с мышью.

Мое предлагаемое решение - сообщить окнам, что ваша программа «осведомлена о DPI». Есть несколько способов сделать это. Самым простым в вашем случае может быть вызов SetProcessDPIAware прямо в начале вашей программы. Вы также можете сделать это, пометив свою программу в манифесте. В зависимости от используемого вами компилятора может быть опция командной строки для автоматического создания нужного вам манифеста.

person Adrian McCarthy    schedule 16.04.2015
comment
Большое спасибо! SetProcessDPIAware() решил эту проблему! Я включил эту функцию прямо в функцию main(), надеюсь, все в порядке. Могу ли я в любом случае оценить ваш пост как ответ? Просто хочу еще раз сказать спасибо. :) - person Sakire Sileteik; 16.04.2015
comment
Из-за виртуализации DPI, если одно приложение запрашивает другое приложение с другим уровнем осведомленности для получения информации, зависящей от DPI, система автоматически масштабирует значения в соответствии с уровнем осведомленности вызывающего абонента. Одним из примеров этого является вызов GetWindowRect и передача окна, созданного другим приложением. Используя ситуацию, описанную выше, предположим, что приложение PROCESS_DPI_UNAWARE создало окно 500 на 500 на дисплее C. Если вы запрашиваете прямоугольник окна из другого приложения, размер прямоугольника будет варьироваться в зависимости от поддержки DPI вашего приложения. Источник: bit.ly/1RpUnHx - person mikew; 17.12.2015
comment
@mikew: я не уверен, что вы пытаетесь сделать. Здесь нет связи между приложениями. Только один из двух API, которые использует Sakire Sileteik, применяет масштабирование. - person Adrian McCarthy; 17.12.2015
comment
Я просто публиковал эту цитату для справки с сайта MSDN. Я бы подумал, что GetDC квалифицируется как межприложение так же, как GetWindowRect, но я не знаю. Все, что я знаю, это то, что я заметил проблему, даже не получая координаты мыши. Я бы отправлял жестко закодированные координаты и все равно получал бы неправильные результаты. - person mikew; 17.12.2015

Еще одна альтернатива, которая сработала для меня, — изменить настройку на панели управления, чтобы отключить масштабирование DPI для каждого устройства. Вы используете несколько мониторов?

В Win 8.1 появился новый параметр на панели управления, в котором говорится: «Позвольте мне выбрать одно масштабирование DPI для всех дисплеев». По умолчанию это отключено. Включение его сработало для меня.

Посмотрите это видео, чтобы найти настройку: https://www.youtube.com/watch?v=sE3IUTPy1WA

Мне любопытно, поэтому дайте мне знать, работает ли это для вас, когда вы не используете SetProccesDPIAware()

person mikew    schedule 16.12.2015