Юрий Спектор дата публикации 24-11-2006 06:26 Выделение произвольной части изображения. Принцип “волшебной палочки”.
Поводом для написания этой статьи стал Вопрос КС №46822. Наверняка многие программисты задавались целью написать свой графический редактор, и у многих возникала проблема: как выделить произвольную область изображения. Чаще других встречаются следующие принципы выделения: принцип "лассо" - пользователь сам очерчивает область выделения, и принцип "волшебной палочки" - пользователь кликает в одной точке изображения, а выделяется область, цвет которой близок к цвету в этой точке. Для решения подобных задач можно использовать регионы (Regions) Windows. Когда у нас есть регион, соответствующий области выделения, мы можем начертить его границу на изображении (функция FrameRgn), чтобы показать пользователю, какая область выделена, назначить его как область отсечения (SelectClipRgn), чтобы работать только с выделенной частью изображения, или еще как-нибудь. Вся задача сводится к тому, как этот регион построить.
Для прямоугольного выделения - все очень просто: мы запоминаем начальную точку, где пользователь нажал кнопку мыши, и конечную, где пользователь отпустил кнопку мыши. По двум точкам несложно построить прямоугольный регион (CreateRectRgn). Построение региона при выделении по принципу "лассо" не намного труднее - пока пользователь водит мышкой, мы запоминаем координаты, а когда перестает - строим по этим точкам полигональный регион (CreatePolygonRgn). А вот задача построения региона для выделения по принципу "волшебной палочки" сложнее и интереснее, именно ее решение и приводится в данной статье.
function MagicWandSelect(Graphic: TGraphic; StartPoint: TPoint;
CmpFunc: TMagicWandCmpFunc): HRGN;
Реализация данной функции содержится в прилагаемом к статье файле MagicWand.pas. В качестве параметров функции необходимо передать изображение Graphic, начальную точку StartPoint и функцию сравнения цветов CmpFunt. Эта функция должна иметь следующий прототип:
TMagicWandCmpFunc = function(a,b: TColor): Boolean;
Что должна делать эта функция видно из комментариев. В прилагаемом к статье тестовом примере описан один из вариантов такой функции, вы можете использовать свой.
Функция MagicWandSelect реализует известный "волновой алгоритм". Его описание - это тема для отдельного разговора. Для тех, кто не знаком с данным алгоритмом, скажу лишь, что обычно его используют для поиска кратчайшего пути на карте (чаще всего игровой). В основе алгоритма лежит принцип Гюйгенса, который утверждает, что каждую точку в пространстве, до которой дошло возмущение, можно считать вторичным источником возмущения. Порядок перебора точек изображения напоминает движение фронта круговой волны - от центра возмущения к краям, причем каждая точка, до которой "волна" дошла, становится источником новой "круговой волны". Из-за подобной схожести алгоритм и получил свое название. Вообще, всех, кого эта тема заинтересует, наберите в поисковике "волновой алгоритм" - информации в Интернете полно!
Для тех, кто попытается самостоятельно разобраться с реализацией этой функции, возможно, столкнуться с некоторыми проблемами. Я хоть и писал комментарии, где это возможно, но из-за стремления увеличить быстродействие, иногда использовались немного "хитрые" приемы. Тестовый пример, показывающий пример использования функции выделения части изображения, был написан на скорую руку - ну не люблю я писать тестовые примеры! Но я думаю, вы сами сможете разобраться, как использовать эту функцию. Ну все, надеюсь этот материал будет кому-либо полезен...
К материалу прилагаются файлы:
[Создание графического редактора] [Регионы и траектории (Paths)]
Обсуждение материала [ 01-12-2007 07:13 ] 15 сообщений |