Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 29.12.2007, 15:43   #1
prizrak1390
-=PriZraK=-
Форумчанин
 
Аватар для prizrak1390
 
Регистрация: 12.12.2007
Сообщений: 399
Вопрос найти пиксел определённого цвета

В компонент IMAGE загружаем картинку, затем нужно найти пиксел определённого цвета(быстро найти) и вычислить его координаты.
Мой способ слишком медленный и неудобный в отладке и работе...
prizrak1390 вне форума Ответить с цитированием
Старый 29.12.2007, 15:54   #2
Ins
Форумчанин
 
Регистрация: 29.12.2007
Сообщений: 137
По умолчанию

Если картинка - это Bitmap, то можно с помощью свойства ScanLine получить прямой доступ к данным битмапа и далее просто работать с данными Bitmap-а в памяти. Только предварительно лучше проверить формат битмапа (DIB, DDB, если DIB - то сколько бит на пиксел, если DDB - преобразовать в DIB) а еще лучше - выставить PixelFormat = pf24bit например. Если рисунок НЕ битмап - то сначала его в битмап преобразовать.

Графика в Win API

Та часть Win API, которая служит для работы с графикой, обычно называется GDI (Graphic Device Interface). Ключевым в GDI является понятие контекста устройства (Device Context, DC). Контекст устройства - это специфический объект, хранящий информацию о возможностях устройства, о способе работы с ним и о разрешённой для изменения области. В Delphi контекст устройства представлен классом TCanvas, свойство Handle которого содержит дескриптор контекста устройства. TCanvas универсален в том смысле, что с его помощью рисование в окне, на принтере или в метафайле выглядит одинаково. То же самое справедливо и для контекста устройства. Разница заключается только в том, как получить в разных случаях дескриптор контекста.

Большинство методов класса TCanvas являются "калькой" с соответствующих (в большинстве случаев одноимённых) функций GDI. Но в некоторых случаях (прежде всего в методах вывода текста и рисования многоугольников) параметры методов TCanvas имеют более удобный тип, чем функции GDI. Например, метод TCanvas.Polygon требует в качестве параметра открытый массив элементов типа TPoint, а соответствующая функция GDI - указатель на область памяти, содержащую координаты точек, и число точек. Это означает, что до вызова функции надо выделить память, а потом - освободить её. Ещё нужен код, который заполнит эту область памяти нужными значениями. И ни в коем случае нельзя ошибаться в количестве элементов массива. Если зарезервировать память для одного числа точек, а при вызове функции указать другое, программа будет работать неправильно. Но для простых функций работа через GDI ничуть не сложнее, чем через TCanvas.

Для получения дескриптора контекста устройства существует много функций. Только для того, чтобы получить дескриптор контекста обычного окна, существуют четыре функции: BeginPaint, GetDC, GetWindowDC и GetDCEx. Первая из них может использоваться только при обработке сообщения WM_Paint. Вторая даёт контекст клиентской области окна. Третья позволяет получить контекст всего окна, вместе с неклиентской частью. Последняя же позволяет получить контекст определённой области клиентской части окна.

После того, как дескриптор контекста получен, можно воспользоваться преимуществами класса TCanvas. Для этого надо создать экземпляр такого класса, и присвоить его свойству Handle полученный дескриптор. Освобождение ресурсов нужно проводить в следующем порядке: сначала свойству Handle присваивается нулевое значение, затем уничтожается экземпляр класса TCanvas, затем с помощью подходящей функции GDI освобождается контекст устройства.

Использование класса TCanvas для рисования на контексте устройства, для которого имеется дескриптор, показано в примере PanelMsg.

Разумеется, можно вызывать функции GDI при работе через TCanvas. Для этого им просто надо передать в качестве дескриптора контекста Canvas.Handle. Коротко перечислим те возможности GDI, которые разработчики VCL почему-то не сочли нужным включать в TCanvas: работа с путями и регионами; выравнивание текста по любому углу или по центру; установка собственной координатной системы; получение детальной информации об устройстве; использование геометрических карандашей; вывод текста под углом к горизонтали; расширенные возможности вывода текста; ряд возможностей по рисованию нескольких кривых и многоугольников одной функцией; поддержка режимов заливки. Доступ ко всем этим возможностям может быть осуществлён только через API. Отметим также, что Windows NT/2000/XP поддерживает большее число графических функций, чем 9x/ME. Функции, которые не поддерживаются в 9x/ME, также не имеют аналогов среди методов TCanvas, иначе программы, написанные с использованием данного класса, нельзя было бы запустить в этих версиях Windows.

http://programmersforum.ru/showpost....69&postcount=7
Ins вне форума Ответить с цитированием
Старый 29.12.2007, 16:00   #3
prizrak1390
-=PriZraK=-
Форумчанин
 
Аватар для prizrak1390
 
Регистрация: 12.12.2007
Сообщений: 399
По умолчанию

хм...а есть ли альтернатива?)
prizrak1390 вне форума Ответить с цитированием
Старый 29.12.2007, 16:03   #4
Ins
Форумчанин
 
Регистрация: 29.12.2007
Сообщений: 137
По умолчанию

Цитата:
хм...а есть ли альтернатива?)
Нет, а что Вас так напугало? Примеров в гугле - навалом, ссылку на статью - я дал, в справке все хорошо расписано. Там буквально десяток строк кода написать...

В общем, я тут набросал функцию, писал прямо в браузере, в среде не проверял. Но должно завестись с первого раза, там все тривиально...

Код:
function GetColorXY(Graphic: TGraphic; Color: TColor; var X, Y: Integer): Boolean;
var
  Bmp: TBitmap;
  i, j: Integer;
  Pixel, CmpColor: Cardinal;
  Scan: Pointer;
  R, G, B: Byte;
begin
  Result:=false;
  CmpColor:=ColorToRGB(Color);
  Bmp:=TBitmap.Create;
  try
    Bmp.Assign(Graphic);
    Bmp.PixelFormat:=pf24bit;
    for i:=0 to Bmp.Height - 1 do begin
      Scan:=Bmp.ScanLine[i];
      for j:=0 to Bmp.Width - 1 do begin
        Pixel:=PCardinal(Integer(Scan) + j*3)^;
        R:=GetBValue(Pixel);
        G:=GetGValue(Pixel);
        B:=GetRValue(Pixel);
        if RGB(R, G, B) = CmpColor then begin
          Result:=true;
          X:=j + 1;
          Y:=i + 1;
          Exit;
        end;
      end;
    end;
  finally
    Bmp.Free;
  end;
end;

Последний раз редактировалось Ins; 29.12.2007 в 16:20.
Ins вне форума Ответить с цитированием
Старый 29.12.2007, 17:44   #5
prizrak1390
-=PriZraK=-
Форумчанин
 
Аватар для prizrak1390
 
Регистрация: 12.12.2007
Сообщений: 399
По умолчанию

Спасибо большое...попробую этот вариант
prizrak1390 вне форума Ответить с цитированием
Старый 29.12.2007, 18:59   #6
mutabor
Телепат с дипломом
Старожил
 
Аватар для mutabor
 
Регистрация: 10.06.2007
Сообщений: 4,929
По умолчанию

2 prizrak
Вообще если нужна скорость, то доступ к пикселям через канву не лучший вариант. Тогда лучше скопировать картинку в обычный двухмерный массив, доступ будет намного быстрее, но копирование в массив время займет. Все от конкретной задачи зависит.
The future is not a tablet with a 9" screen no more than the future was a 9" black & white screen in a box. It’s the paradigm that survives. (Kroc Camen)
Проверь себя! Онлайн тестирование | Мой блог
mutabor вне форума Ответить с цитированием
Старый 02.01.2008, 04:38   #7
Alar
Александр
Администратор
 
Аватар для Alar
 
Регистрация: 28.10.2006
Сообщений: 17,501
По умолчанию

Некоторые возможности GDI, которым нет аналогов в TCanvas, демонстрируются примером GDIDraw.

Для задания цвета в GDI предусмотрен тип COLORREF (в модуле Windows определён также его синоним для Delphi - TColorRef). Это 4-байтное беззнаковое целое, старший байт которого определяет формат представления цвета. Если этот байт равен нулю, первый, второй и третий байты представляют собой интенсивности красного, зелёного и синего цветов соответственно. Если старший байт равен 1, два младших байта хранят индекс цвета в текущей палитре устройства, третий байт не используется и должен быть равен нулю. Если старший байт равен 2, остальные байты, как и в нулевом формате, показывают интенсивность цветовых компонент.

Тип TColorRef позволяет менять глубину каждого цветового канала от 0 до 255, обеспечивая кодирование 16777216 различных оттенков (это соответствует режиму True Color). Если цветовое разрешение устройства невелико, GDI подбирает ближайший возможный цвет из палитры. Если старший байт TColorRef равен нулю, цвет выбирается из текущей системной палитры (по умолчанию эта палитра содержит всего 20 цветов, поэтому результаты получаются далёкими от совершенства). Если же старший байт равен 2, GDI выбирает ближайший цвет из палитры устройства. В этом случае результаты получаются более приемлемыми. Если устройство имеет большую цветовую глубину и не использует палитру, разницы между нулевым и вторым форматом COLORREF нет.

Примечание: хотя режимы HighColor (32768 или 65536 цветов) не обладают достаточной цветовой глубиной, чтобы передать все возможные значения TColorRef, палитра в этих режимах не используется, и ближайший цвет выбирается не из палитры, а из всех цветов, которые способно отобразить устройство. Поэтому использование нулевого формата в этих режимах даёт хорошие результаты.

В API определены макросы (а в Windows, соответственно, одноимённые функции) RGB, PaletteIndex и PaletteRGB. RGB принимает три параметра - интенсивности красного, зелёного и синего компонентов и строит из них значение типа TColorRef нулевого формата. PaletteIndex принимает в качестве параметра номер цвета в палитре и на его основе конструирует значение первого формата. Макрос PaletteRGB эквивалентен RGB, за исключением того, что устанавливает старший байт возвращаемого значения равным двум. Для извлечения интенсивностей отдельных цветовых компонент из значения типа TColorRef можно воспользоваться функциями GetRValue, GetGValue и GetBValue.

В системе определены два специальных значения цвета: CLR_NONE ($1FFFFFFF) и CLR_DEFAULT ($20000000). Они используются только в списках рисунков (image lists) для задания фонового и накладываемого цветов при выводе рисунка. CLR_NONE задаёт отсутствие фонового или накладываемого цвета (в этом случае соответствующий визуальный эффект не применяется), CLR_DEFAULT - использование цвета, заданного для всего списка.

В VCL для передачи цвета используется тип TColor, определённый в модуле Graphics. Это 4-байтное число, множество значений которого является надмножеством значений типа TColorRef. К системным форматам 0, 1 и 2 добавлен формат 255. Если старший байт значения типа TColor равен 255, то младший байт интерпретируются как индекс системного цвета. (второй и третий байт при этом не используются). Системные цвета - это цвета, используемые системой для рисования различных элементов интерфейса пользователя. конкретные RGB-значения этих цветов зависят от версии Windows и от текущей цветовой схемы. RGB-значение системного цвета можно получить с помощью функции GetSysColor. 255-ый формат TColor освобождает от необходимости вызова данной функции.

Для типа TColor определён ряд констант, облегчающих использование данного типа. Среди них есть как те, которые соответствуют определённому RGB-цвету (clWhite, clBlack, clRed и т.п.), так и те, которые соответствуют определённому системному цвету (clWindow, clHighlight, clBtnFace и т.п.). Значения RGB-цветов определены в нулевом формате. Это не приведёт к потере точности цветопередачи в режимах с палитрой, т.к. константы определены только для 16-ти основных цветов, которые обязательно присутствуют в системной палитре. Значениям CLR_NONE и CLR_DEFAULT соответствуют константы clNone и clDefault. Они используются (помимо списков рисунков) при задании прозрачного цвета в растровом изображении. Если этот цвет равен clNone, изображение считается непрозрачным, если clDefault, в качестве прозрачного цвета берётся цвет левого нижнего пикселя.

http://programmersforum.ru/showpost....70&postcount=8
Alar вне форума Ответить с цитированием
Старый 02.01.2008, 04:39   #8
Alar
Александр
Администратор
 
Аватар для Alar
 
Регистрация: 28.10.2006
Сообщений: 17,501
По умолчанию

Везде, где требуется значение типа TColor, можно подставлять TColorRef, т.е. всем свойствам и параметрам методов класса TCanvas, имеющим тип TColor, можно присваивать те значения TColorRef, которые сформированы функциями API. Обратное неверно: API-функции не умеют обращаться с 255-ым форматом TColor. Преобразование из TColor в TColorRef осуществляется с помощью функции ColorToRGB. Значения нулевого, первого и второго формата, а также clNone и clDefault она оставляет без изменения, а значения 255-ого формата приводит к нулевому с помощью функции GetSysColor. Эту функцию следует использовать при передаче значений типа TColor в функции GDI.

Использование кистей, карандашей и шрифтов в GDI принципиально отличается от того, как это делается в VCL. Класс TCanvas имеет свойства Brush, Pen и Font, изменение свойств которых приводит к выбору того или иного карандаша, шрифта, кисти. В GDI эти объекты самостоятельны, должны создаваться, получать свой дескриптор, "выбираться" в нужный контекст устройства с помощью функции SelectObject и уничтожаться после использования. Причём удалять можно только те объекты, которые не выбраны ни в одном контексте. Есть также несколько стандартных объектов, которые не надо ни создавать, ни удалять. Их дескрипторы можно получить с помощью функции GetStockObject. Для примера рассмотрим фрагмент программы, рисующей на контексте с дескриптором DC две линии - синюю и красную. В этом фрагменте используется то, что функция SelectObject возвращает дескриптор объекта, родственного выбираемому, который был выбран ранее. Так, при выборе нового карандаша она вернёт дескриптор того карандаша, который был выбран до этого.
Код:
SelectObject(DC, CreatePen(PS_Solid, 1, RGB(255, 0, 0)));
MoveToEx(DC, 100, 100, nil);
LineTo(DC, 200, 200);
DeleteObject(SelectObject(DC, CreatePen(PS_Solid, 1, RGB(0, 0, 255))));
MoveToEx(DC, 200, 100, nil);
LineTo(DC, 100, 200);
DeleteObject(SelectObject(DC, GetStockObject(Black_Pen)));
http://programmersforum.ru/showpost....71&postcount=9
Alar вне форума Ответить с цитированием
Старый 02.01.2008, 04:39   #9
Alar
Александр
Администратор
 
Аватар для Alar
 
Регистрация: 28.10.2006
Сообщений: 17,501
По умолчанию

При переходе на 32-разрядную версию Windows многие функции были исключены из GDI и заменены новыми. Список устаревших функций и соответствующих им новых можно найти в справке в разделе 'Graphics Functions'.

Ещё одно отличие от 16-разрядных версий заключается в том, что ранее дескрипторы графических объектов были глобальными, то есть объект, созданный одной программой, можно было использовать в другой, если эти программы могли передавать друг другу дескрипторы. В 32-разрядных версиях дескрипторы GDI-объектов, созданные одним процессом, не имеют смысла для другого.

Для хранения растровых изображений в Windows существуют три формата: DDB, DIB и DIB-секция. DDB - это Device Dependent Format, формат, который определяется графическим устройством, на которое идёт вывод. DIB - это Device Independent Bitmap, формат, единый для всех устройств. Формат DIB - это устаревший формат, который не позволяет использовать графические функции GDI для модификации картинки, модифицировать изображение можно, только вручную изменяя цвета отдельных пикселей. В 32-разрядных версиях появился ещё один формат - DIB-секция. По сути дела это тот же самый DIB, но дополненный возможностями рисовать на нём с помощью GDI-функций. Все различия между этими тремя форматами можно прочитать в замечательной книге [1]; мы же здесь ограничимся только кратким их обзором.

http://programmersforum.ru/showpost....2&postcount=10
Alar вне форума Ответить с цитированием
Старый 02.01.2008, 04:39   #10
Alar
Александр
Администратор
 
Аватар для Alar
 
Регистрация: 28.10.2006
Сообщений: 17,501
По умолчанию

Формат DDB поддерживается самой видеокартой (или другим устройством вывода), поэтому при операциях с таким изображением задействуется аппаратный ускоритель графики. DDB-изображение хранится в выгружаемом системном пуле памяти (Windows NT/2000/XP) или в куче GDI (Windows 9x/ME). При этом размер DDB-растра не может превышать 16 Мб в Windows 9x/ME и 48 Мб в Windows NT/2000/XP. Формат DDB непереносим с одного устройства на другое, он должен использоваться только в рамках одного устройства. Прямой доступ к изображению и его модификация вручную невозможны, т.к. формат хранения изображения конкретным устройством непредсказуем. Модифицировать DDB можно только с помощью функций GDI. Цветовая глубина DDB-изображений определяется устройством.

DIB-секция может храниться в любой области памяти, их размер ограничивается только размером доступной приложению памяти, функции GDI для рисования на таком изображении используют чисто программные алгоритмы, никак не задействуя аппаратный ускоритель, поэтому графические операции с DIB-секцией выполняются медленнее, чем с DDB (не все видеокарты поддерживают аппаратные алгоритмы построения линий, кривых, заполнения областей и т.п., поэтому рисование на DIB-изображении может выполняться быстрее, чем на DDB; но вывод DDB на экран всегда существенно быстрее, чем DIB). DIB-секция поддерживает различную цветовую глубину и прямой доступ к области памяти, в которой хранится изображение. DIB-секция переносима с одного устройства на другое. BMP-файлы хранят изображение как DIB.

Класс TBitmap может хранить изображение как в виде DDB, так и в виде DIB-секции - это определяется значением свойства PixelFormat. Значение pfDevice означает использование DDB, остальные значения - DIB-секции с различной цветовой глубиной. По умолчанию TBitmap создаёт изображение с форматом pfDevice, но программист может изменить формат в любой момент. При этом создаётся новое изображение нового формата, старое копируется в него и уничтожается.

Со свойством PixelFormat тесно связано свойство HandleType, которое может принимать значение bmDIB и bmDDB. Изменение свойства PixelFormat приводит к изменению свойства HandleType и наоборот.


При загрузке изображения из файла, ресурса или потока класс TBitmap обычно создаёт изображение в формате DIB-секции, соответствующее источнику по цветовой глубине. Исключение составляют сжатые файлы (формат BMP поддерживает сжатие только для 16- и 256-цветных изображений) - в этом случае создаётся DDB. В файле Graphics определена глобальная переменная DDBsOnly, которая по умолчанию равна False. Если изменить её значение на True, загружаемое изображение всегда будет иметь формат DDB.

Примечание: в справке сказано, что когда DDBsOnly=False, вновь создаваемые изображения по умолчанию хранятся в виде DIB-секции. На самом деле из-за ошибки в модуле Graphics (как минимум до 7-ой версии Delphi включительно) вновь созданное изображение всегда хранится как DDB независимо от значения DDBsOnly.

Класс TBitmap имеет свойство ScanLine, через которое можно получить прямой доступ к массиву пикселей, составляющих изображение. В справке написано, что это свойство можно использовать только с DIB-изображениями. Но на самом деле DDB-изображения тоже позволяют использовать это свойство, хотя и с существенными ограничениями. Если изображение хранится в DDB-формате, при обращении к ScanLine создаётся его DIB-копия, и ScanLine возвращает указатель на массив этой копии. Поэтому, во-первых, ScanLine работает с DDB-изображениями очень медленно, а во-вторых, работает не с изображением, а с его копией, откуда вытекают следующие ограничения:
Копия создаётся на момент обращения к ScanLine, поэтому изменения, сделанные на изображении с помощью GDI-функций после этого, будут недоступны.
Каждое обращение к ScanLine создаёт новую копию изображения, а старая при этом уничтожается. Гарантии, что новая копия будет располагаться в той же области памяти, нет, поэтому указатель, полученный при предыдущем обращении к ScanLine, больше нельзя использовать.
Изменения, сделанные в массиве пикселей, затрагивают только копию изображения, но само изображение при этом не меняется. Поэтому при использовании DDB свойство ScanLine даёт возможность прочитать, но не изменить изображение.

Следует отметить, что TBitmap иногда создаёт DIB-секции, даже если свойства HandleType и PixelFormat явно указывают на использование DDB. Особенно часто это наблюдается для изображений большого размера. По всей видимости, это происходит в тех случаях, когда в системном пуле нет места для хранения DDB-изображения такого размера, и разработчики TBitmap решили, что в таком случае лучше создать DIB-изображение, чем не создавать никакого.

Пример BitmapSpeed позволяет сравнить скорость выполнения различных операций с DDB- и DIB-изображениями.

http://www.delphikingdom.com/asp/vie...talogid=169#10
Alar вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Инверсия цвета Dj_smart Общие вопросы Delphi 6 08.05.2008 16:29
DBGrid цвета Steel_rat БД в Delphi 9 01.02.2008 11:06
Поиск определённого текста в текстовом файле vitawt Общие вопросы Delphi 4 20.01.2008 22:12
Формат цвета xTANATOSx Общие вопросы Delphi 14 02.11.2007 20:22
цвета Toxa Общие вопросы Delphi 3 20.04.2007 12:03