Gradient Tool/ru
The release of Synfig Studio 0.64.0 introduced new terminology and this translated page needs to be updated according to original English text.
You can help updating this page — see instructions here. Thank you!
warning end
ALT-G
Инструмент «Градиент» используется для создания плавных переходов между двумя или большим количеством цветов внутри объекта.
Когда вы выбираете этот инструмент на панели параметров инструмента будут показаны опции создания градиента.
Они позволяют вам:
- Указать имя слоя который будет создан.
- Выбрать тип градиента (Линейный, Радиальный, Конический, Спиральный) в выпадающем меню.
NOTE: Имя слоя всегда может быть изменено позже на панели слоёв или панели параметров если это понадобится, но тип градиента должен быть выбран заранее.
О том как менять цвета градиента можно прочитать в статье «Редактирование градиента».
Есть 4 типа градиентов:
- Линейный — Он производит простой переход по прямой линии. Установите цвет для фона и переднего плана, кликните в месте где градиент должен взять своё начало и перетащите курсор в место где переход должен завершится. Градиент будет создан перпендикулярно линии которую вы проведёте. В любой момент градиент может быть изменён с помощью перемещения одной из конечных точек линии в любом направлении. Используйте Инструмент преобразования для того чтобы перемещать эти точки.
- Радиальный — Он производит круглую градиентную заливку. Кликните в месте где вы хотите видеть центр круга заливки и перетащите точку чтобы установить радиус цветового перехода. Используйте Инструмент преобразования чтобы изменить положение градиента (центральной точки) или радиус (крайней точки) радиального градиента.
- Конический — Этот градиент похож на конус если смотреть на него с верху. Градиент следует по дуге и расходится во всех направлениях. Кликните чтобы установить центр и тащите курсор чтобы указать в каком направлении цвета градиента должны распространяться. Для последующего изменения точек используйте Инструмент преобразования, центральная точка меняет и центр градиента, а вторая меняет направление градиента.
- Спиральный — Производит спиральный градиент. Кликните чтобы указать центр спирали и тащите чтобы настроить «сжатие» спирали. Как всегда для того чтобы изменить точки используется Инструмент преобразования.
28. OpenCV шаг за шагом. Преобразование Хафа
На прошлом шаге мы узнали о функции, реализующей детектор границ Кенни. Если вы немного поэкспериментировали с представленным примером, то обратили внимание, что cvCanny() помогает замечательно выделять границы предметов и окружающей обстановки. В нашем рукотворном мире городов и квартир преобладают прямые линии и другие простые геометрические формы (квадрат, прямоугольник, треугольник, круг).
Поэтому, одной из задач зрения робота может быть детектирование этих линий (для поиска каких-либо геометрических форм, например, дверного проёма, круглой розетки и т.п.)
Эта задача весьма неплохо решается с помощью т.н. преобразования Хафа.
Преобразование Хафа (Hough Transform) — это метод для поиска линий, кругов и других простых форм на изображении.
метод Хафа был впервые применен для анализа изображений пузырьковой камеры
Преобразование Хафа предназначено для поиска объектов, принадлежащих определённому классу фигур с использованием процедуры голосования. Процедура голосования применяется к пространству параметров, из которого и получаются объекты определённого класса фигур по локальному максимуму в, так называемом, накопительном пространстве (accumulator space) которое строится при вычислении трансформации Хафа.
Преобразование Хафа основывается на представлении искомого объекта в виде параметрического уравнения. Параметры этого уравнения представляют фазовое пространство (т.н. аккумуляторный массив/пространство, пространство Хафа).
Затем, берётся двоичное изображение (например, результат работы детектора границ Кенни). Перебираются все точки границ и делается предположение, что точка принадлежит линии искомого объекта — т.о. для каждой точки изображения рассчитывается нужное уравнение и получаются необходимые параметры, которые сохраняются в пространстве Хафа.
Финальным шагом является обход пространства Хафа и выбор максимальных значений, за которые «проголосовало» больше всего пикселей картинки, что и даёт нам параметры для уравнений искомого объекта.
Запутано? Попробуем разобраться на примерах
Самым распространённым и простым случаем преобразования Хафа является поиск линий
Преобразовании Хафа для поиска линий (Hough Line Transform)
В основе теории преобразования Хафа лежит утверждение, что любая точка двоичного изображения может быть частью некоторого набора возможных линий.
y = a*x+b // в декартовых координатак p = x*cos(f)+y*sin(f) // в полярных координатах
Прямую на плоскости можно представить:
x*cos(f) + y*sin(f) = R
, где
R – длина перпендикуляра опущенного на прямую из начала координат,
f — угол между перпендикуляром к прямой и осью OX.
f находится в пределах от 0 до 2*PI,
R ограничено размерами входного изображения.
Через каждую точку (x, y) изображения можно провести несколько прямых с разными R и f, то есть каждой точке (x, y) изображения соответствует набор точек в фазовом пространстве (R, f), образующий синусоиду.
Так же каждой точке (R0, f0) пространства (R, f) можно поставить в соответствие счетчик, соответствующий количеству точек (x, y), лежащих на прямой
x*cos(f0) + y sin(f0) = R0
Теперь непрерывное фазовое пространство нужно перевести в дискретное, введя сетку на пространстве (R, f), одной ячейке которой соответствует набор прямых с близкими значениями R и f.
Можно попробовать реализовать преобразование Хафа самостоятельно, например что-то вроде этого:
// // Hough transform - преобразование Хафа // - нахождение линий // // долгий и нудный перебор, поэтому лучше тестировать // на маленьких картинках :) // // https://robocraft.ru // #include #include #include #include #include // // преобразование Хафа для нахождения линий // // код на Паскале: http://forum.graphicon.ru/viewtopic.php?p=20222#p20222 // void houghLine(IplImage* original, float accuracy=0.1) < assert(original!=0); IplImage *src=0, *rgb=0; IplImage *bin=0; IplImage *phase=0; src=cvCloneImage(original); // заведём цветную картинку rgb = cvCreateImage(cvGetSize(src), 8, 3); cvConvertImage(src, rgb, CV_GRAY2BGR); // бинарная картинка - для контуров bin = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1); cvCanny(src, bin, 50, 200); cvNamedWindow( "bin", 1 ); cvShowImage( "bin", bin ); // максимальное расстояние от начала координат - это длина диагонали int RMax = cvRound( sqrt( (double)(src->width*src->width + src->height*src->height) ) ); // картинка для хранения фазового пространства Хафа (r, f) // 0 < r < RMax // 0 < f < 2*PI phase = cvCreateImage(cvSize(RMax, 180), IPL_DEPTH_16U, 1); cvZero(phase); int x=0, y=0, r=0, f=0; float theta=0; // пробегаемся по пикселям изображения контуров for(y=0; yheight; y++)< uchar* ptr = (uchar*) (bin->imageData + y * bin->widthStep); for(x=0; xwidth; x++)< if(ptr[x]>0)< // это пиксель контура? // рассмотрим все возможные прямые, которые могут // проходить через эту точку for(f=0; fimageData + f * phase->widthStep); for(r=0; r > > > > > cvNamedWindow( "phase", 1 ); cvShowImage( "phase", phase ); // увеличим фазовую картинку IplImage* phaseImage = cvCreateImage( cvSize(phase->width*3, phase->height*3), IPL_DEPTH_16U, 1); cvResize(phase, phaseImage); cvNamedWindow( "phaseImage", 1 ); cvShowImage( "phaseImage", phaseImage); // Выбираем точку фазового пространства которая набрала наибольшее число попаданий unsigned int MaxPhaseValue = 0; float Theta=0; int R=0; for(f=0; fimageData + f * phase->widthStep); for(r=0; rMaxPhaseValue) < MaxPhaseValue = ptrP[r]; Theta = f; R = r; >> > #if 1 printf("[M] %d\n", MaxPhaseValue); // нормировка float scaler = 0xFFFFFFFF/(float)MaxPhaseValue; for(y=0; yheight; y++)< short* ptr = (short*) (phaseImage->imageData + y * phaseImage->widthStep); for(x=0; xwidth; x++) < ptr[x]*=scaler; >> cvNamedWindow( "phaseImage2", 1 ); cvShowImage( "phaseImage2", phaseImage); #endif // Рисуем линию по точкам для R, Teta которые получили в результате преобразования Theta=Theta*CV_PI/180.0; for(y=0; yheight; y++)< uchar* ptr = (uchar*) (rgb->imageData + y * rgb->widthStep); for(x=0; xwidth; x++) < if ( cvRound(((y) * sin(Theta) + (x) * cos(Theta))) == R)< ptr[3*x]=0; ptr[3*x+1]=0; ptr[3*x+2]=255; >> > cvNamedWindow( "line", 1 ); cvShowImage( "line", rgb ); // освобождаем ресурсы cvReleaseImage(&src); cvReleaseImage(&rgb); cvReleaseImage(&bin); cvReleaseImage(&phase); cvReleaseImage(&phaseImage); > int main(int argc, char* argv[]) < IplImage *original=0; // имя картинки задаётся первым параметром char* filename = argc >= 2 ? argv[1] : "Image0.jpg"; // получаем картинку original = cvLoadImage(filename, 0); printf("[i] image: %s\n", filename); assert( original != 0 ); // покажем изображения cvNamedWindow( "original", 1 ); cvShowImage( "original", original ); houghLine(original); cvWaitKey(0); cvReleaseImage(&original); // удаляем окна cvDestroyAllWindows(); return 0; >

скачать иcходник (28-houghLine.cpp)
— получается оооочень долго
Но, в OpenCV уже есть функция, реализующая преобразование Хафа для поиска линий
CVAPI(CvSeq*) cvHoughLines2( CvArr* image, void* line_storage, int method, double rho, double theta, int threshold, double param1 CV_DEFAULT(0), double param2 CV_DEFAULT(0));
— нахождение линий на двоичном изображении, используя преобразование Хафа
image — 8-битное двоичное изображение (в случае вероятностного метода изображение будет модифицироваться)
line_storage — хранилище памяти для сохранения найденных линий (можно использовать матрицу 1xЧисло_линий CvMat)
method — метод:
#define CV_HOUGH_STANDARD 0 #define CV_HOUGH_PROBABILISTIC 1 #define CV_HOUGH_MULTI_SCALE 2
CV_HOUGH_STANDARD — классический вариант трансформации Хафа. Каждая линия представляется двумя числами типа float (rho, theta), где rho — дистанция между точкой (0,0) и линией, а theta — угол между осью x и нормалью к линии (т.е. матрица должна иметь тип of CV_32FC2)
CV_HOUGH_PROBABILISTIC — вероятностный метод трансформации Хафа (более эффективен с случае изображений с несколькими длинными линейными сегментами). Возвращает сегменты линии, которые представляются точками начала и конца (т.е. матрица должна иметь тип of CV_32SC4)
CV_HOUGH_MULTI_SCALE — масштабный вариант классической трансформации Хафа. Линии представлены так же, как и в CV_HOUGH_STANDARD
Вероятностное преобразование Хафа (Probabilistic Hough Transform)
заключается в том, что для нахождения объекта достаточно провести преобразование Хафа только для части (a) точек исходного изображения, 0%
rho — разрешение по дистанции
theta — разрешение по углу (в радианах)
threshold — пороговый параметр. Линия возвращается, если аккумулирующий параметр больше порогового значения.
param1 — первый параметр (в зависимости от метода трансфрмации:
CV_HOUGH_STANDARD — 0 — не используется
CV_HOUGH_PROBABILISTIC — минимальная длина линии
CV_HOUGH_MULTI_SCALE — делитель разрешения по дистанции (rho/param1))
param2 — второй параметр (в зависимости от метода трансфрмации:
CV_HOUGH_STANDARD — 0 — не используется
CV_HOUGH_PROBABILISTIC — максимальный промежуток между сегментами линии, лежащими на одной линии, чтобы считать их одним сегментом (объединить их вместе)
CV_HOUGH_MULTI_SCALE — делитель разрешения по углу (theta/param1))
если line_storage — указатель на хранилище памяти, то функция вернёт указатель на первый элемент последовательности, содержащей найденные линии.
В составе OpenCV уже идёт пример, демонстрирующий работу cvHoughLines2():
\OpenCV\samples\c\houghlines.c
// // нахождение линий на изображении, // с использованием преобразования Хафа cvHoughLines2() // // модифицированный пример samples\c\houghlines.c // // https://robocraft.ru // #include #include #include int main(int argc, char* argv[]) < IplImage* src = 0; IplImage* dst=0; IplImage* color_dst=0; // имя картинки задаётся первым параметром char* filename = argc >= 2 ? argv[1] : "Image0.jpg"; // получаем картинку (в градациях серого) src = cvLoadImage(filename, CV_LOAD_IMAGE_GRAYSCALE); if( !src ) < printf("[!] Error: cant load image: %s \n", filename); return -1; >printf("[i] image: %s\n", filename); // хранилище памяти для хранения найденных линий CvMemStorage* storage = cvCreateMemStorage(0); CvSeq* lines = 0; int i = 0; dst = cvCreateImage( cvGetSize(src), 8, 1 ); color_dst = cvCreateImage( cvGetSize(src), 8, 3 ); // детектирование границ cvCanny( src, dst, 50, 200, 3 ); // конвертируем в цветное изображение cvCvtColor( dst, color_dst, CV_GRAY2BGR ); // нахождение линий lines = cvHoughLines2( dst, storage, CV_HOUGH_PROBABILISTIC, 1, CV_PI/180, 50, 50, 10 ); // нарисуем найденные линии for( i = 0; i < lines->total; i++ ) < CvPoint* line = (CvPoint*)cvGetSeqElem(lines,i); cvLine( color_dst, line[0], line[1], CV_RGB(255,0,0), 3, CV_AA, 0 ); >// показываем cvNamedWindow( "Source", 1 ); cvShowImage( "Source", src ); cvNamedWindow( "Hough", 1 ); cvShowImage( "Hough", color_dst ); // ждём нажатия клавиши cvWaitKey(0); // освобождаем ресурсы cvReleaseMemStorage(&storage); cvReleaseImage(&src); cvReleaseImage(&dst); cvReleaseImage(&color_dst); cvDestroyAllWindows(); return 0; >

скачать иcходник (28-cvHoughLines2.cpp)
Преобразовании Хафа для нахождения окружностей (Hough Circle Transform)
точки окружности можно представить формулой:
(x - a)^2 + (y - b)^2 = R2,
, где (a, b) – координаты центра окружности, а R – ее радиус.
т.е. формула, задающая семейство окружностей, имеет вид:
F (a, b, R, x, y) = (x - a)^2 + (y - b)^2 - R2
Как видим, для нахождения окружностей нужно задавать уже 3 пераметра — координаты центра окружности и её радиус. Это приводит к увеличению пространства Хафа на целое измерение, что в итоге сказывается на скорости работы. Поэтому для поиска окружностей применяется т.н. градиентный метод Хафа (Hough gradient method).
эффективность использования преобразования Хафа резко падает при увеличении размерности фазового пространства, поэтому перед его применением желательно минимизировать каким-либо образом количество параметров кривой.
Можно существенно снизить количество кривых, потенциально проходящих через данную точку изображения, если рассматривать только кривые, касательная которой перпендикулярна градиенту яркости изображения в рассматриваемой точке. Таким образом, можно, например, свести задачу выделения окружностей с неизвестным радиусом к двумерному фазовому пространству.
Нахождение кругов
1. используется детектор границ Кенни для нахождения границ на изображении
2. для ненулевых точек высчитывается градиент (через вычисление 1-й производной по X и Y через cvSobel())
3. определяются центры кругов
4. относительно центра определяются ненулевые точки, лежащие на одном расстоянии
в OpenCV, преобразовании Хафа для нахождения окружностей реализуется функцией cvHoughCircles():
CVAPI(CvSeq*) cvHoughCircles( CvArr* image, void* circle_storage, int method, double dp, double min_dist, double param1 CV_DEFAULT(100), double param2 CV_DEFAULT(100), int min_radius CV_DEFAULT(0), int max_radius CV_DEFAULT(0));
— нахождение кругов на изображении
image — исходное изображение (8-битное, одноканальное, градации серого)
line_storage — хранилище памяти для сохранения найденных кругов (можно использовать матрицу типа CV_32FC3, 1xЧисло_кругов CvMat). Круг хранится в виде трёх чисел типа float: координаты центра (x,y) и радиус.
method — метод, на настоящее время реализован только:
#define CV_HOUGH_GRADIENT 3
dp — разрешение сумматора, используемое для детектирования центров кругов (1 — одинаково с исходным изображением, 2 — половина высоты/ширины и т.д.)
min_dist — минимальная дистанция между центрами детектируемых кругов
param1 — первый параметр (в зависимости от метода трансфрмации:
CV_HOUGH_GRADIENT — верхнее пороговое значение, передаваемое детектору границ Кенни (нижнее пороговое значение будет в 2 раза меньше)
param2 — второй параметр (в зависимости от метода трансфрмации:
CV_HOUGH_GRADIENT — суммирующее пороговое значение детектированя центров
min_radius — минимальный радиус круга
max_radius — максимальный радиус круга
// // Несколько модифицированный пример example 6-1 Hough circles // нахождение кругов на изображении, // с использованием трансформации Хафа cvHoughCircles() // // из книги: // Learning OpenCV: Computer Vision with the OpenCV Library // by Gary Bradski and Adrian Kaehler // Published by O'Reilly Media, October 3, 2008 // // // https://robocraft.ru // #include #include #include int main(int argc, char* argv[]) < IplImage* image = 0; // имя картинки задаётся первым параметром char* filename = argc >= 2 ? argv[1] : "Image0.jpg"; // получаем картинку (в градациях серого) image = cvLoadImage(filename, CV_LOAD_IMAGE_GRAYSCALE); printf("[i] image: %s\n", filename); assert( image != 0 ); // загрузим оригинальное изображении IplImage* src = cvLoadImage(filename ); // хранилище памяти для кругов CvMemStorage* storage = cvCreateMemStorage(0); // сглаживаем изображение cvSmooth(image, image, CV_GAUSSIAN, 5, 5 ); // поиск кругов CvSeq* results = cvHoughCircles( image, storage, CV_HOUGH_GRADIENT, 10, image->width/5 ); // пробегаемся по кругам и рисуем их на оригинальном изображении for( int i = 0; i < results->total; i++ ) < float* p = (float*) cvGetSeqElem( results, i ); CvPoint pt = cvPoint( cvRound( p[0] ), cvRound( p[1] ) ); cvCircle( src, pt, cvRound( p[2] ), CV_RGB(0xff,0,0) ); >// показываем cvNamedWindow( "cvHoughCircles", 1 ); cvShowImage( "cvHoughCircles", src); // ждём нажатия клавиши cvWaitKey(0); // освобождаем ресурсы cvReleaseMemStorage(&storage); cvReleaseImage(& image); cvReleaseImage(&src); cvDestroyAllWindows(); return 0; >

скачать иcходник (28-cvHoughCircles.cpp)
результат cvHoughCircles() очень сильно зависит от параметров,
например,
CvSeq* results = cvHoughCircles( image, storage, CV_HOUGH_GRADIENT, 2, image->width/5 );

уже даёт результат:
Существует и так называемое Обобщённое преобразование Хафа, с помощью которого можно искать фигуры произвольной формы.
( хм… об Обобщённом преобразовании Хафа даже нету странички в русской википедии — сейчас исправим :))
Циклические градиенты SkiaSharp
Класс SKShader определяет статические методы для создания четырех различных типов градиентов. Этот метод рассматривается в статье Об линейном градиенте CreateLinearGradient SkiaSharp. В этой статье рассматриваются три других типа градиентов, основанных на кругах.
Метод CreateRadialGradient создает градиент, исходящий из центра круга:

Метод CreateSweepGradient создает градиент, который разворачивается вокруг центра окружности:

Третий тип градиента довольно необычный. Он называется двухточечным коническим градиентом и определяется методом CreateTwoPointConicalGradient . Градиент распространяется от одного круга к другому:

Если два круга имеют разные размеры, то градиент принимает форму конуса.
В этой статье эти градиенты рассматриваются более подробно.
Радиальный градиент
Метод CreateRadialGradient имеет следующий синтаксис:
public static SKShader CreateRadialGradient (SKPoint center, Single radius, SKColor[] colors, Single[] colorPos, SKShaderTileMode mode)
Перегрузка CreateRadialGradient также включает параметр матрицы преобразования.
Первые два аргумента указывают центр круга и радиус. Градиент начинается с этого центра и распространяется наружу для radius пикселей. Что происходит дальше radius , зависит от аргумента SKShaderTileMode . Параметр colors представляет собой массив из двух или более цветов (как и в методах линейного градиента) и colorPos представляет собой массив целых чисел в диапазоне от 0 до 1. Эти целые числа указывают относительные положения цветов вдоль этой radius линии. Для этого аргумента можно задать значение null , чтобы равное пространство цветов было равно.
Если вы используете для CreateRadialGradient заполнения круга, можно задать центр градиента в центр круга, а радиус градиента — радиус круга. В этом случае SKShaderTileMode аргумент не влияет на отрисовку градиента. Но если область, заполненная градиентом, больше круга, определенного градиентом, то SKShaderTileMode аргумент оказывает глубокое влияние на то, что происходит за пределами круга.
Эффект демонстрируется на странице Радиальный градиент SKShaderMode в примере SkiaSharpFormsDemos. XAML-файл для этой страницы создает экземпляр , Picker который позволяет выбрать один из трех элементов перечисления SKShaderTileMode :
Файл кода программной части окрашивает весь холст радиальным градиентом. Центр градиента устанавливается в центр холста, а радиус равен 100 пикселям. Градиент состоит всего из двух цветов: черного и белого:
public partial class RadialGradientPage : ContentPage < public RadialGradientPage () < InitializeComponent (); >void OnPickerSelectedIndexChanged(object sender, EventArgs args) < canvasView.InvalidateSurface(); >void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args) < SKImageInfo info = args.Info; SKSurface surface = args.Surface; SKCanvas canvas = surface.Canvas; canvas.Clear(); SKShaderTileMode tileMode = (SKShaderTileMode)(tileModePicker.SelectedIndex == -1 ? 0 : tileModePicker.SelectedItem); using (SKPaint paint = new SKPaint()) < paint.Shader = SKShader.CreateRadialGradient( new SKPoint(info.Rect.MidX, info.Rect.MidY), 100, new SKColor[] < SKColors.Black, SKColors.White >, null, tileMode); canvas.DrawRect(info.Rect, paint); > > >
Этот код создает градиент с черным цветом в центре, постепенно увядая до белого на 100 пикселей от центра. Что происходит за пределами этого радиуса, зависит от аргумента SKShaderTileMode :

Во всех трех случаях градиент заполняет холст. На экране iOS слева градиент за радиус продолжается с последним цветом, который является белым. Это результат SKShaderTileMode.Clamp . На экране Android показан эффект SKShaderTileMode.Repeat : в 100 пикселях от центра градиент снова начинается с первого цвета, который является черным. Градиент повторяется каждые 100 пикселей радиуса.
На экране универсальная платформа Windows справа показано, как SKShaderTileMode.Mirror градиенты переходит в альтернативные направления. Первый градиент — от черного в центре до белого с радиусом 100 пикселей. Следующий — белый от радиуса 100 пикселей до черного в радиусе 200 пикселей, а следующий градиент снова возвращается обратно.
В радиальном градиенте можно использовать более двух цветов. В примере градиента радужной дуги создается массив из восьми цветов, соответствующих цветам радуги и заканчивающегося красным, а также массив из восьми позиционных значений:
public class RainbowArcGradientPage : ContentPage < public RainbowArcGradientPage () < Title = "Rainbow Arc Gradient"; SKCanvasView canvasView = new SKCanvasView(); canvasView.PaintSurface += OnCanvasViewPaintSurface; Content = canvasView; >void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args) < SKImageInfo info = args.Info; SKSurface surface = args.Surface; SKCanvas canvas = surface.Canvas; canvas.Clear(); using (SKPaint paint = new SKPaint()) < float rainbowWidth = Math.Min(info.Width, info.Height) / 4f; // Center of arc and gradient is lower-right corner SKPoint center = new SKPoint(info.Width, info.Height); // Find outer, inner, and middle radius float outerRadius = Math.Min(info.Width, info.Height); float innerRadius = outerRadius - rainbowWidth; float radius = outerRadius - rainbowWidth / 2; // Calculate the colors and positions SKColor[] colors = new SKColor[8]; float[] positions = new float[8]; for (int i = 0; i < colors.Length; i++) < colors[i] = SKColor.FromHsl(i * 360f / 7, 100, 50); positions[i] = (i + (7f - i) * innerRadius / outerRadius) / 7f; >// Create sweep gradient based on center and outer radius paint.Shader = SKShader.CreateRadialGradient(center, outerRadius, colors, positions, SKShaderTileMode.Clamp); // Draw a circle with a wide line paint.Style = SKPaintStyle.Stroke; paint.StrokeWidth = rainbowWidth; canvas.DrawCircle(center, radius, paint); > > >
Предположим, что минимальная ширина и высота холста составляет 1000, что означает, что rainbowWidth значение равно 250. Для значений outerRadius и innerRadius заданы значения 1000 и 750 соответственно. Эти значения используются для вычисления массива positions ; восемь значений находятся в диапазоне от 0,75f до 1. Значение radius используется для поглаживания круга. Значение 875 означает, что ширина штриха 250 пикселей простирается от радиуса 750 до 1000 пикселей:

Если вы заполнили весь холст этим градиентом, вы увидите, что он красный в пределах внутреннего радиуса. Это связано с тем, positions что массив не начинается с 0. Первый цвет используется для смещений от 0 до первого значения массива. Градиент также красный за пределами внешнего радиуса. Это результат режима плитки Clamp . Так как градиент используется для поглаживания толстой линии, эти красные области не видны.
Радиальные градиенты для маскирования
Как и линейные градиенты, радиальные градиенты могут включать прозрачные или частично прозрачные цвета. Эта функция полезна для процесса маскирования, который скрывает часть изображения, чтобы подчеркнуть другую часть изображения.
Пример показан на странице Маска радиального градиента . Программа загружает одно из растровых изображений ресурсов. Поля CENTER и RADIUS были определены на основе анализа растрового изображения и ссылки на область, которую необходимо выделить. Обработчик PaintSurface начинается с вычисления прямоугольника для отображения растрового изображения, а затем отображает его в этом прямоугольнике:
public class RadialGradientMaskPage : ContentPage < SKBitmap bitmap = BitmapExtensions.LoadBitmapResource( typeof(RadialGradientMaskPage), "SkiaSharpFormsDemos.Media.MountainClimbers.jpg"); static readonly SKPoint CENTER = new SKPoint(180, 300); static readonly float RADIUS = 120; public RadialGradientMaskPage () < Title = "Radial Gradient Mask"; SKCanvasView canvasView = new SKCanvasView(); canvasView.PaintSurface += OnCanvasViewPaintSurface; Content = canvasView; >void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args) < SKImageInfo info = args.Info; SKSurface surface = args.Surface; SKCanvas canvas = surface.Canvas; canvas.Clear(); // Find rectangle to display bitmap float scale = Math.Min((float)info.Width / bitmap.Width, (float)info.Height / bitmap.Height); SKRect rect = SKRect.Create(scale * bitmap.Width, scale * bitmap.Height); float x = (info.Width - rect.Width) / 2; float y = (info.Height - rect.Height) / 2; rect.Offset(x, y); // Display bitmap in rectangle canvas.DrawBitmap(bitmap, rect); // Adjust center and radius for scaled and offset bitmap SKPoint center = new SKPoint(scale * CENTER.X + x, scale * CENTER.Y + y); float radius = scale * RADIUS; using (SKPaint paint = new SKPaint()) < paint.Shader = SKShader.CreateRadialGradient( center, radius, new SKColor[] < SKColors.Transparent, SKColors.White >, new float[] < 0.6f, 1 >, SKShaderTileMode.Clamp); // Display rectangle using that gradient canvas.DrawRect(rect, paint); > > >
После рисования растрового изображения некоторый простой код преобразует CENTER и RADIUS center в и radius , которые ссылаются на выделенную область в растровом рисунке, масштабируемом и смещенном для отображения. Эти значения используются для создания радиального градиента с этим центром и радиусом. Два цвета начинаются с прозрачным в центре и для первых 60 % радиуса. Затем градиент исчезает до белого цвета:

Этот подход не является лучшим способом маскировки растрового изображения. Проблема заключается в том, что маска в основном имеет белый цвет, который был выбран в соответствии с фоном холста. Если фон имеет другой цвет или, возможно, сам градиент, он не будет совпадать. Лучший подход к маскировке показан в статье SkiaSharp Porter-Duff режимов наложения.
Радиальные градиенты для отраженных выделений
Когда свет попадает на скругленную поверхность, он отражает свет во многих направлениях, но часть света отскакивает непосредственно в глаза зрителю. Это часто создает вид нечеткой белой области на поверхности, называемой зеркальной подсветкой.
В трехмерной графике зеркальное выделение часто является результатом алгоритмов, используемых для определения световых путей и заливки. В двумерной графике иногда добавляются зеркальные выделения, чтобы предложить внешний вид трехмерной поверхности. Зеркальное выделение может превратить плоский красный круг в круглый красный шар.
На странице «Радиальное зеркальное выделение » для этого используется радиальный градиент. Обработчик PaintSurface вычисляет радиус для круга и два SKPoint значения — a center и , направляемые offCenter на полпути между центром и верхним левым краем круга:
public class RadialSpecularHighlightPage : ContentPage < public RadialSpecularHighlightPage() < Title = "Radial Specular Highlight"; SKCanvasView canvasView = new SKCanvasView(); canvasView.PaintSurface += OnCanvasViewPaintSurface; Content = canvasView; >void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args) < SKImageInfo info = args.Info; SKSurface surface = args.Surface; SKCanvas canvas = surface.Canvas; canvas.Clear(); float radius = 0.4f * Math.Min(info.Width, info.Height); SKPoint center = new SKPoint(info.Rect.MidX, info.Rect.MidY); SKPoint offCenter = center - new SKPoint(radius / 2, radius / 2); using (SKPaint paint = new SKPaint()) < paint.Shader = SKShader.CreateRadialGradient( offCenter, radius / 2, new SKColor[] < SKColors.White, SKColors.Red >, null, SKShaderTileMode.Clamp); canvas.DrawCircle(center, radius, paint); > > >
Вызов CreateRadialGradient создает градиент, который начинается в offCenter этой точке с белым цветом и заканчивается красным цветом на расстоянии половины радиуса. Вот как оно выглядит:

Если присмотреться к этому градиенту, можно решить, что он имеет недостатки. Градиент сосредоточен вокруг определенной точки, и может потребоваться, чтобы он был немного менее симметричным, чтобы отразить скругленные поверхности. В этом случае вы можете предпочесть зеркальное выделение, показанное ниже в разделе Конические градиенты для зеркальных выделений.
Градиент очистки
Метод CreateSweepGradient имеет самый простой синтаксис из всех методов создания градиента:
public static SKShader CreateSweepGradient (SKPoint center, SKColor[] colors, Single[] colorPos)
Это просто центр, массив цветов и позиций цветов. Градиент начинается справа от центральной точки и подметает 360 градусов по часовой стрелке вокруг центра. Обратите внимание, что параметр отсутствует SKShaderTileMode .
Также CreateSweepGradient доступна перегрузка с параметром преобразования матрицы. Вы можете применить преобразование поворота к градиенту, чтобы изменить начальную точку. Вы также можете применить преобразование масштаба, чтобы изменить направление с часовой стрелки на против часовой стрелки.
На странице Градиент очистки используется градиент развертки для цвета круга с шириной штриха 50 пикселей:

Класс SweepGradientPage определяет массив из восьми цветов с разными значениями оттенков. Обратите внимание, что массив начинается и заканчивается красным цветом (значение оттенка 0 или 360), который отображается справа на снимках экрана:
public class SweepGradientPage : ContentPage < bool drawBackground; public SweepGradientPage () < Title = "Sweep Gradient"; SKCanvasView canvasView = new SKCanvasView(); canvasView.PaintSurface += OnCanvasViewPaintSurface; Content = canvasView; TapGestureRecognizer tap = new TapGestureRecognizer(); tap.Tapped += (sender, args) =>< drawBackground ^= true; canvasView.InvalidateSurface(); >; canvasView.GestureRecognizers.Add(tap); > void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args) < SKImageInfo info = args.Info; SKSurface surface = args.Surface; SKCanvas canvas = surface.Canvas; canvas.Clear(); using (SKPaint paint = new SKPaint()) < // Define an array of rainbow colors SKColor[] colors = new SKColor[8]; for (int i = 0; i < colors.Length; i++) < colors[i] = SKColor.FromHsl(i * 360f / 7, 100, 50); >SKPoint center = new SKPoint(info.Rect.MidX, info.Rect.MidY); // Create sweep gradient based on center of canvas paint.Shader = SKShader.CreateSweepGradient(center, colors, null); // Draw a circle with a wide line const int strokeWidth = 50; paint.Style = SKPaintStyle.Stroke; paint.StrokeWidth = strokeWidth; float radius = (Math.Min(info.Width, info.Height) - strokeWidth) / 2; canvas.DrawCircle(center, radius, paint); if (drawBackground) < // Draw the gradient on the whole canvas paint.Style = SKPaintStyle.Fill; canvas.DrawRect(info.Rect, paint); >> > >
Программа также реализует TapGestureRecognizer , который включает некоторый код в конце обработчика PaintSurface . Этот код использует тот же градиент для заполнения холста:

На этих снимках экрана показано, что градиент заполняет любую область, окрашенную им. Если градиент не начинается и не заканчивается тем же цветом, справа от центральной точки будет разрыв.
Двухточечный конический градиент
public static SKShader CreateTwoPointConicalGradient (SKPoint startCenter, Single startRadius, SKPoint endCenter, Single endRadius, SKColor[] colors, Single[] colorPos, SKShaderTileMode mode)
Параметры начинаются с центральных точек и радиусов для двух кругов, называемых начальным и конечным кругом. Остальные три параметра совпадают с параметрами для CreateLinearGradient и CreateRadialGradient . Перегрузка CreateTwoPointConicalGradient включает в себя матричное преобразование.
Градиент начинается с начального круга и заканчивается в конце круга. Параметр SKShaderTileMode определяет, что происходит за пределами двух кругов. Двухточечный конический градиент является единственным градиентом, который не полностью заполняет область. Если два круга имеют одинаковый радиус, градиент ограничивается прямоугольником с шириной, которая совпадает с диаметром кругов. Если два круга имеют разные радиусы, градиент образует конус.
Скорее всего, вы захотите поэкспериментировать с коническим градиентом из двух точек, поэтому страница конического градиента является производным от InteractivePage , чтобы разрешить перемещение двух точек касания для двух кругового радиуса:
Файл кода программной части определяет два TouchPoint объекта с фиксированными радиусами 50 и 100:
public partial class ConicalGradientPage : InteractivePage < const int RADIUS1 = 50; const int RADIUS2 = 100; public ConicalGradientPage () < touchPoints = new TouchPoint[2]; touchPoints[0] = new TouchPoint < Center = new SKPoint(100, 100), Radius = RADIUS1 >; touchPoints[1] = new TouchPoint < Center = new SKPoint(300, 300), Radius = RADIUS2 >; InitializeComponent(); baseCanvasView = canvasView; > void OnPickerSelectedIndexChanged(object sender, EventArgs args) < canvasView.InvalidateSurface(); >void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args) < SKImageInfo info = args.Info; SKSurface surface = args.Surface; SKCanvas canvas = surface.Canvas; canvas.Clear(); SKColor[] colors = < SKColors.Red, SKColors.Green, SKColors.Blue >; SKShaderTileMode tileMode = (SKShaderTileMode)(tileModePicker.SelectedIndex == -1 ? 0 : tileModePicker.SelectedItem); using (SKPaint paint = new SKPaint()) < paint.Shader = SKShader.CreateTwoPointConicalGradient(touchPoints[0].Center, RADIUS1, touchPoints[1].Center, RADIUS2, colors, null, tileMode); canvas.DrawRect(info.Rect, paint); >// Display the touch points here rather than by TouchPoint using (SKPaint paint = new SKPaint()) < paint.Style = SKPaintStyle.Stroke; paint.Color = SKColors.Black; paint.StrokeWidth = 3; foreach (TouchPoint touchPoint in touchPoints) < canvas.DrawCircle(touchPoint.Center, touchPoint.Radius, paint); >> > >
Массив colors имеет красный, зеленый и синий цвет. Код в нижней части обработчика PaintSurface рисует две точки касания в виде черных кругов, чтобы они не препятствовали градиенту.
Обратите внимание, что DrawRect вызов использует градиент для цвета всего холста. Однако в общем случае большая часть холста остается неокрашенных градиентом. Ниже приведена программа, показывающая три возможные конфигурации:

На экране iOS слева отображается эффект SKShaderTileMode настройки Clamp . Градиент начинается с красного цвета внутри края меньшего круга, который находится напротив стороны, ближайшей ко второму кругу. Значение Clamp также приводит к тому, что красный цвет будет продолжаться до точки конуса. Градиент заканчивается синим цветом на внешнем крае большего круга, который ближе всего к первому кругу, но продолжается синим цветом внутри этого круга и за его пределами.
Экран Android аналогичен, но с . SKShaderTileMode Repeat Теперь ясно, что градиент начинается внутри первого круга и заканчивается за пределами второго круга. Этот Repeat параметр приводит к повторному повтору градиента с красным цветом внутри большего круга.
На экране UWP показано, что происходит при перемещении меньшего круга целиком внутри большего круга. Градиент перестает быть конусом и заполняет всю область. Эффект аналогичен радиальному градиенту, но он асимметричен, если меньшая окружность не находится точно по центру в пределах большего круга.
Вы можете сомневаться в практической полезности градиента, когда один круг вложен в другой, но он идеально подходит для зеркального выделения.
Конические градиенты для зеркальных выделений
Ранее в этой статье вы узнали, как использовать радиальный градиент для создания зеркального выделения. Для этой цели можно также использовать конический градиент с двумя точками, и вы можете предпочесть, как он выглядит:

Асимметричный внешний вид лучше предполагает округленную поверхность объекта.
Код рисования на странице конического зеркального выделения совпадает со страницей «Радиальное выделение зеркального отображения «, за исключением шейдера:
public class ConicalSpecularHighlightPage : ContentPage < ··· void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args) < ··· using (SKPaint paint = new SKPaint()) < paint.Shader = SKShader.CreateTwoPointConicalGradient( offCenter, 1, center, radius, new SKColor[] < SKColors.White, SKColors.Red >, null, SKShaderTileMode.Clamp); canvas.DrawCircle(center, radius, paint); > > >
Эти два круга имеют центры offCenter и center . Окружность по центру center связана с радиусом, охватывающим весь шар, но окружность, центрированная в offCenter , имеет радиус всего в один пиксель. Градиент фактически начинается в этой точке и заканчивается на краю мяча.
Связанные ссылки
- API SkiaSharp
- SkiaSharpFormsDemos (пример)
Как сделать красивый градиент в Adobe Photoshop

Всем привет! Сегодня я хочу рассказать вам о том, как пользоваться инструментами для создания градиентов в Фотошопе.
Градиенты и цветовые переходы часто используются в современном графическом дизайне – этот тренд ворвался в визуальную среду еще в 2018 и все еще не теряет своей актуальности. Дизайнеры используют градиенты для оформления фонов, иконок, типографики и многого другого, а еще с его помощью можно имитировать 3D!
Что самое главное для новичков в Photoshop – сделать градиент очень просто. Давайте разберем процесс на примерах.
Как создать свой градиент в Фотошопе
- Откройте инструмент «Градиент». Он находится на панели инструментов в левой части экрана Adobe Photoshop. Если он не отображается сразу – просто кликните правой кнопкой мыши по «Заливке» и выберите его в выпадающем меню.

- В верхней части экрана появится изображение градиента. Кликните по нему.

- Открылось окно редактора градиентов. Щелкните по контрольной точке, а затем на окошко «Цвет».

- Теперь задайте цвет. Я хочу сделать переход от сиреневого к темно-фиолетовому. Выбираю для этой точки наиболее светлый оттенок и нажимаю ОК.

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

- Сохраните свой новый градиент, нажав на кнопку «Новый». Теперь он всегда будет лежать в списке градиентов в этом окне.

Комьюнити теперь в Телеграм
Подпишитесь и будьте в курсе последних IT-новостей
Как сделать фон градиентом
- Чтобы залить фон градиентом, выберите инструмент «Градиент».
- Затем кликните мышью в той части экрана, откуда будет начинаться заливка.
- Проведите мышью по экрану.
Например, чтобы сделать переход цвета, как показано ниже, щелкните и проведите мышью сверху вниз.

А чтобы сделать такой переход, я кликнула и провела мышкой по диагонали справа налево. Попробуйте! Это работает во все стороны.

Как залить объект градиентом
Если делать заливку объектов градиентом в Фотошопе, можно добиться классного эффекта 3D, который в этом году самый трендовый. Я хочу показать вам, как сделать вот такую картинку:

Какой получается объем! На этом примере вы поймете все основные принципы использования градиента на объектах в Photoshop. Смотрите пошаговую инструкцию:
- Я создаю новый документ и заливаю фон сохраненным градиентом, как я показывала в предыдущем пункте.
- Чтобы создать шары, я воспользуюсь инструментом «Эллипс». Находится он вот здесь.

- С зажатой клавишей Shift создаю эллипс. Он автоматически появляется на новом слое. В меню «Заливка» можно выбрать цвет.

- Теперь дважды кликаю по слою с эллипсом, и появляется окно стилей.

- Тут нужно нажать «Наложение градиента» (слева), а потом кликнуть по окошку с градиентом, чтобы настроить цвет.

- Я хочу сделать шарик в малиновых тонах. Выбираю, какого цвета будет светлая и теневая сторона шара.

- Настраиваю угол, чтобы «освещение» объекта совпадало с градиентом фона.

Первый этап пройден. Это главное, что вам нужно знать о заливке объектов градиентом. Но если вы хотите повторить мою картинку, смотрите дальше.
Давайте добавим немного «натуральности», чтобы шарик выглядел объемнее.
- Добавляю пункт «Внутренняя тень» и щелкаю по цвету.

- Выбираю цвет тени. Пусть уходит в фиолетовый.

- Теперь настрою угол, непрозрачность, смещение и размер этой тени. Поиграйте с ползунками, чтобы создать наиболее натуральный и мягкий эффект. После этого закройте окно стилей.

Теперь я хочу скопировать и изменить размер объекта. Для копирования щелкните по объекту с инструментом «Перемещение» (V на клавиатуре) и с зажатой клавишей Ctrl сдвиньте его в сторону. Объект оказался на новом слое.

Чтобы он масштабировался с эффектами, нажмите правой кнопкой мыши по слою, а затем на «Преобразовать в смарт-объект».

Таким образом я несколько раз копирую и размещаю шарик в разных местах. Далее с помощью инструмента «Перо кривизны» (P) я нарисую еще один объект.

Нужно сделать заливку этого объекта с такими же настройками, как у шаров. Для этого я нажимаю правой кнопкой мыши по слою с первым шаром (который не смарт-объект) и копирую стиль слоя. Эта функция позволяет скопировать все настройки, которые мы делаем в окне стилей слоя.

Теперь нужно щелкнуть правой кнопкой мыши по слою с новой фигурой и вклеить стиль слоя.

Смотрите, теперь новый объект, нарисованный пером, выглядит так же. Эта функция работает для всех новых объектов, которые вы создадите.

То же самое я делаю для еще одной фигуры. Но здесь я подумала, что неплохо было бы добавить внутреннее свечение, чтобы создавалась иллюзия, как свет «обволакивает» ее. Дважды кликаю по слою с новой фигурой, чтобы вызвать окно стилей, и добавляю свечение.

Можете скопировать еще несколько шаров и добавить фильтр «Размытие по Гауссу», чтобы казалось, что они плавают где-то вдалеке. То же самое и для объекта на переднем плане – так будет выглядеть правдивее. Вот вам и имитация 3D в Фотошопе.
Как наложить градиент на текст

Наложить градиент на текст очень просто: мы будем пользоваться тем же окном стилей слоя. Давайте напишем какой-нибудь текст. Я просто возьму слово «Gradient», написанное жирным шрифтом черного цвета. Итак:
- Дважды кликните по слою с текстом и выберите «Наложение градиента» в новом окне.

- Выберите градиент из готовых наборов либо создайте свой. О том, как сделать собственный градиент, я писала выше в этой статье.

- Вы можете изменять угол и масштаб наложения градиента, чтобы добиться желаемого эффекта.

- Если добавить новую точку цвета, можно создавать градиент из трех или более оттенков. Экспериментируйте!

Как наложить градиент на фото в Adobe Photoshop

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

- Пройдите по вкладкам «Изображение» – «Коррекция» – «Карта градиента».

- Щелкните по линии с градиентом, чтобы открыть редактор и изменить цвета контрольных точек.

Где взять идеи для градиентов: лучшие сервисы
Создать красивый градиент самостоятельно не всегда легко. А бывает, что просто нет времени для раздумий. Для этого и придумали сервисы, где можно подсмотреть идеи градиентов. Я подобрала для вас 3 лучших.
Coolors

На этом сайте можно просматривать как готовые наборы градиентов, так и создавать собственные. У цветов имеются номера, так что их с легкостью можно перенести в любой редактор.
Перейти на ресурс можно по ссылке.
Uigradients

Здесь вы можете посмотреть самые невероятные варианты сочетаний. Хорош сервис тем, что градиенты можно посмотреть в полноэкранном формате. И еще есть маленькая фишка: каждый градиент имеет уникальное название, поэтому выглядит это очень атмосферно. Как вам градиент под именем Moonlit Asteroid?
Изучите остальные варианты здесь.
CoolHue

Небольшая, но очень милая коллекция готовых градиентов. Любой из них можно загрузить в виде PNG-изображения.
Заключение
Создать градиент в Фотошопе не такое уж трудное дело, правда? Оставаясь в тренде, градиенты намертво закрепились в дизайне на ближайшие годы, поэтому знать, как их использовать, будет полезно для начинающего специалиста.
Надеюсь, что вы научились создавать и применять градиенты для ваших проектов, изучив этот материал. Удачи!
