Урок 5. Светотень — продолжение. Как рисовать фрукты
В этом уроке мы вновь поработаем со светотенью, но теперь для предметов округлой формы, подобных шару, конусу, цилиндру, а также для тех, которые сочетают в себе несколько таких форм.
Для начала вернемся к тону. Тональное разнообразие, существующее в природе, очень широко. Наш глаз способен различить не все тона, но с практикой художник видит больше тональных нюансов. Однако художественные материалы не справляются со всеми теми изменениями тона, которые мы наблюдаем. В рисунке мы имеем дело с более узким тональным диапазоном, упрощенной версией. Например, мы не можем иногда передать всю яркость блика или черноту самых темных участков теней. Таким образом в рисунке важно выстраивать свой тональный диапазон. Например, если тень получается более светлой, чем в натуре, то относительно нее смещаем полутень и свет к более светлым тонам.
Содержание:
- Тональная шкала
- Светотень на предметах округлой формы
- Рисуем яйцо
- Рисуем грушу
- Подсказки при работе со светотенью
- Проверочный тест
Тональная шкала
Давайте начнем с упражнения, которое учит замечать тональные нюансы, а также передавать их в рисунке. Это определяет, насколько объемными будут получаться наши работы. Например, если тени нарисованы недостаточно темно, а свет – недостаточно светло, если затененные области проработаны без тональных нюансов (равномерно), то изображение будет выглядеть более плоским.
Давайте нарисуем тональную шкалу от белого к темно-серому.
Начнем с прямоугольника, состоящего из 7-8 сегментов.
А теперь начнем заполнять его тоном. Первый сегмент оставим белым, последний будет наиболее насыщенный по тону. Слева направо тон постепенно нарастает (каждый последующий сегмент должен быть чуть-чуть темнее предыдущего). Сначала заполняем тоном крайние сегменты, а потом постепенно двигаемся к центру. Для первых сегментов удобно использовать твердый карандаш (например, 2Н или Н), для средних – НВ, а для последних – 2В и мягче. Регулируем степень нажима на карандаш. Для светлых используем более легкий и наоборот. Сложно сразу угадать тон. Поэтому по мере появления новых сегментов придется корректировать тональную насыщенность ранее заштрихованных. Высветлять тон сложнее, поэтому важно не штриховать сразу в полную силу, а затемнять тон постепенно (слоями), по мере появления новых сегментов и возможности сравнивать.
Старайтесь тонировать сегменты равномерно, чтобы они были одного тона на всем своем протяжении. Периодически смотрите на шкалу с расстояния – так проще видеть разницу в тоне.
Это очень непростое упражнение, но ценное. Важно не спешить с ним. Его можно начать и с более простой шкалы, состоящей из 5-6 сегментов. А потом перейти к 8 и далее. Кстати, эту шкалу можно использовать, чтобы сравнивать друг с другом разные участки в рисунке. Например, чтобы проверить, не слишком ли светел рефлекс, сравнив его с полутенью.
Светотень на предметах округлой формы
Как будет выглядеть светотень на подобных предметах? Представьте, что у нас есть яблоко. Мы разрезаем его, при этом держим нож под наклоном – перпендикулярно лучам света. Справа показаны линии разрезов. Они имеют округлые очертания из-за округлой объемной формы яблока. Форма элементов светотени соответствует этим линиям разрезов.
Вот как это выглядит на примере реальной объемной формы (бледно-голубым показаны невидимые части линий «разрезов»). Здесь видно, что граница тени и рефлекса параллельны линиям разреза.
Рисуем яйцо
Давайте для разогрева сделаем несложное задание – нарисуем яйцо. Предлагаем работать со светотенью цветным карандашом, так как благодаря его мягкости мы сможем довольно быстро покрыть изображение тоном. Лучше взять более темный карандаш. Не тратьте много времени на точность контура. Здесь нам важно в первую очередь закрепить информацию о форме светотени и потренироваться накладывать штрихи на подобные округлые предметы.
Шаг 1. Наметим общие габариты для яйца и падающей тени. Проведем оси и нарисуем яйцо. Пробуйте сделать это на глаз, без поиска наклона основных отрезков, образующих контур, или касательных. Нарисуем границы собственной тени и рефлекса.
Шаг 2. Заштрихуем собственную тень, не в полную силу. Обратите внимание на штрихи. Они не длинные, слегка скруглены и повторяют форму контура яйца и границы собственной тени. Темнее заштрихуем падающую тень, работая в горизонтальном направлении.
Шаг 3. Легкой штриховкой создадим полутень. Потом еще затемним собственную тень, обращая внимание на неравномерность ее тона. Она наиболее насыщена на границе с более освещенными участками. Ее нижняя половина светлее, особенно самая нижняя часть, которая касается падающей тени. От собственной тени делаем плавный переход к полутени. Для этого штрихуем от более темного участка к светлому, постепенно снижая нажим на карандаш и частоту штриха.
Шаг 4. Штрихами с очень легким нажимом покроем область света, не трогая блик. Сделаем еще темнее собственную тень на границе с полутенью. Создаем плавные переходы от более темных участков к более светлым. Падающую тень (особенно рядом с яйцом) и рефлекс тоже затемним. Рисунок готов!
Рисуем грушу
Давайте разберем, как выглядит светотень на предметах, в основе которых заключено несколько форм. Например, для груши это усеченный конус (ее верх) и шар (основание). От верха груши часть тени падает на ее основание. А в остальном здесь действует вышеописанный принцип распределения светотени по линиям разрезов.
Приступим к рисованию:
Шаг 1. Начнем с общих параметров: соотношение ширины к высоте для груши и ее падающей тени. После того как отметили габариты, найдем оси для груши и направляющую для тени. Методом визирования найдем наклоны отрезков, образующих линию контура.
Шаг 2. Уточним контур, сделаем его более плавным и смягчим линии построения.
Шаг 3. Наметим контур собственной тени. Затем заполним ее штриховкой по форме, то есть ориентируясь на очертания груши и контур собственной тени. Пока набираем тон не в полную силу. Поработаем также с падающей тенью. Сделаем ее немного темнее собственной.
Шаг 4. Слегка заштрихуем полутень и свет на груше, а потом усилим собственную тень, при этом рефлексы слева оставляем немного светлее.
Шаг 5. Сделаем темнее полутень. От собственной тени создадим плавный переход к более освещенным участкам. При этом граница падающей тени от верхней части груши на ее основание будет более жесткой.
Шаг 6. Поработаем с плодоножкой и сделаем ее темнее слева. Нарисуем фрагмент ее падающей тени сверху на груше. Выделим тоном основание плодоножки. Усилим собственную и падающую тени груши. Ластиком можно высветлить блики.
Шаг 7. Теперь переходим к очень важному этапу – будем уточнять светотень. Смотрите на свою грушу и натуру (или фотографию) с расстояния, прищурив глаза. Сравнивайте расположение и темноту/светлоту тональных пятен, их форму. По необходимости уточняйте рисунок. Здесь рефлексы выглядят слишком светлыми на контрасте с тенями, поэтому сделаем их темнее. Затемним еще самые темные участки груши и падающую тень рядом с ней. Почему только рядом с ней, а не целиком, как на фото? Чтобы выделить грушу сильнее, для нее и рядом с ней используем наиболее контрастные пятна, а остальное делаем менее выразительным.
Шаг 8. Финальные штрихи: давайте сделаем намек на фактуру. Мягким карандашом с легким нажимом поставим немного точек в полутени, и несколько на свету. Не делаем их слишком выраженными – так они будут смотреться живее.
Подсказки при работе со светотенью
1 | Обращаем внимание на форму пятен тени, света, полутени, бликов, а также на четкость или размытость их границ. |
2 | Также важна форма пятен внутри элементов светотени, ведь они часто неравномерны по тону. |
3 | Прищуриваем глаза, чтобы сравнить тональные пятна в натуре и на рисунке. |
4 | Можно использовать белый лист бумаги как ориентир: поднести его к натюрморту и сравнивать с ним освещенные участки изображаемых объектов. |
5 | Часть тени, расположенная на границе с освещенными участками, наиболее темная. |
Проверьте свои знания
Если вы хотите проверить свои знания по теме данного урока, можете пройти небольшой тест, состоящий из нескольких вопросов. В каждом вопросе правильным может быть только 1 вариант. После выбора вами одного из вариантов, система автоматически переходит к следующему вопросу. На получаемые вами баллы влияет правильность ваших ответов и затраченное на прохождение время. Обратите внимание, что вопросы каждый раз разные, а варианты перемешиваются.
Cтатистика На весь экран
Юлия Отрубянникова← 4 Светотень6 Фактура →
Как рисовать картины по номерам
Дополнительно вам может понадобиться:— Стаканчик с водой – для промывки кисточек,
— Ватные палочки – для корректировки лишних штрихов,
— Салфетки.
Основные методы и техники раскрашивания картин по номерам
Не существует какой-то одной правильной техники. Вы можете выбрать и попробовать для себя любую, которая покажется вам наиболее удобной, или совместить их, а мы расскажем вам подробнее о каждой.
1. По цветам или от светлого к темному
Этим методом поочередно закрашиваются все области одного цвета на полотне. Лучше всего начиная закрашивать области светлых тонов постепенно двигаясь к темным участкам. При ошибке куда как проще закрасить помарку следующим, более темным тоном, чем наоборот. К плюсам данной техники закрашивания можно отнести удобство работы с красками. В один момент времени открыта только одна баночка. Не надо постоянно мыть кисти. К минусам – вам придется искать все участки с одним номером по всему холсту и стараться не смазать рукой уже закрашенные участки.
2. От большего к меньшему
На холсте выделяются самые крупные участки одного цвета и закрашиваются в первую очередь. Далее постепенно закрашиваются участки поменьше постепенно доходя до самых мелких. Данная техника позволяет практически не допускать погрешностей в закрашивании и исправлять их минимальными усилиями. Но кисточки придется мыть гораздо чаще.
3. По направлению:
3.1. Классический метод – Сверху вниз
Картина постепенно закрашивается линия за линией вниз. Смазывание красок исключено, так как рука всегда будет лежать на незакрашенных участках. По окончании последнего нижнего слоя, верхние слои уже будут практически сухими. Из минусов можно отметить частую смену баночек с красками и необходимость мыть кисточки.
3.2. От правого или левого края
Метод может оказать немного более удобным, чем обычный сверху вниз. Выбор направления от правого или левого края зависит от того, левша вы, или правша. Картина рисуется по диагонали. Смазывание уже раскрашенных участков практически исключено. Минусы данного метода аналогичны классическому методу – сверху вниз.
3.3. От центра – к краям
Раскрашивание картины начинается в центре и идет к ее краям. Для удобства можно немного поворачивать картину. Смазывания закрашенных областей исключены, но частую смену красок и промывку кисточек можно считать минусом метода.
3.4. От заднего плана к переднему
Метод больше подходит более опытным художникам. Вы сами определяете на полотне объекты заднего плана картины и раскрашиваете их в первую очередь. И постепенно переходите на объекты переднего плана. Данная техника позволяет придать картине глубину. Минусы данной техники очевидны – частая смена красок, промывка кисточек и вероятность задеть рукой и смазать уже закрашенные области.
Держим кисть правильно
Раскрашивание по номерам отличается от классического письма тем, что вы закрашиваете четко обозначенные и пронумерованные участки. Не так-то много возможностей для небрежных и размашистых мазков.
По нашему мнению, самым подходящим хватом кисточки будет классический способ подобный тому, как вы держите в руке ручку или карандаш. Он обеспечивает максимальный контроль над кистью и позволяет сделать четкие и точные мазки в пределах границ закрашиваемого участка. Если вы закрашиваете картину в первый раз, то не спешите сразу наносить краску на полотно. Возьмите кисть и попробуйте нанести несколько мазков на бумаге или картоне. Проверьте — удобно ли вам, как ложатся мазки. Посмотрите, с каким нажимом вам удобно наносить краску. После этого уже можете переходить к рабочему полотну.
Самый главный совет
Теперь, когда вы готовы выбрать и приобрести готовый набор для рисования с потрясающим сюжетом и приступить к раскрашиванию. Но помните, рисование – это расслабляющее и успокаивающее занятие. Почти что медитативное. Поэтому – не спешите и получайте от процесса удовольствие.
Ведь именно для этого и созданы картины по номерам.
python — Нарисуйте эллипс постепенного изменения в skimage
Начнем с подробного описания примера изображения.
- Это 4-канальное изображение (RGB + альфа-прозрачность), но оно использует только оттенки серого.
- Изображение очень хорошо вписывается в рисунок, поля вокруг фигуры минимальны.
- Имеется заполненный, сглаженный, повернутый внешний эллипс , окруженный прозрачным фоном.
- Внешний эллипс заполнен числом повернутый эллиптический градиент (концентрический и с тем же вращением, что и эллипс), черный по краю и линейно переходящий в белый в центре.
- На внешний эллипс накладывается концентрический, заполненный, сглаженный, повернутый
Далее, пусть:
-
a
иb
— большая и малая полуоси эллипса -
тета
угол поворота эллипса вокруг его центра в радианах (от 0до
точек по оси x) -
inner_scale
— это отношение между соответствующими осями внутреннего и внешнего эллипса (т. е. 0,5 означает, что внутренний масштаб уменьшен на 50%) -
h
иk
— координаты (x,y) центра эллипса
В продемонстрированном коде мы будем использовать следующие импорты:
импорт cv2 импортировать numpy как np импортировать математику
И задаем параметры, определяющие наш чертеж (рассчитаем h
и k
) как:
a, b = (360. 0, 200.0) # Большая и малая полуоси theta = math.radians(40.0) # Вращение эллипса (радианы) inner_scale = 0.6 # Масштаб внутреннего полностью белого эллипса
Первый шаг, который нам нужно сделать, чтобы сгенерировать такое изображение, это рассчитать, какой размер «холста» (изображения, на котором мы будем рисовать) нам нужен. Для этого мы можем вычислить ограничивающую рамку повернутого внешнего эллипса и добавить вокруг него небольшое поле.
Я не знаю о существующей функции OpenCV для эффективного выполнения этой задачи, но StackOverflow спасает ситуацию — уже есть связанный вопрос с ответом, связанным со ссылкой на полезную статью, в которой обсуждается проблема. Мы можем использовать эти ресурсы для следующей реализации Python:
def ellipse_bbox(h, k, a, b, theta): ux = a * math.cos(тета) uy = a * math.sin(тета) vx = b * math.cos (тета + math.pi / 2) vy = b * math.sin(тета + math.pi / 2) box_halfwidth = np.ceil (math.sqrt (ux ** 2 + vx ** 2)) box_halfheight = np.ceil (math.sqrt (uy ** 2 + vy ** 2)) return ((int(h - box_halfwidth), int(k - box_halfheight)) , (int(h + box_halfwidth), int(k + box_halfheight)))
NB: Я округляю размеры с плавающей запятой в большую сторону, так как мы должны покрывать целые пиксели и возвращать верхний левый и нижний правый углы как целые пары (x,y).
Затем мы можем использовать функцию следующим образом:
# Вычислить размер изображения, необходимый для рисования и центрирования эллипса. _, (h, k) = ellipse_bbox(0, 0, a, b, theta) # Центр эллипса h += 2 # Добавляем небольшое поле k += 2 # Добавляем небольшое поле ширина, высота = (h*2+1, k*2+1) # Размер холста
Второй шаг — создание слоя прозрачности. Это одноканальное 8-битное изображение, где черный цвет (0) представляет собой полностью прозрачное изображение, а белый (255) — полностью непрозрачные пиксели. Эта задача довольно проста, так как мы можем использовать cv2.эллипс
.
Мы можем определить наш внешний эллипс в виде структуры RotatedRect
(повернутый прямоугольник, плотно прилегающий к эллипсу). В Python это представлено в виде кортежа, содержащего:
- кортеж, представляющий центр повернутого прямоугольника (координаты x и y)
- кортеж, представляющий размер повернутого прямоугольника (его ширину и высоту)
- угол поворота в градусах
Вот код:
ellipse_outer = ((h,k), (a*2, b*2), math.степени(тета)) прозрачность = np.zeros((высота, ширина), np.uint8) cv2.ellipse(прозрачность, ellipse_outer, 255, -1, cv2.LINE_AA)
… и получаемое изображение:
В качестве третьего шага мы создаем одноканальное изображение (оттенки серого или интенсивность), содержащее желаемый повернутый эллиптический градиент . Но, прежде всего, как мы можем даже математически определить повернутый эллипс с точки зрения декартовой 9 декартовой диаграммы нашего изображения?0030 (x, y) координат, используя наши (a, b)
, theta
(θ) и (h, k)
параметры?
На этот раз Mathematics StackExchange спасает положение: есть вопрос, точно соответствующий нашей проблеме, и ответ, содержащий это полезное уравнение: сторона стороны оценивается как 1 по периметру эллипса. Это 0 в центре и линейно увеличивается к 1 по периметру, а затем дальше от него.
Назовем правую часть весом
за неимением лучшего термина. Поскольку он очень хорошо масштабируется от центра к краям, мы можем использовать его для расчета желаемого градиента. Наша формула дает нам белый (1,0 в случае изображения с плавающей запятой) снаружи и черный (0,0) в центре. Нам нужно обратное, поэтому мы просто вычитаем вес
из 1.0
и обрезаем результат до диапазона [0.0, 1.0]
.
Давайте начнем с простой реализации только для Python (например, при ручном переборе отдельных элементов numpy.array
, представляющий наше изображение) для расчета весов. Однако, поскольку мы ленивые программисты, мы будем использовать Numpy для преобразования рассчитанного веса
в изображение градации, используя векторизованное вычитание вместе с numpy.clip
.
Вот код:
def make_gradient_v1(width, height, h, k, a, b, theta): # Предварительный расчет констант ст, кт = math.sin(тета), math.cos(тета) аа, бб = а**2, б**2 веса = np.zeros ((высота, ширина), np.float64) для y в диапазоне (высота): для x в диапазоне (ширина): веса[y,x] = ((((x-h) * ct + (y-k) * st) ** 2) / aa +(((х-з)*ст-(у-к)*ст)**2)/бб) вернуть np.clip (1.0 - веса, 0, 1)
… и получаемое изображение:
Это все красиво и красиво, но так как мы перебираем каждый пиксель и делаем вычисления в интерпретаторе Python, это также ааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааа его его его работы занимает, может быть, секунду, но мы используем Numpy, поэтому мы наверняка сможем добиться большего успеха, если воспользуемся его преимуществами. Это означает векторизацию всего, что мы можем.
Прежде всего, давайте заметим, что единственным входом, который меняется, являются координаты каждого заданного пикселя. Это означает, что для векторизации нашего алгоритма нам нужны в качестве входных данных два массива (того же размера, что и изображение), содержащие x
и y
координаты каждого пикселя. К счастью, Numpy предоставляет нам инструмент для создания таких массивов — numpy.mgrid
. Мы можем написать
y,x = np.mgrid[:height,:width]
для генерации необходимых нам входных массивов. Однако давайте заметим, что мы никогда не используем x
и y
напрямую — мы всегда компенсируем их константой. Давайте избежим этой операции смещения, создав x-h
и y-k
…
y,x = np.mgrid[-k:height-k,-h:width-h]
Мы снова можем предварительно вычислить 4 константы, а кроме того, остальное — просто векторизованное сложение, вычитание, умножение, деление и степени, которые предоставляются Numpy как векторизованные операции (т.е. намного быстрее).
def make_gradient_v2 (ширина, высота, h, k, a, b, тета): # Предварительный расчет констант ст, кт = math.sin(тета), math.cos(тета) аа, бб = а**2, б**2 # Генерация (x,y) массивов координат y,x = np.mgrid[-k:высота-k,-h:ширина-h] # Рассчитываем вес каждого пикселя веса = (((x * ct + y * st) ** 2) / aa) + (((x * st - y * ct) ** 2) / bb) вернуть np. clip (1.0 - веса, 0, 1)
Сценарий, использующий эту версию, занимает около 30% времени по сравнению со сценарием, использующим только Python. Ничего ошеломляющего, но результат тот же, и эта задача кажется чем-то, что вам не нужно делать часто, так что мне этого достаточно.
Если вы [читатель] знаете более быстрый способ, опубликуйте его как ответ.
Теперь у нас есть изображение с плавающей запятой, интенсивность которого находится в диапазоне от 0,0 до 1,0. Чтобы сгенерировать наш результат, мы хотим иметь 8-битное изображение со значениями от 0 до 255.
интенсивность = np.uint8 (make_gradient_v2 (ширина, высота, h, k, a, b, тета) * 255)
Четвертый шаг — нарисуйте внутренний эллипс . Это просто, мы делали это раньше. Нам просто нужно масштабировать оси соответствующим образом.
ellipse_inner = ((h,k), (a*2*inner_scale, b*2*inner_scale), math.степени(тета)) cv2.ellipse(интенсивность, ellipse_inner, 255, -1, cv2. LINE_AA)
Это дает нам следующее изображение интенсивности:
Пятый шаг — мы почти закончили. Все, что нам нужно сделать, это объединить слои интенсивности и прозрачности в изображение BGRA, а затем сохранить его в формате PNG.
результат = cv2.merge([интенсивность, интенсивность, интенсивность, прозрачность])
NB: Использование одинаковой интенсивности для красного, зеленого и синего дает нам только оттенки серого.
Когда мы сохраняем результат, мы получаем следующее изображение:
Учитывая, что я предположил параметры, которые вы использовали для создания образца изображения, я бы сказал, что результат моего скрипта чертовски близок. Он также работает достаточно быстро — если вы хотите чего-то лучшего, вы, вероятно, не сможете избежать приближения к «голому железу» (C, C++ и т. д.). Более разумный подход или, возможно, графический процессор могли бы работать еще лучше. Стоит поэкспериментировать с. ..
В заключение, вот небольшая демонстрация того, что этот код также работает для других ротаций:
И полный сценарий, который я использовал для написания этого:
import cv2 импортировать numpy как np импортировать математику # ================================================ ============================ def ellipse_bbox (ч, к, а, б, тета): ux = a * math.cos(тета) uy = a * math.sin(тета) vx = b * math.cos (тета + math.pi / 2) vy = b * math.sin(тета + math.pi / 2) box_halfwidth = np.ceil (math.sqrt (ux ** 2 + vx ** 2)) box_halfheight = np.ceil (math.sqrt (uy ** 2 + vy ** 2)) return ((int(h - box_halfwidth), int(k - box_halfheight)) , (int(h + box_halfwidth), int(k + box_halfheight))) # -------------------------------------------------- --------------------------- # Повернутый эллиптический градиент - медленный подход только для Python def make_gradient_v1 (ширина, высота, h, k, a, b, тета): # Предварительный расчет констант ст, кт = math. sin(тета), math.cos(тета) аа, бб = а**2, б**2 веса = np.zeros ((высота, ширина), np.float64) для y в диапазоне (высота): для x в диапазоне (ширина): веса[y,x] = ((((x-h) * ct + (y-k) * st) ** 2) / aa +(((х-з)*ст-(у-к)*ст)**2)/бб) вернуть np.clip (1.0 - веса, 0, 1) # -------------------------------------------------- --------------------------- # Повернутый эллиптический градиент - более быстрый, векторизованный подход numpy def make_gradient_v2 (ширина, высота, h, k, a, b, тета): # Предварительный расчет констант ст, кт = math.sin(тета), math.cos(тета) аа, бб = а**2, б**2 # Генерация (x,y) массивов координат y,x = np.mgrid[-k:высота-k,-h:ширина-h] # Рассчитываем вес каждого пикселя веса = (((x * ct + y * st) ** 2) / aa) + (((x * st - y * ct) ** 2) / bb) вернуть np.clip (1.0 - веса, 0, 1) # ================================================ ============================ def draw_image(a, b, theta, inner_scale, save_intermediate=False): # Рассчитать размер изображения, необходимый для рисования этого и центрирования эллипса _, (h, k) = ellipse_bbox(0,0,a,b,theta) # Центр эллипса h += 2 # Добавляем небольшое поле k += 2 # Добавляем небольшое поле ширина, высота = (h*2+1, k*2+1) # Размер холста # Параметры, определяющие два эллипса для OpenCV (структура RotatedRect) ellipse_outer = ((h,k), (a*2, b*2), math. степени(тета)) ellipse_inner = ((h,k), (a*2*inner_scale, b*2*inner_scale), math.степени(тета)) # Создаем слой прозрачности -- внешний эллипс заполнен и сглажен. прозрачность = np.zeros((высота, ширина), np.uint8) cv2.ellipse(прозрачность, ellipse_outer, 255, -1, cv2.LINE_AA) если save_intermediate: cv2.imwrite("eligrad-t.png", прозрачность) # Сохранить промежуточный файл для демонстрации # Генерируем градиент и масштабируем его до 8-битного диапазона оттенков серого интенсивность = np.uint8 (make_gradient_v1 (ширина, высота, h, k, a, b, тета) * 255) если save_intermediate: cv2.imwrite("eligrad-i1.png", Intensity) # Сохранить промежуточный файл для демонстрации # Нарисуйте промежуточный эллипс, заполненный и сглаженный cv2.ellipse(интенсивность, ellipse_inner, 255, -1, cv2.LINE_AA) если save_intermediate: cv2.imwrite("eligrad-i2.png", Intensity) # Сохранить промежуточный файл для демонстрации # Превратить его в образ BGRA результат = cv2. merge([интенсивность, интенсивность, интенсивность, прозрачность]) вернуть результат # ================================================ ============================ a, b = (360.0, 200.0) # Большая и малая полуоси theta = math.radians(40.0) # Вращение эллипса (радианы) inner_scale = 0.6 # Масштаб внутреннего полностью белого эллипса cv2.imwrite("eligrad.png", draw_image(a, b, theta, inner_scale, True)) # ================================================ ============================ строки = [] для j в диапазоне (0, 4, 1): столбцы = [] для я в диапазоне (0, 90, 10): плитка = np.zeros ((170, 170, 4), np.uint8) image = draw_image(80.0, 50.0, math.radians(i + j * 90), 0.6) плитка[:image.shape[0],:image.shape[1]] = изображение cols.append(плитка) rows.append (np.hstack (столбцы)) cv2.imwrite("eligrad-m.png", np.vstack(строки))
Примечание. Если вы обнаружите какие-либо глупые ошибки, непонятную терминологию или любые другие проблемы с этим постом, не стесняйтесь оставлять конструктивный комментарий или просто отредактируйте ответ, чтобы сделать его лучше. Я знаю, что есть способы дальнейшей оптимизации этого — пусть читатель сделает это упражнение (и, возможно, даст дополнительный ответ).
ios — danielgindi/Диаграммы: как рисовать постепенно слева направо
(https://github.com/danielgindi/Charts/issues/5057)
Проблема в том, что я не могу нарисовать шаг входящих данных шаг за шагом. Я не могу найти такой флаг. Теперь записи идут постепенно — не все сразу. Но sdk сразу отображает их по всей ширине представления диаграммы, несмотря на их количество. Мне нужно, чтобы они рисовали точка за точкой слева направо и только после достижения правого края, чтобы начать масштабирование. Вроде есть такой флаг bool, но мне его не удалось настроить. Буду признателен за любую помощь. Под кодом.
импорт UIKit импортировать диаграммы импортировать RxSwift импорт RxCocoa структура ChartViewModel { let blueValue: Driver} окончательный класс ChartView: UIView { частный ленивый var blueSet = makeEmptySet (цвет: . синий) частный ленивый var blueLineCharView = makeChartView() частная сумка для сдачи = DisposeBag() инициализация (модель: ChartViewModel) { super.init(кадр: .ноль) настраивать() установка ограничений () привязать (модель) } требуется инициализация? (кодер: NSCoder) { fatalError("init(coder:) не реализован") } настройка частной функции () { фоновый цвет = .clear addSubview (блюлайнчарвиев) } частная функция setupConstraints() { blueLineCharView.make { $0.edges.equalToSuperview() } } приватная функция привязки (_ модель: ChartViewModel) { model.blueValue.drive(onNext: {значение [weak self] в охранять let self = self, let value = value else { return } self.blueSet.append(значение) self.blueLineCharView.data = LineChartData(dataSet: self.blueSet) }) .disposed(по: сумка) } частная функция makeChartView() -> LineChartView { пусть chartView = LineChartView() chartView. backgroundColor = .clear chartView.leftAxis.enabled = ложь chartView.rightAxis.enabled = ложь chartView.xAxis.enabled = ложь chartView.isUserInteractionEnabled = ложь chartView.legend.enabled = ложь chartView.dragEnabled = ложь возврат диаграммы } частная функция makeEmptySet (цвет: UIColor) -> LineChartDataSet { пусть set = LineChartDataSet (записи: []) set.drawCirclesEnabled = ложь set.drawValuesEnabled = ложь set.mode = .cubicBezier set.lineWidth = 2 set.setColor(цвет) set.drawVerticalHighlightIndicatorEnabled = ложь set.drawHorizontalHighlightIndicatorEnabled = ложь набор возврата } }
- ios
- swift
- графики
- uikit
Зарегистрируйтесь или войдите в систему
Зарегистрируйтесь с помощью Google Зарегистрироваться через Facebook Зарегистрируйтесь, используя электронную почту и парольОпубликовать как гость
Электронная почтаТребуется, но не отображается
Опубликовать как гость
Электронная почтаТребуется, но не отображается
Нажимая «Опубликовать свой ответ», вы соглашаетесь с нашими условиями обслуживания и подтверждаете, что прочитали и поняли нашу политику конфиденциальности и кодекс поведения.