Russian Qt Forum

Qt => 2D и 3D графика => Тема начата: Igors от Январь 27, 2012, 14:46



Название: Градиент [решено]
Отправлено: Igors от Январь 27, 2012, 14:46
Добрый день

Умеет ли Qt (или кто-нибудь другой) делать такой градиент (аттач)? Цвета в углах/вершинах заданы. Если да, то какой класс задействовать?

Спасибо


Название: Re: Градиент
Отправлено: Пантер от Январь 27, 2012, 15:07
А как же. ;D
Код
C++ (Qt)
#include <QtGui/QApplication>
#include <QtGui/QLabel>
 
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
 
QLabel label;
label.setWindowTitle ("For Igors");
 
QPixmap pixmap;
pixmap.load ("/var/tmp/grad.png", "PNG");
label.setPixmap (pixmap);
label.show ();
label.setScaledContents (true);
 
return a.exec();
}
 


Название: Re: Градиент
Отправлено: Igors от Январь 27, 2012, 16:13
Ну вставить картинку градиент не нужен :)
А как для произвольных (заданных) цветов/вершин? Ответ "такого нет" тоже будет информативен, значит позаимствовать из исходников не удастся и придется долбать теорию. А что скажет GreatSnake?


Название: Re: Градиент
Отправлено: alexman от Январь 27, 2012, 17:42
Можно kriging заюзать.


Название: Re: Градиент
Отправлено: kamre от Январь 27, 2012, 17:50
Умеет ли Qt (или кто-нибудь другой) делать такой градиент (аттач)? Цвета в углах/вершинах заданы. Если да, то какой класс задействовать?
GDI+ умеет, называется PathGradientBrush (http://msdn.microsoft.com/en-us/library/ms533917(v=vs.85).aspx).


Название: Re: Градиент
Отправлено: Igors от Январь 27, 2012, 18:12
GDI+ умеет, называется PathGradientBrush (http://msdn.microsoft.com/en-us/library/ms533917(v=vs.85).aspx).
Спасибо, не знал об этой возможности GDI. Но она не то делает, заданного центра у меня нет, наоборот в какой-то центральной  точке должна быть смесь всех цветов.

Можно kriging заюзать.
Вот kriging "не асилил". Читал что это, мол, самая крутизна, пытался неск раз прорваться но безуспешно. Может мешает привычка все время прикидывать "а как быстро это будет работать", а в kriging расчетов немеряно. А Вы его делали? Если да, расскажите. Спасибо  


Название: Re: Градиент
Отправлено: ufna от Январь 27, 2012, 18:55
мне кажется тут достаточно радиальные градиенты от 100 до нуля по альфе микшировать и будет то, что на картинке


Название: Re: Градиент
Отправлено: Igors от Январь 27, 2012, 19:24
мне кажется тут достаточно радиальные градиенты от 100 до нуля по альфе микшировать и будет то, что на картинке
Думал в этом направлении, но ничего не придумалось. "Радиально" предполагает что есть "центр" который становится неприятно видимым/заметным, как его ни вычисляй.

А ведь для 3 углов все так известно и хорошо  :) 


Название: Re: Градиент
Отправлено: ufna от Январь 27, 2012, 19:53
Думал в этом направлении, но ничего не придумалось. "Радиально" предполагает что есть "центр" который становится неприятно видимым/заметным, как его ни вычисляй.

А ведь для 3 углов все так известно и хорошо  :) 

центр - это вершины многоугольника. От них и считать.


Название: Re: Градиент
Отправлено: Igors от Январь 27, 2012, 19:59
центр - это вершины многоугольника. От них и считать.
Хмм.. несколько странное определение центра :) Ну ладно, тогда расскажите как считать, а то Ваша мысль непонятна


Название: Re: Градиент
Отправлено: alexman от Январь 27, 2012, 22:41
Цитировать
Можно kriging заюзать.
Вот kriging "не асилил". Читал что это, мол, самая крутизна, пытался неск раз прорваться но безуспешно. Может мешает привычка все время прикидывать "а как быстро это будет работать", а в kriging расчетов немеряно. А Вы его делали? Если да, расскажите. Спасибо  
Kriging работает достаточно медленно. То есть если надо что интерактивное (типа потянул и сразу все пересчиталось), то это вряд ли. Хотя если точек, участвующих в расчете значения для текущей немного, то может и прокатит. Сам использовал kriging, но для неинтерактивных целей.


Название: Re: Градиент
Отправлено: alexman от Январь 27, 2012, 22:53
Трудно сказать годится ли данный вариант для этого случая (так как давно уже с подобным "не ковырялся" и не помню всех нюансов алгоритмов), но можно попробовать:
1. Построить триангуляцию по набору точек.
2. Для любой точки находим треугольник и рассчитываем значение по известному алгоритму. То есть значение будет учитывать только 3 точки и это, наверное, не то?

ЗЫ kriging 100% подойдет, но хз по скорости.


Название: Re: Градиент
Отправлено: ufna от Январь 27, 2012, 22:58
Хмм.. несколько странное определение центра :) Ну ладно, тогда расскажите как считать, а то Ваша мысль непонятна

как в файле, только радиус у всех - как у зеленого (предполагаю, что "до дальней вершины" должен быть)

рисуем градиенты каждого цвета от 255 до 0 по альфе от центра до дальней точки. микшируем их.


Название: Re: Градиент
Отправлено: twp от Январь 27, 2012, 23:03
это довольно легко реализуется на OpenGL.
Код
C
glShadeModel(GL_SMOOTH);
glBegin(GL_LINE_STRIP);
  glColor(....);
  glVertex(...);
  ....
glEnd();
 
тут (http://www3.ntu.edu.sg/home/ehchua/programming/opengl/GL2_Graphics3D.html) есть пример с пирамидой


Название: Re: Градиент
Отправлено: Igors от Январь 28, 2012, 11:43
ЗЫ kriging 100% подойдет, но хз по скорости.
Давайте я создам новую тему и там Вы расскажете как "крайгить"? (чтобы не мешать все в кучу)

1. Построить триангуляцию по набору точек.
2. Для любой точки находим треугольник и рассчитываем значение по известному алгоритму. То есть значение будет учитывать только 3 точки и это, наверное, не то?
Не то, треугольники получаются поганенькие - со слишком острыми углами, ну сразу попрут "ребра" между ними.

как в файле, только радиус у всех - как у зеленого (предполагаю, что "до дальней вершины" должен быть)

рисуем градиенты каждого цвета от 255 до 0 по альфе от центра до дальней точки. микшируем их.
Если радиусы малы - тогда неясно что делать в центре (ни одна вершина не покрывает). А если увеличить радиусы, то вес вершин в других станет > 0. Переменный радиус по углу (используя длины прилегающих к вершине ребер) не годится по той же причине. Что мы видим на картинке:

- цвета в вершинах = заданным
- цвета на ребрах = микс только 2 цветов этого ребра

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

это довольно легко реализуется на OpenGL.
тут (http://www3.ntu.edu.sg/home/ehchua/programming/opengl/GL2_Graphics3D.html) есть пример с пирамидой
Там я вижу треугольник(и), для него решение широко известно и проблем нет. Как OpenGL закрашивает N-угольник не знаю, интересно посмотреть. В любом случае мне нужно это в виде текста/кода, а не просто выходная картинка.


Название: Re: Градиент
Отправлено: alexman от Январь 28, 2012, 11:56
ЗЫ kriging 100% подойдет, но хз по скорости.
Давайте я создам новую тему и там Вы расскажете как "крайгить"? (чтобы не мешать все в кучу)
А что непонятно? По произвольному набору точек вычисляем значение для произвольной точки. Здесь есть где оптимизировать:
 1. Алгоритм параллелится. То есть вычисление значений точек друг от друга независимы.
 2. Так как вычислять значения всех точек на каждый чих критично, то можно вычислять некоторую регулярную сетку с шагом, а промежуточные значения можно интерполировать.


Название: Re: Градиент
Отправлено: twp от Январь 28, 2012, 12:51
Там я вижу треугольник(и), для него решение широко известно и проблем нет. Как OpenGL закрашивает N-угольник не знаю, интересно посмотреть. В любом случае мне нужно это в виде текста/кода, а не просто выходная картинка.
а что мешает самому попробывать? В Qt есть отличная поддержка OpenGL и не нужно мучаться с GLUT или чем либо еще.
 На счет того что в примере треугольники. В описании glShadeModel(GL_SMOOTH), которая собственно делает интерполяцию цвета, никаких ограничений на это нет. Я там ошибся, нужно использовать GL_LINE_LOOP вместо GL_LINE_STRIP. glBegin(GL_LINE_LOOP) рисует по точкам при этом последнюю точку замыкает с первой. Можно еще использовать GL_POLYGON вместо GL_LINE_LOOP. Что еще надо?


Название: Re: Градиент
Отправлено: Igors от Январь 28, 2012, 13:53
А что непонятно? По произвольному набору точек вычисляем значение для произвольной точки.
Это можно сказать о любом из 11 (если не ошибаюсь) методов интерполяции начиная с простейшего "взять ближайший". Ладно, понял, отстал  :)

а что мешает самому попробывать? В Qt есть отличная поддержка OpenGL и не нужно мучаться с GLUT или чем либо еще.
 На счет того что в примере треугольники. В описании glShadeModel(GL_SMOOTH), которая собственно делает интерполяцию цвета, никаких ограничений на это нет. Я там ошибся, нужно использовать GL_LINE_LOOP вместо GL_LINE_STRIP. glBegin(GL_LINE_LOOP) рисует по точкам при этом последнюю точку замыкает с первой. Можно еще использовать GL_POLYGON вместо GL_LINE_LOOP. Что еще надо?
Да хоть LOOP, хоть STRIP. они оба линии рисуют, просто один замыкает другой нет, но внутренность не закрашивают. Поправьте если не так

В своем предыдущем посте я уже говорил что мне нужен код  (для расчета весов (чисел)), так что даже если GL нарисует - мне это ничего не дает. Поэтому если у Вас есть такая отрисовка под рукой - покажите, а специально на это время тратить не нужно.



Название: Re: Градиент
Отправлено: twp от Январь 28, 2012, 14:51
Да хоть LOOP, хоть STRIP. они оба линии рисуют, просто один замыкает другой нет, но внутренность не закрашивают. Поправьте если не так
все верно, внутренность закрашивается установкой цвета glColor перед установкой координаты точки glVertex
В своем предыдущем посте я уже говорил что мне нужен код  (для расчета весов (чисел)), так что даже если GL нарисует - мне это ничего не дает. Поэтому если у Вас есть такая отрисовка под рукой - покажите, а специально на это время тратить не нужно.
Я ответил чисто по теме, готового примера у меня к сожалению нет. И я не совсем понял про расчет весов, из предыдущего поста не совсем очевидно что нужно сделать


Название: Re: Градиент
Отправлено: Igors от Январь 28, 2012, 16:29
И я не совсем понял про расчет весов, из предыдущего поста не совсем очевидно что нужно сделать
Напр считаем цвет точки внутри треугольника

pixel_color = (colo1_1 * 5 + colo1_2 * 6 + color_3 * 6) / (5 + 6 + 7)

Вот эти 5. 6, 7 и есть "веса" которые мне нужно получить. Если они нормализованы (т.е. их сумма = 1), то деление можно не делать. Ну и понятно что можно считать не только цвет, но и все для чего заданы значения в вершинах.


Название: Re: Градиент
Отправлено: Disa от Январь 28, 2012, 16:54
http://sophia.javeriana.edu.co/~ochavarr/computer_graphics_2010_2/smoothPolygon/

Цитировать
The combination of colors can be calculated as a weighted average as a function of distance. You have to determine what exact function should be used, noting that:

Each pixel has a coordinate position (x, y)
The final color on a pixel is the sum of several vertex color contributions
The fartest a vertex is, the less its color contribution is


Название: Re: Градиент
Отправлено: Igors от Январь 28, 2012, 17:23
http://sophia.javeriana.edu.co/~ochavarr/computer_graphics_2010_2/smoothPolygon/
Здесь студенту предлагается самому это написать :) Судя по картинке веса вычисляются как
Код
C++ (Qt)
weight[i] = 1.0 / MAX(distance(p, vertex[i]), EPSILON);
 
т.е. вес каждой вершины обратно пропорционален расстоянию до нее. Это не годится по причинам изложенным в ответе #13. Представим себе смежный полигон внизу нарисованного. Тогда малиновый цвет (что есть на нижнем ребре) мгновенно оборвется - ведь смежный полигон не имеет малиновой точки внутри.


Название: Re: Градиент
Отправлено: Disa от Январь 29, 2012, 23:32
Окей, блин, былоб больше времени - яб попробовал закодить :-/
Ну в любом случае ясно что цвет точки внутри это либо:
а) f(colorRGB[n], width[n] (or x, y), n); - в случае когда вершины "сами" являются источником цвета
б) f(colorRGB[n], width[n] (or x, y), normal[n], n); - в случае внешнего источника.

Теперь нужно выбрать соответственное усреднение или интерполяцию (я точно не уверен какой из методов нужно употреблять к данной задачи, но я все же склоняюсь к усреднению).
В случае усреднения можно взять Колмогоровское среднее (http://ru.wikipedia.org/wiki/%D0%A1%D1%80%D0%B5%D0%B4%D0%BD%D0%B5%D0%B5_%D0%9A%D0%BE%D0%BB%D0%BC%D0%BE%D0%B3%D0%BE%D1%80%D0%BE%D0%B2%D0%B0) и поиграться со  степенью функции.

Если же брать интерполяцию, то требуется построить функция color(x0, y0) = f(x, y) для всех x, y лежащих внутри нашего многоугольника, по значениям color(x, y) вершин (то есть это некая гладкая функция в 3х мерном пространстве). Взять например: Билинейную интерполяцию (http://ru.wikipedia.org/wiki/%D0%91%D0%B8%D0%BB%D0%B8%D0%BD%D0%B5%D0%B9%D0%BD%D0%B0%D1%8F_%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D0%BF%D0%BE%D0%BB%D1%8F%D1%86%D0%B8%D1%8F)

Извиняюсь, что не могу помочь кодом, а только идеями :-/

PS: OpenGL умеет закрашивать только выпуклые многоугольники (в случае неправильных как раз и нужна треангуляция), откуда можно предположить что это сделанно для правильного подсчета расстояния.
PSPS: Вообще задача интересная конечно)


Название: Re: Градиент
Отправлено: Igors от Январь 30, 2012, 09:32
Ладно, давайте уже с OpenGL выясним. Да, он может закрашивать многоугольники (GL_POLYGON), но делает это простейшей триангуляцией (аттач). Вот источник http://www.codeproject.com/Articles/23991/OpenGL-Geometric-Primitives#Sample59 (http://www.codeproject.com/Articles/23991/OpenGL-Geometric-Primitives#Sample59). Даже 4-x угольник (GL_QUAD) он закрашивает как 2 треугольника. Прут "ребра", это не то что хотелось


Название: Re: Градиент
Отправлено: Igors от Январь 30, 2012, 09:44
Теперь нужно выбрать соответственное усреднение или интерполяцию (я точно не уверен какой из методов нужно употреблять к данной задачи, но я все же склоняюсь к усреднению).
Осреднение и интерполяция - по существу одно и то же :) Bilenear прекрасный метод, но мне ничего не известно как его применить для 5 или более точек (нужны 4). Просто интерполировать - не вопрос, можно взять напр вес = 1 / расстояние_до_вершины (как уже говорилось выше). Но так получаем "швы" на ребрах (см ответы #13 и #21) 


Название: Re: Градиент
Отправлено: Disa от Январь 30, 2012, 10:18
Да-да, я уже посмотрел ответ 13, поэтому и предложил билинейную, но забыл, что число точек в ней не более 4х :(
Мб многочлены Лагранжа для 2х переменных (http://www.machinelearning.ru/wiki/index.php?title=%D0%98%D0%BD%D1%82%D0%B5%D1%80%D0%BF%D0%BE%D0%BB%D1%8F%D1%86%D0%B8%D1%8F_%D0%BF%D0%BE%D0%BB%D0%B8%D0%BD%D0%BE%D0%BC%D0%B0%D0%BC%D0%B8_%D0%9B%D0%B0%D0%B3%D1%80%D0%B0%D0%BD%D0%B6%D0%B0_%D0%B8_%D0%9D%D1%8C%D1%8E%D1%82%D0%BE%D0%BD%D0%B0)? Я правда баюсь что будет резкая потеря в производительности для большого числа вершин.

Интерполяция функций двух переменных (http://www.machinelearning.ru/wiki/index.php?title=%D0%98%D0%BD%D1%82%D0%B5%D1%80%D0%BF%D0%BE%D0%BB%D1%8F%D1%86%D0%B8%D1%8F_%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%B9_%D0%B4%D0%B2%D1%83%D1%85_%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D1%8B%D1%85%2C_%D0%BF%D1%80%D0%BE%D0%B1%D0%BB%D0%B5%D0%BC%D0%B0_%D0%B2%D1%8B%D0%B1%D0%BE%D1%80%D0%B0_%D1%83%D0%B7%D0%BB%D0%BE%D0%B2)


Название: Re: Градиент
Отправлено: Igors от Февраль 04, 2012, 12:21
В общем есть это в теории, формула достаточно простая

weight[ i ] = (cot(A) + cot(B)) / (d * d)

где

weight - вес i-й вершины
cot - котангенс ф-ция
d - расстояние от интерполируемой точки до i-й вершины
A, B - углы образованные 2 векторами: первый вершина - интерполируемая точка, второй вершина - прилегающая вершина

Однако хлопот немало. Во-первых нужно тщательно проверять на epsilon. Во-вторых я не смог найти а что же делать если котангенс получается отрицательный. Вообще получается что чем "острее" внутренний угол, тем мощнее его влияние, и наоборот. Когда угол приближается к 180 - результат выглядит неестественно.

В общем, подтверждается старая истина: N-угольник - урод, и рендерить его напрямую - себе дороже


Название: Re: Градиент [решено]
Отправлено: Disa от Февраль 05, 2012, 17:27
А не дорого каждый раз просчитывать sin и cos? Я все же попробую сделать с помощью полинома.
Я ,конечно, не очень силен в не классических алгоритмах компьютерной графики, но интуиция подсказывает что должно быть полноценное решение (которое могло бы полностью равномерно закрашывать любой выпуклый многоугольник или хотя бы какой-то (достаточно большой) их класс) Ну в общем нужно делать :)


Название: Re: Градиент [решено]
Отправлено: Igors от Февраль 05, 2012, 17:38
А не дорого каждый раз просчитывать sin и cos? Я все же попробую сделать с помощью полинома.
Ну так елы-палы, все ж цивильно: cos вычисляется как скалярное произведение, sin как длина векторного произведения. А если с полиномом пошустрее - обсудим (буду рад с единомышленником)