Русский
Русский
English
Статистика
Реклама

Матрицы

Математика верстальщику не нужна 2 Матрицы, базовые трансформации, построение 3D и фильтры для картинок

22.09.2020 12:22:19 | Автор: admin


В прошлый раз мы говорили о графиках и траекториях для покадровых анимаций, а сегодня речь пойдет про матрицы. Мы разберемся с тем, как строятся базовые трансформации в CSS, SVG и WebGL, построим отображение 3D-мира на экране своими руками, попутно проводя параллель с таким инструментом, как Three.js, а также поэкспериментируем с фильтрами для фотографий и разберемся, что же за магия такая лежит в их основе.

Напомню, что в этой серии статей мы знакомимся с разными штуками из области математики, которые пугают верстальщиков, но могут быть полезны при решении рабочих задач. Мы стараемся избежать излишней теоретизации, отдавая предпочтение картинкам и объяснению на пальцах, с акцентом на практическое применение во фронтенде. В связи с этим формулировки местами могут быть не совсем точными с точки зрения математики, или не совсем полными. Цель этой статьи дать общее представление о том, что бывает, и откуда можно начать в случае чего.

Скрипты для генерирования картинок в стиле этого цикла статей находятся на GitHub, так что если если вы хотите себе сообразить такие же вы знаете что делать.

Немного определений


Матрица в математике это такая абстракция, можно сказать, что это тип данных в каком-то смысле, и записываетя она в виде прямоугольной таблицы. Количество столбцов и строк может быть любым, но в вебе мы почти всегда имеем дело с квадратными матрицами 2x2, 3x3, 4x4, и 5x5.

Также нам понадобится такое определение, как вектор. Думаю из школьной геометрии вы можете вспомнить определение, связанное со словами длина и направление, но вообще в математике вектором может называться очень много чего. В частности мы будем говорить о векторе, как об упорядоченном наборе значений. Например координаты вида (x, y) или (x, y, z), или цвет в формате (r, g, b) или (h, s, l, a) и.т.д. В зависимости от того, сколько элементов вошло в такой набор мы будем говорить о векторе той или иной размерности: если два элемента двумерный, три трехмерный и.т.д. Также, в рамках рассматриваемых тем, может быть удобно иногда думать о векторе, как о матрице размера 1x2, 1x3, 1x4 и.т.д. Технически можно было бы ограничиться только термином матрица, но мы все же будем использовать слово вектор, чтобы отделить эти два понятия друг от друга, хотя бы в логическом смысле.

Для матриц, равно как и для векторов, определены разные операции, которые с ними можно делать. В частности умножение. Мы постоянно их умножаем между собой. Сам алгоритм умножения не очень сложный, хотя может показаться немного запутанным:

function multiplyMatrices(a, b) {    const m = new Array(a.length);    for (let row = 0; row < a.length; row++) {        m[row] = new Array(b[0].length);        for (let column = 0; column < b[0].length; column++) {            m[row][column] = 0;            for (let i = 0; i < a[0].length; i++) {                m[row][column] += a[row][i] * b[i][column];            }        }    }    return m;}

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

При работе со сложными сущностями в математике очень полезно абстрагироваться. Как здесь мы будем часто говорить про умножение, но не будем уделять внимание тому, какие именно арифметические операции в каком порядке там происходят. Мы знаем, что умножение определено и этого достаточно для работы.

Мы будем использовать только квадратные матрицы в очень частном наборе задач, так что будет достаточно набора простых правил:

  • Умножать можно только матрицы одной размерности.
  • Умножаем матрицу на матрицу получаем матрицу.
  • Можно умножить матрицу на вектор получим вектор.
  • Порядок умножения важен.



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

Также для дальнейшей работы нам понадобится такое понятие, как единичная матрица. Это матрица, у которой по главной диагонали расположены единицы, а во всех остальных ячейках нули. Алгоритм умножения построен таким образом, что умножая единичную матрицу на другую матрицу получаем ту самую матрицу. Или вектор, если мы говорим о векторе. Иными словами единичная матрица выполняет роль единицы при обычном умножении чисел. Это нейтральная штука, которая при умножении ни на что не влияет.



И последнее, что нам понадобится, это пример, показанный на картинке выше. Это как бы частный случай умножения матрицы на вектор, когда у матрицы последняя строка представляет собой кусочек единичной матрицы, а у вектора последний элемент тоже равен 1.

В этом примере мы используем буквы (x, y), и как вы уже можете догадаться, дальше речь пойдет о координатах в 2D. Но зачем добавлять третью координату и оставлять ее единицей? спросите вы. Все дело в удобстве, или даже лучше сказать, что в универсальности. Мы очень часто добавляем +1 координату для упрощения расчетов, и работа с 2D идет с матрицами 3x3, работа с 3D с матрицами 4x4, а работа с 4D, например с цветами в формате (r, g, b, a) идет с матрицами 5x5. На первый взгляд это кажется безумной идеей, но дальше мы увидим, насколько это унифицирует все операции. Если вы захотите более подробно разобраться в этой теме, то можете загуглить выражение однородные координаты.

Но довольно теории, перейдем к практике.

I. Базовые трансформации в компьютерной графике


Давайте возьмем выражения из упомянутого примера и посмотрим на них как есть, вне контекста матриц:

newX = a*x + b*y + cnewY = d*x + e*y + f

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

newX = 1*x + 0*y + 0 = xnewY = 0*x + 1*y + 0 = y

Здесь ничего не меняется новые координаты (x, y) идентичны старым. Если подставить эти коэффициенты в матрицу и внимательно присмотреться, то увидим, что получится единичная матрица.

А что получится, если взять другие коэффициенты? Например вот такие:

newX = 1*x + 0*y + A = x + AnewY = 0*x + 1*y + 0 = y

Мы получим смещение по оси X. Впрочем, что еще здесь могло получиться? Если для вас это не очевидно, то лучше вернуться к первой части, где мы говорили про графики и коэффициенты.

Меняя эти 6 коэффициентов a, b, c, d, e, f и наблюдая за изменениями x и y, рано или поздно мы придем к четырем их комбинациям, которые кажутся полезными и удобными для практического применения. Запишем их сразу в форме матриц, возвращаясь к изначальному примеру:



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

Очень часто удобно воспринимать матрицы именно как трансформации для чего-либо, например для координат. Это еще раз к слову об абстракциях.

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



Базовые трансформации в CSS


Но это все слова. Давайте посмотрим, как это выглядит в реальном фронтенде. В CSS у нас (внезапно) есть функция matrix. Выглядит она в контексте кода как-то так:

.example {    transform: matrix(1, 0, 0, 1, 0, 0);}

Многих новичков, которые впервые видят ее, накрывает вопрос почему здесь шесть параметров? Это странно. Было бы 4 или 16 еще куда не шло, но 6? Что они делают?

Но на самом деле все просто. Эти шесть параметров те самые коэффициенты, из которых мы только что собирали матрицы для базовых трансформаций. Только их почему-то расставили в другом порядке:



Также в CSS есть функция matrix3d для того, чтобы задавать с помощью матрицы трансформацию в 3D. Там уже есть 16 параметров, ровно чтобы сделать матрицу 4x4 (не забываем, что мы добавляем +1 размерность).

Матрицы для базовых 3D трансформаций строятся так же, как и для 2D, только нужно больше коэффициентов, чтобы расставлять их не по двум координатам, а по трем. Но принципы те же.

Естественно, каждый раз городить матрицу и следить за корректной расстановкой коэффициентов при работе с простыми трансформациями в CSS было бы странно. Мы, программисты, обычно все же стараемся упростить себе жизнь. Так что у нас в CSS появились краткие функции для создания отдельных трансформаций translateX, translateY, scaleX и.т.д. Обычно мы используем именно их, но важно понимать, что внутри они создают эти же самые матрицы, о которых мы говорили, просто скрывая от нас этот процесс за еще одним слоем абстракции.

Эти же самые трансформации translate, rotate, scale и skew, а также универсальная функция matrix для задания трансформаций, присутствуют и в SVG. Синтаксис немного другой, но суть такая же. При работе с трехмерной графикой, например с WebGL, мы тоже будем прибегать к этим же трансформациям. Но об этом чуть позже, сейчас важно понять, что они есть везде, и работают везде по одному и тому же принципу.

Промежуточные итоги


Обобщим вышесказанное:

  • Матрицы могут быть использованы в качестве трансформаций для векторов, в частности для координат каких-то объектов на странице.
  • Почти всегда мы оперируем квадратными матрицами и добавляем +1 размерность для упрощения и унификации вычислений.
  • Есть 4 базовых трансформации translate, rotate, scale и skew. Они используются везде от CSS до WebGL и везде работают схожим образом.

II. Построение 3D сцены своими руками


Логичным развитием темы про трансформации координат будет построение 3D сцены и отображение ее на экране. В той или иной форме эта задача обычно есть во всех курсах по компьютерной графике, но вот в курсах по фронтенду ее обычно нет. Мы посмотрим может быть немного упрощенный, но тем не менее полноценный вариант того, как можно сделать камеру с разными углами обзора, какие операции нужны, чтобы посчитать координаты всех объектов на экране и построить картинку, а также проведем параллели с Three.js самым популярным инструментом для работы с WebGL.

Здесь должен возникнуть резонный вопрос зачееем? Зачем учиться делать все руками, если есть готовый инструмент? Ответ кроется в вопросах производительности. Вероятно вы бывали на сайтах с конкурсами вроде Awwwards, CSS Design Awards, FWA и им подобных. Вспомните, насколько производительные сайты принимают участие в этих конкурсах? Да там почти все тормозят, лагают при загрузке и заставляют ноутбук гудеть как самолет! Да, конечно, основная причина обычно это сложные шейдеры или слишком большое количество манипуляций с DOM, но вторая невероятное количество скриптов. Это катастрофическим образом влияет на загрузку подобных сайтов. Обычно все происходит так: нужно сделать что-то на WebGL берут какой-нибудь 3D движок (+500КБ) и немного плагинов для него (+500КБ); нужно сделать падение объекта или разлетание чего-то берут физический движок (+1МБ, а то и больше); нужно обновить какие-то данные на странице ну так добавляют какой-нибудь SPA-фреймворк с десятком плагинов (+500КБ) и.т.д. И таким образом набирается несколько мегабайтов скриптов, которые мало того, что нужно загрузить клиенту (и это еще вдобавок к большим картинкам), так еще и браузер с ними что-то будет делать после загрузки они же не просто так к нему прилетают. Причем, в 99% случаев, пока скрипты не отработают, пользователь не увидит всей той красоты, которую ему бы нужно с самого начала показывать.

Народная примета гласит, что каждые 666КБ скриптов в продакшене увеличивают время загрузки страницы на время, достаточное, чтобы пользователь отправил разработчика сайта на следующий круг ада. Three.js в минимальной комплектации весит 628КБ...

При этом часто задачи просто не требуют подключения сложных инструментов. Например чтобы показать пару плоскостей с текстурами в WebGL и добавить пару шейдеров, чтобы картинки расходились волнами, не нужен весь Three.js. А чтобы сделать падение какого-то объекта не нужен полноценный физический движок. Да, он скорее всего ускорит работу, особенно если вы с ним знакомы, но вы заплатите за это временем пользователей. Тут каждый решает сам для себя, что ему выгоднее.

Цепочка преобразований координат


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

Так вот. Допустим дизайнер нарисовал 3D-модель. Пусть это будет куб (в примерах будем использовать максимально простые построения, чтобы не усложнять иллюстрации на ровном месте):



Что эта модель из себя представляет? По сути это набор точек в какой-то системе координат и набор взаимосвязей между ними, чтобы можно было определить, между какими из точек должны находиться плоскости. Вопрос плоскостей в контексте WebGL будет лежать на плечах самого браузера, а для нас важны координаты. Нужно понять, как именно их преобразовать.

У модели, как мы и сказали, есть система координат. Но обычно мы хотим иметь много моделей, хотим сделать сцену с ними. Сцена, наш 3D-мир, будет иметь свою, глобальную систему координат. Если мы просто будем интерпретировать координаты модели как глобальные координаты то наша модель будет находиться как бы в центре мира. Иными словами, ничего не поменяется. Но мы хотим добавить много моделей в разные места нашего мира, примерно так:



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

Например для кубиков будут примерно такие матрицы:

// Центральный кубик в центре мира.// Единичная матрица ничего не меняет и координаты просто интерпретируются как глобальные.const modelMatrix1 = [    [1, 0, 0, 0],    [0, 1, 0, 0],    [0, 0, 1, 0],    [0, 0, 0, 1]];// Кубик, смещенный по глобальной оси X.const modelMatrix2 = [    [1, 0, 0, 1.5],    [0, 1, 0, 0  ],    [0, 0, 1, 0  ],    [0, 0, 0, 1  ]];// Кубик, смещенный по глобальной оси X в другую сторону.const modelMatrix3 = [    [1, 0, 0, -1.5],    [0, 1, 0, 0   ],    [0, 0, 1, 0   ],    [0, 0, 0, 1   ]];

Дальше мы будем действовать примерно следующим образом:

для каждой точки модели {    глобальные координаты точки = [ матрица этой модели ] * локальные кординаты}

Соответственно для каждой модели нужна своя матрица.

Аналогичным образом можно делать цепочку из каких-то объектов. Если птица должна махать крыльями, то будет уместно координаты точек крыла сначала перевести в координаты птицы, а потом уже в глобальные мировые координаты. Это будет куда проще угадывания траектории крыла сразу в глобальных координатах. Но это так, к слову.


Дальше нужно определиться с тем, с какой стороны мы будем смотреть на мир. Нужна камера.



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

для каждой точки в мире {    координаты точки для камеры = [ матрица камеры ] * глобальные кординаты}

Если у вас сложная сцена, то будет иметь смысл произвести некоторые оптимизации и не считать ничего для точек, которые точно не попадут в поле зрения камеры. Не забывайте о производительности!

Давайте посмотрим на сцену с того места, где стоит наша условная камера:



Сейчас, преобразовав все точки в систему координат камеры, мы можем просто выбросить ось Z, а оси X и Y интерпретировать как горизонтальную и вертикальную. Если нарисовать все точки моделей на экране, то получится картинка, как в примере никакой перспективы и сложно понять, какая часть сцены на самом деле попадает в кадр. Камера как бы бесконечного размера во все стороны. Мы можем как-то все подогнать, чтобы то, что нужно, влезло на экран, но было бы неплохо иметь универсальный способ определения того, какая часть сцены попадет в поле зрения камеры, а какая нет.

У физических камер мы можем говорить о такой штуке, как угол обзора. Почему бы и здесь его не добавить?

Для этого нам понадобится еще одна матрица матрица проекции. Вообще строить ее можно по-разному. В зависимости от того, что взято за изначальные параметры, получится немного разный вид этой самой матрицы, но суть будет одна и та же. Мы возьмем следующий, немного упрощенный вариант:

// Пусть угол обзора будет 90 градусовconst s = 1 / (Math.tan(90 * Math.PI / 360));const n = 0.001;const f = 10;const projectionMatrix  = [    [s, 0, 0,          0],    [0, s, 0,          0],    [0, 0, -(f)/(f-n), -f*n/(f-n)],    [0, 0, -1,         0]];

Матрица проекции, так или иначе, содержит в себе три параметра это угол обзора, а также минимальное и максимальное расстояние до точек, с которыми идет работа. Выражаться это может по-разному, использоваться тоже по-разному, но эти параметры будут в этой метрице в любом случае.

Понимаю, что ни разу не очевидно, почему матрица выглядит именно так, но для ее выведения с пояснениями понадобится формул на 2-3 страницы. Это еще раз возвращает нас к мысли, что абстрагироваться полезно мы можем оперировать более общим результатом, не вдаваясь в мелкие детали там, где это не нужно для решения конкретной задачи.

Теперь, произведя уже знакомые преобразования:

для каждой точки в системе координат камеры {    координаты точки = [ матрица проекции ] * координаты в камере}

Получим в нашем поле зрения именно то, что и ожидаем. Увеличивая угол видим больше всего по сторонам, уменьшая угол видим только то, что ближе к направлению, куда камера направлена. PROFIT!



Но на самом деле нет. Мы забыли про перспективу. Бесперспективная картинка нужна мало где, так что нужно ее как-то добавить. И здесь, внезапно, нам не нужны матрицы. Задача выглядит очень сложной, но решается банальным делением координат X и Y на W для каждой точки:



* Здесь мы сместили камеру в сторону, и добавили параллельные линии на полу, чтобы было понятнее, где эта самая перспектива появляется.

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

Теперь мы имеем полноценную картинку. Можно брать координаты X и Y для каждой точки и рисовать ее на экране любым удобным вам способом.

Вообще этого достаточно, чтобы построить сцену, но в реальных проектах вы также можете столкнуться с дополнительной трансформацией, связанной с масштабированием, в самом конце. Идея в том, что после проекции мы получаем координаты (x, y) в пределах 1, нормализованные координаты, а потом уже умножаем их на размер экрана или канваса, получая координаты для отображения на экране. Этот дополнительный шаг выносит размер канваса из всех вычислений, оставляя его только в самом конце. Иногда это удобно.

Здесь у вас, вероятно заболела голова от количества информации, так что притормозим и повторим еще раз все трансформации в одном месте:



Если эти трансформации объединить в одну, то получится паровозик.

Как это выглядит в Three.js?


Теперь, когда мы понимаем, откуда этот паровозик взялся, посмотрим на пример вершинного шейдера по умолчанию в Three.js, который ничего не делает:

void main() {    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);}

или в более полном варианте:

void main() {    gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);}

Ничего он вам не напоминает? Да, это именно этот паровозик. И под ничего не делает мы подразумеваем, что он как раз делает всю работу по пересчету координат, на основе заботливо переданных со стороны Three.js матриц. Но никто не мешает эти матрицы сделать своими руками, не так ли?

Типы камер в компьютерной графике и Three.js


Тема типов камер не касается непосредственно матриц, но все же уделим ей пару минут, раз уж все равно зашла речь про Three.js, а то порой у людей каша в голове по этому поводу.

Камера это абстракция. Она помогает нам мыслить в 3D мире таким же образом, как мы мыслим в мире реальном. Как мы уже сказали, у камеры есть положение в пространстве, направление, куда она смотрит, и угол обзора. Все это задается с помощью двух матриц и, возможно, дополнительного деления координат для создания перспекивы.

В компьютерной графике мы имеем два вида камер это с перспективой и без перспективы. Это два принципиально разных типа камер в техническом плане, требующих разных действий для получения изображения. И все. Больше ничего нет. Все остальное это их комбинации, какие-то более сложные абстракции. Например в Three.js есть стерео-камера это не какой-то особый тип камеры в техническом плане, а просто абстракция две камеры, немного разнесенные в пространстве и расположенные под углом:



Для каждой половины экрана мы берем свою камеру и получается стерео-картинка. А CubeCamera это 6 обычных камер, расположенных с разных сторон от какой-то точки, не более того.

Что дальше?


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

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

Про текстуры и эффекты для картинок на WebGL, в том числе без библиотек, мы говорили в предыдущих статьях уже не раз. Вы можете обратиться к ним, если вам эта тема интересна. Таким образом, объединив все эти знания воедино, мы сможем строить полноценные красочные 3D-штуки своими руками.

Мы действительно можем строить полноценные 3D-сцены своими руками. Но все же здесь важно соблюдать баланс для простой генеративной графики или каких-то эффектов для картинок это будет хорошей идеей. Для сложных сцен может быть проще все же взять готовый инструмент, потому что свой по объему будет приближаться к тому же Three.js и мы ничего не выиграем при избавлении от него. А если вам нужно естественное освещение, мех, стекло, множественные отражения или еще что-то в этом духе, то из соображений производительности может иметь смысл отказаться от самой идеи рендерить что-то в реальном времени и заранее заготовить картинки с видами на сцену с разных сторон и уже их показывать пользователю. Мыслите шире, не зацикливайтесь на определенном подходе к решению задач.

Промежуточные итоги


Сейчас самое время обобщить вышесказанное, чтобы в голове появилось место для следующего варианта применения матриц.

Итак:

  • Можно построить 3D мир и рассчитать координаты объектов на экране своими руками, используя паровозик из матриц.
  • В 3D мире мы оперируем такой абстракцией, как камера. Она имеет расмоложение, направление и угол обзора. Все это задается с помощью все тех же матриц. И есть два базовых вида камер с перспективой и без перспективы.
  • В контексте WebGL ручное построение картинки на экране или физические расчеты часто позволяют выбросить тяжелые зависимости и ускорить загрузку страниц. Но важно соблюдать баланс между своими скриптами, готовыми инструментами, а также альтернативными вариантами решения задач, уделяя внимание не только своему удобству, но и вопросам скорости загрузки и конечной производительности, в том числе на телефонах.

III. Фильтры для изображений


Напоследок мы рассмотрим такую область применения матриц, как фильтры для изображений. Если мы рассмотрим цвет в формате RGBA как вектор, то можно предположить, что здесь можно применить трансформацию, аналогичную той, что мы использовали с координатами:



И применить это для картинки по очевидному принципу:

для каждого пикселя картинки {    новый цвет пикселя = [ фильтр ] * старый цвет пикселя}

Если в качестве матрицы будет выступать единичная матрица ничего не изменится, это мы уже знаем. А что будет, если применить фильтры, схожие с трансформациями translate и scale?



Оу. Получились фильтры яркости и контраста. Занятно.

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

А как сделать черно-белое изображение из цветного? Первое, что может прийти в голову это сложить значения каналов RGB, поделить на 3, и использовать полученное значение для всех трех каналов. В формате матрицы это будет выглядеть как-то так:



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

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

А если мы еще и домножим главную диагональ немного, то получится универсальный фильтр насыщенности:



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

Вообще играться с фильтрами можно долго, получая самые разные результаты:



* Использованные в этом примере матрицы можно посмотреть на GitHub, если они вдруг вам понадобились. Для вставки в статью их объем будет избыточным.

Но давайте все же уделим немного внимания тому, где это собственно применить. Понятно, что сама идея замены цвета для каждого пикселя наводит на мысли о шейдерах для обработки фото, либо для постобработки какой-то 3D-сцены, но может быть это еще где-то есть во фронтенде?

Фильтры в CSS


В CSS у нас есть свойство filter. И там, в частности, есть вот такие варианты фильтров, связанных с цветами:

  • brightness (мы его сделали)
  • contrast (сделали)
  • invert (то же, что и контраст, только коэффициенты по главной диагонали с другим знаком)
  • saturate (сделали)
  • grayscale (как уже отметили, это частный случай saturate)
  • sepia (очень размытое понятие, разные варианты сепии получаются игрой с коэффициентами, где мы так или иначе уменьшаем присутствие синего цвета)

И эти фильтры принимают на вход коэфициенты, которые потом в том или ином виде подставляются в те матрицы, которые мы сделали ранее. Теперь мы знаем, как эта магия устроена изнутри. И теперь понятно, как эти фильтры комбинируются в недрах интерпретатора CSS, ведь здесь все строится по тому же принципу, что и с координатами: умножаем матрицы складываем эффекты. Правда пользовательской функции matrix в этом свойстве в CSS не предусмотрено. Но зато она есть в SVG!

Фильтры-матрицы в SVG


В рамках SVG у нас есть такая штука, как feColorMatrix, которая применяется при создании фильтров для изображений. И здесь у нас уже есть полная свобода можем сделать матрицу на свой вкус. Синтаксис там примерно такой:

<filter id=my-color-filter>    <feColorMatrix in=SourceGraphics        type=matrix,        matrix=1 0 0 0 0                0 1 0 0 0                0 0 1 0 0                0 0 0 1 0                0 0 0 0 1    /></filter>

А еще SVG фильтры можно применить к обычным DOM-элементам в рамках CSS, там для этого есть специальная функция url Но я вам этого не говорил!

На самом деле SVG-фильтры в рамках CSS до сих пор не поддерживаются всеми браузерами (не показываю пальцем на IE), но ходят слухи, что Edge окончательно переезжает на хромиумный движок, и старые версии лишатся поддержки в обозримом будущем, так что пора эту технологию осваивать, с ней можно много всякого интересного делать.

А что еще бывает?


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

Kernel matrix


В частности во фронтенде мы встречаем такую штуку, как kernel matrix, и связанными с ней эффектами. Суть проста есть квадратная матрица, обычно 3x3 или 5x5, хотя может быть и больше, а в ней хранятся коэффициенты. В центре матрицы для текущего пикселя, вокруг центра для соседних пикселей. Если матрица 5x5 то появляется еще один слой вокруг центра для пикселей, находящихся через один от текущего. Если 7x7 то еще один слой и.т.д. Иными словами мы рассматриваем матрицу как такое двумерное поле, на котором можно расставить коэффициенты по своему усмотрению, уже без привязки к каким-то уравнениям. А трактоваться они будут следующим образом:

для каждого пикселя картинки {    новый цвет пикселя =        сумма цветов соседних пикселей, умноженных на их коэффициенты из матрицы}

Чистый канвас не очень подходит для таких задач, а вот шейдеры очень даже. Но нетрудно догадаться, что чем больше матрица, тем больше соседних пикселей мы будем использовать. Если матрица 3x3 мы будем складывать 9 цветов, если 5x5 25, если 7x7 49 и.т.д. Больше операций больше нагрузка на процессор или видеокарту. Это неизбежно повлияет на производительность страницы в целом.

По возможности используйте маленькие матрицы для подобных эффектов, если вам нужно их накладывать куда-то в реальном времени.


В рамках SVG у нас есть специальный тег feConvolveMatrix, который сделан как раз для создания подобных эффектов:

<filter id=my-image-filter>    <feConvolveMatrix        kernelMatrix=0 0 0                      0 1 0                      0 0 0    /></filter>

Здесь мы сделали простейший фильтр для картинки, который не делает ничего новый цвет для каждого пикселя будет равен текущему, умноженному на 1, а значения для цветов соседних пикселей умножатся на 0.

Обратите внимание, что разные браузеры рендерят SVG по-разному, и цветопередача тоже может плавать в очень широких пределах. Порой разница просто катастрофическая. Так что всегда тестируйте свои SVG фильтры или используйте canvas это более предсказуемая штука в нашем контексте.

Если мы начнем расставлять числа по слоям, от большего у меньшему, то получится blur:



Чем больше матрица, чем больше соседних пикселей мы затрагиваем, тем сильнее мылится картинка. Главное здесь не забывать нормализовать значения, а то изображение просто засветится.

Теперь, зная как работает blur, мы можем понять, почему активное его использование на странице в рамках CSS или SVG ведет к тормозам для каждого пикселя браузер проделывает кучу расчетов.

Если начать экспериментировать со сменой знаков у коэффициентов и расставлять их в разные паттерны, то получатся эффекты sharpen, edge detection и некоторые другие. Попробуйте поиграть с ними самостоятельно. Это может быть полезно.



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

Промежуточные итоги


Обобщим сказанное в этой части:

  • Матрицы могут использоваться не только для трансформаций, связанных с координатами, но и для создания цветовых фильтров. Делается все по тому же принципу.
  • Матрицы могут использоваться как удобное 2D-хранилище для каких-то данных, в том числе разных коэффициентов для визуальных эффектов.

Заключение


Если немного абстрагироваться от запутанных алгоритмов, то матрицы станут вполне доступным инструментом для решения практических задач. С их помощью можно своими руками рассчитывать геометрические трансформации, в том числе в рамках CSS и SVG, строить 3D сцены, а также делать всевозможные фильтры для фотографий или для постобработки изображений в рамках WebGL. Все эти темы обычно выходят за рамки классического фронтенда и больше связаны с компьютерной графикой в целом, но, даже если вы не будете решать эти задачи непосредственно, знание принципов их решения позволит лучше понимать, как устроены некоторые ваши инструменты. Это лишним никогда не будет.

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

Кэширование данных увеличивает скорость даже в неожиданных случаях

13.04.2021 16:13:10 | Автор: admin

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

Эта статья основана на реальном проекте и реальном коде, который был ускорен с помощью кэша почти в полтора раза. Весь код написан на JavaScript.

Задача

Допустим, у нас есть матрица A порядка 2000x2000. Нужно посчитать обратную ей матрицу по простому модулю N. Другими словами, надо найти такую матрицу A-1, что AA-1 mod N = E.

Поскольку вычисления у нас происходят в поле по модулю, итерационные методы обращения нам не подойдут. Будем использовать старый добрый метод Гаусса.

Этот пост посвящён оптимизации метода Гаусса под данный конкретный случай. В реальном проекте вычисление обратной матрицы происходит в отдельном WebWorker, в данном примере обойдёмся главным потоком.

Вспомогательные функции

Для работы программы нам потребуется четыре вспомогательные функции. Первая вычисление (1 / x) mod N по расширенному алгоритму Евклида:

function invModGcdEx(x, domain){    if(x === 1)    {        return 1;    }    else    {        //В случае 0 или делителя нуля возвращается 0, означающий некий "некорректный результат"        if(x === 0 || domain % x === 0)        {            return 0;        }        else        {            //Расширенный алгоритм Евклида, вычисляющий такое число tCurr, что tCurr * x + rCurr * N = 1            //Другими словами, существует такое число rCurr, при котором tCurr * x mod N = 1            let tCurr = 0;            let rCurr = domain;            let tNext = 1;            let rNext = x;            while(rNext !== 0)            {                let quotR = Math.floor(rCurr / rNext);                let tPrev = tCurr;                let rPrev = rCurr;                tCurr = tNext;                rCurr = rNext;                tNext = Math.floor(tPrev - quotR * tCurr);                rNext = Math.floor(rPrev - quotR * rCurr);            }            tCurr = (tCurr + domain) % domain;            return tCurr;        }    }}

Вторая корректное целочисленное деление по модулю. Наивное вычисление c = a % b во всех языках программирования не будет давать математически верный результат, если a отрицательное число. Поэтому заведём функцию, которая будет делить правильно:

function wholeMod(x, domain){    return ((x % domain) + domain) % domain;}

Последние две функции относятся к операциям над строками матрицы. Первая вычитание из строки матрицы домноженной на число другой:

function mulSubRow(rowLeft, rowRight, mulValue, domain){    for(let i = 0; i < rowLeft.length; i++)    {        rowLeft[i] = wholeMod(rowLeft[i] - mulValue * rowRight[i], domain);    }}

Последняя нужная нам функция умножение строки матрицы на число:

function mulRow(row, mulValue, domain){    for(let i = 0; i < row.length; i++)    {        row[i] = (row[i] * mulValue) % domain;    }}

Обращение матрицы

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

function invertMatrix(matrix, domain){    let matrixSize = matrix.length;    //Инициализируем обратную матрицу единичной    let invMatrix = [];    for(let i = 0; i < matrixSize; i++)    {        let matrixRow = new Uint8Array(matrixSize);        matrixRow.fill(0);        matrixRow[i] = 1;        invMatrix.push(matrixRow);    }    //Прямой ход: приведение матрицы к ступенчатому виду    for(let i = 0; i < matrixSize; i++)    {        let thisRowFirst = matrix[i][i];        if(thisRowFirst === 0 || (thisRowFirst !== 1 && domain % thisRowFirst === 0)) //Первый элемент строки 0 или делитель нуля, меняем строку местами со следующей строкой, у которой первый элемент не 0        {            for(let j = i + 1; j < matrixSize; j++)            {                let otherRowFirst = matrix[j][i];                if(otherRowFirst !== 0 && (otherRowFirst === 1 || domain % otherRowFirst !== 0)) //Нашли строку с ненулевым первым элементом                {                    thisRowFirst = otherRowFirst;                                        let tmpMatrixRow = matrix[i];                    matrix[i]        = matrix[j];                    matrix[j]        = tmpMatrixRow;                    let tmpInvMatrixRow = invMatrix[i];                    invMatrix[i]        = invMatrix[j];                    invMatrix[j]        = tmpInvMatrixRow;                    break;                }            }        }        //Обнуляем первые элементы всех строк после первой, отнимая от них (otherRowFirst / thisRowFirst) * x mod N        let invThisRowFirst = invModGcdEx(thisRowFirst, domain);        for(let j = i + 1; j < matrixSize; j++)        {            let otherRowFirst = matrix[j][i];            let mulValue      = invThisRowFirst * otherRowFirst;            if(otherRowFirst !== 0 && (otherRowFirst === 1 || domain % otherRowFirst !== 0))            {                mulSubRow(matrix[j],    matrix[i],    mulValue, domain);                mulSubRow(invMatrix[j], invMatrix[i], mulValue, domain);            }        }    }    //Обратный ход - обнуление всех элементов выше главной диагонали    let matrixRank = matrixSize;    for(let i = matrixSize - 1; i >= 0; i--)    {        let thisRowLast    = matrix[i][i];        let invThisRowLast = invModGcdEx(thisRowLast, domain);        for(let j = i - 1; j >= 0; j--)        {            let otherRowLast = matrix[j][i];            let mulValue     = invThisRowLast * otherRowLast;            if(otherRowLast !== 0 && (otherRowLast === 1 || domain % otherRowLast !== 0))            {                mulSubRow(matrix[j],    matrix[i],    mulValue, domain);                mulSubRow(invMatrix[j], invMatrix[i], mulValue, domain);            }        }        if(thisRowLast !== 0 && domain % thisRowLast !== 0)        {            mulRow(matrix[i],    invThisRowLast, domain);            mulRow(invMatrix[i], invThisRowLast, domain);        }        if(matrix[i].every(val => val === 0))        {            matrixRank -= 1;        }    }    return {inverse: invMatrix, rank: matrixRank};}

Проверим скорость на матрице 500 x 500, заполненной случайными значениями из поля Z / 29. После 5 испытаний получаем среднее время выполнения в ~9.4с. Можем ли мы сделать лучше?

Первое, что мы можем заметить в поле Z / N не больше N обратных элементов. Чтобы избежать многократного вызова алгоритма Евклида, мы можем вычислить все обратные значения один раз и при надобности брать уже готовые. Изменим функцию соответствующим образом:

function invertMatrixCachedInverses(matrix, domain){    let matrixSize = matrix.length;    //Инициализируем обратную матрицу единичной    let invMatrix = [];    for(let i = 0; i < matrixSize; i++)    {        let matrixRow = new Uint8Array(matrixSize);        matrixRow.fill(0);        matrixRow[i] = 1;        invMatrix.push(matrixRow);    }    //Вычисляем все обратные элементы заранее    let domainInvs = [];    for(let d = 0; d < domain; d++)    {        domainInvs.push(invModGcdEx(d, domain));    }    //Прямой ход: приведение матрицы к ступенчатому виду    for(let i = 0; i < matrixSize; i++)    {        let thisRowFirst = matrix[i][i];        if(domainInvs[thisRowFirst] === 0) // <--- Первый элемент строки 0 или делитель нуля, меняем строку местами со следующей строкой, у которой первый элемент не 0        {            for(let j = i + 1; j < matrixSize; j++)            {                let otherRowFirst = matrix[j][i];                if(domainInvs[otherRowFirst] !== 0) // <--- Нашли строку с ненулевым первым элементом                {                    thisRowFirst = otherRowFirst;                                        let tmpMatrixRow = matrix[i];                    matrix[i]        = matrix[j];                    matrix[j]        = tmpMatrixRow;                    let tmpInvMatrixRow = invMatrix[i];                    invMatrix[i]        = invMatrix[j];                    invMatrix[j]        = tmpInvMatrixRow;                    break;                }            }        }        //Обнуляем первые элементы всех строк после первой, отнимая от них (otherRowFirst / thisRowFirst) * x mod N        let invThisRowFirst = domainInvs[thisRowFirst]; // <---        for(let j = i + 1; j < matrixSize; j++)        {            let otherRowFirst = matrix[j][i];            let mulValue      = invThisRowFirst * otherRowFirst;            if(domainInvs[otherRowFirst] !== 0) // <---            {                mulSubRow(matrix[j],    matrix[i],    mulValue, domain);                mulSubRow(invMatrix[j], invMatrix[i], mulValue, domain);            }        }    }    //Обратный ход - обнуление всех элементов выше главной диагонали    let matrixRank = matrixSize;    for(let i = matrixSize - 1; i >= 0; i--)    {        let thisRowLast    = matrix[i][i];        let invThisRowLast = domainInvs[thisRowLast]; // <---        for(let j = i - 1; j >= 0; j--)        {            let otherRowLast = matrix[j][i];            let mulValue     = invThisRowLast * otherRowLast;            if(domainInvs[otherRowLast] !== 0) // <---            {                mulSubRow(matrix[j],    matrix[i],    mulValue, domain);                mulSubRow(invMatrix[j], invMatrix[i], mulValue, domain);            }        }        if(domainInvs[thisRowLast] !== 0) // <---        {            mulRow(matrix[i],    invThisRowLast, domain);            mulRow(invMatrix[i], invThisRowLast, domain);        }        if(matrix[i].every(val => val === 0))        {            matrixRank -= 1;        }    }    return {inverse: invMatrix, rank: matrixRank};}

Замерим на тех же условиях и получаем результат в те же ~9.4с. Прироста нет, потому что даже при относительно долгом вычислении алгоритма Евклида он вычисляется всего один раз для каждой строки матрицы и особого вклада во время не приносит. Замерим производительность и посмотрим, что ещё можно улучшить.

72% времени занимает деление по модулю при сложении строк матрицы! Ну что тут сказать, деление по модулю, пусть и немного модифицированное для отрицательных чисел это элементарная операция и ускорять её некуда. Алгоритм поменять тоже не получится, из чего мы делаем вывод, что дальнейшее улучшение невозможно и статью можно закрывать.

...Или всё же возможно?

Если деление по модулю занимает столько времени, может, все возможные результаты тоже стоит сохранить в кэш? Даже если это не поможет, попытаться всё равно стоит при текущем времени выполнения функция неюзабельна.

Итак, используется wholeMod()только в функции mulSubRow():

rowLeft[i] = wholeMod(rowLeft[i] - mulValue * rowRight[i], domain);

Нам нужно для всех возможных значений x = a - b * c в поле Z / N сохранить результат выражения x mod N. Воспользоваться периодичностью мы не сможем, потому что тогда для вычисления индекса снова придётся использовать деление по модулю. В итоге при 0 <= a, b, c < N получаем N + (N - 1)^2 возможных значений. Много, но деваться некуда.

Из этих значений (N - 1)^2 значений меньше 0. Поскольку отрицательные индексы невозможны, при индексировании значением a - b * c к нему нужно прибавить (N - 1)^2. Тогда функция для сложения строк модифицируется:

function mulSubRowCached(rowLeft, rowRight, mulValue, wholeModCache, cacheIndexOffset){    for(let i = 0; i < rowLeft.length; i++)    {        rowLeft[i] = wholeModCache[rowLeft[i] - mulValue * rowRight[i] + cacheIndexOffset];    }}

Заметим, что эта функция накладывает ограничение на mulValue его значение не может быть больше domain и перед вызовом функции его тоже надо привести в наше поле Z / N. Кроме этого, обычное деление по модулю используется в функции mulRow().

Помимо wholeMod в вычитании строк матриц, используется . Кроме того, появилась вышеуказанная проблема с ограничением mulValue. Во всех этих случаях деление описывается формулой x = (a * b) mod N. Зная, что кэш хранит значения x = (c - a * b) mod N, мы можем вычислить (a * b) mod N, взяв значение кэша при c = 0 и вычтя его из N. Тогда функция для умножения строки на число модифицируется следующим образом:

function mulRowCached(row, mulValue, domain, wholeModCache, cacheIndexOffset){    for(let i = 0; i < row.length; i++)    {        row[i] = domain - wholeModCache[cacheIndexOffset - row[i] * mulValue];    }}

И получаем новое обращение матрицы:

function invertMatrix(matrix, domain){    let matrixSize = matrix.length;    //Инициализируем обратную матрицу единичной    let invMatrix = [];    for(let i = 0; i < matrixSize; i++)    {        let matrixRow = new Uint8Array(matrixSize);        matrixRow.fill(0);        matrixRow[i] = 1;        invMatrix.push(matrixRow);    }    //Вычисляем все обратные элементы заранее    let domainInvs = [];    for(let d = 0; d < domain; d++)    {        domainInvs.push(invModGcdEx(d, domain));    }    //Вычисляем кэш деления по модулю    const сacheIndexOffset = (domain - 1) * (domain - 1);    let wholeModCache = new Uint8Array((domain - 1) * (domain - 1) + domain);     for(let i = 0; i < wholeModCache.length; i++)    {        let divisor      = i - сacheIndexOffset;      //[-domainSizeCacheOffset, domainSize - 1]        wholeModCache[i] = wholeMod(divisor, domain); //Whole mod    }    //Прямой ход: приведение матрицы к ступенчатому виду    for(let i = 0; i < matrixSize; i++)    {        let thisRowFirst = matrix[i][i];        if(domainInvs[thisRowFirst] === 0) //Первый элемент строки 0 или делитель нуля, меняем строку местами со следующей строкой, у которой первый элемент не 0        {            for(let j = i + 1; j < matrixSize; j++)            {                let otherRowFirst = matrix[j][i];                if(domainInvs[thisRowFirst] !== 0) //Нашли строку с ненулевым первым элементом                {                    thisRowFirst = otherRowFirst;                                            //Меняем строки местами                    let tmpMatrixRow = matrix[i];                    matrix[i]        = matrix[j];                    matrix[j]        = tmpMatrixRow;                    let tmpInvMatrixRow = invMatrix[i];                    invMatrix[i]        = invMatrix[j];                    invMatrix[j]        = tmpInvMatrixRow;                    break;                }            }        }        //Обнуляем первые элементы всех строк после первой, отнимая от них (otherRowFirst / thisRowFirst) * x mod N        let invThisRowFirst = domainInvs[thisRowFirst]; // <---        for(let j = i + 1; j < matrixSize; j++)        {            let otherRowFirst = matrix[j][j];            if(domainInvs[otherRowFirst] !== 0)            {                let mulValue = domain - wholeModCache[сacheIndexOffset - otherRowFirst * invThisRowFirst]; // <---                mulSubRowCached(matrix[j],    matrix[i],    mulValue, wholeModCache, сacheIndexOffset); // <---                mulSubRowCached(invMatrix[j], invMatrix[i], mulValue, wholeModCache, сacheIndexOffset); // <---            }        }    }    //Обратный ход - обнуление всех элементов выше главной диагонали    let matrixRank = matrixSize;    for(let i = matrixSize - 1; i >= 0; i--)    {        let thisRowLast    = matrix[i][i];        let invThisRowLast = domainInvs[thisRowLast];        for(let j = i - 1; j >= 0; j--)        {            let otherRowLast = matrix[j][i];            if(domainInvs[otherRowLast] !== 0)            {                let mulValue = domain - wholeModCache[сacheIndexOffset - otherRowLast * invThisRowLast]; // <---                mulSubRowCached(matrix[j],    matrix[i],    mulValue, wholeModCache, сacheIndexOffset); // <---                mulSubRowCached(invMatrix[j], invMatrix[i], mulValue, wholeModCache, сacheIndexOffset); // <---            }        }        if(domainInvs[thisRowLast] !== 0)        {            mulRowCached(matrix[i],    invThisRowLast, domain, wholeModCache, сacheIndexOffset); // <---            mulRowCached(invMatrix[i], invThisRowLast, domain, wholeModCache, сacheIndexOffset); // <---        }        if(matrix[i].every(val => val === 0))        {            matrixRank -= 1;        }    }    return {inverse: invMatrix, rank: matrixRank};}

Замерим производительность. На той же матрице 500x500 по модулю 29 получаем время выполнения в ~5.4с.

Простите, что?

Нет, серьёзно, как это возможно? Кэшируем результат деления. Операции на два такта. В век супермедленной памяти и супербыстрых процессоров. Получаем прирост в 40%. Как?

Да, использование JavaScript создаёт определённый оверхед. Но JIT его нивелирует. Видимо, либо он нивелирует его недостаточно, либо не всё, чему нас учат про cache-friendly код правда.

И да, размер кэша растёт квадратично. Но если сравнить среднее время в полях по разному модулю, то прирост будет не сильно отличаться:

В реальном проекте, где был применён этот метод, матрицы не рандомные и прирост ещё заметнее.

Заключение

Можно ли ещё больше ускорить вычисление? К сожалению, больше ни одного способа я не знаю. Я думал над распараллеливанием вычислений, но обращение матриц очень плохо параллелизуется. Поэтому пока остаётся так.

Полный код я выложил на Pastebin.

Подробнее..

Почему мы трансформируем трёхмерные векторы матрицами 4х4?

03.02.2021 08:16:01 | Автор: admin

Почему не матрица 3х3? Почему в матрице 4х4 всё уложено именно так? Зачем там последняя строка, заполненная нулями и одной единицей в конце? Этими вопросами я задался накануне, решил поисследовать вопрос и рассказываю что выяснил.

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

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

Афинное преобразование T, примененное на вектор x можно записать как

T(\vec{x}) = A\vec{x}+\vec{b}

Трансформации одномерного вектора

Благорадя одномерности для простоты мы можем представить одномерную матрицу А, вектор b и вектор x как числа на вещественной прямой. Так же трансформированное значение x предпочту записывать как x', мне кажется так выглядит чуть более чисто:

\begin{array}{ll} A\rightarrow [a] \rightarrow a, \\ \vec{b} \rightarrow (b) \rightarrow b, \\ \vec{x} \rightarrow x, \\ T(x) \rightarrow x' \end{array}

Итого

x' = ax+b

Через манипуляции с а мы можем растягивать или сжимать вектор x (линейно трансформировать), а через манипуляции с b перемещать (нелинейно трансформировать).

Случаи, когда используются обе, линейная и нелинейная трансформации вместе довольно частые. Было бы удобно найти такое одно преобразование M, чтобы выразить в нём сразу оба:

x' = ax+b = M(x)

Возьмём для примера трансформацию x' = 3x + 4 (3x линейная трансформация и +4 нелинейная трансформация) и попробуем подобрать нужную матрицу.

\begin{array}{ll} Mx = 3x + 4\\ M = (3x+4)/x\\M=3+(\frac{4}{x})\end{array}

Свойства линейных трансформаций таковы, что они могут быть выражены через матрицы (например преобразование 3x может быть выражено через одномерную матрицу [3]), однако нелинейные трансформации (x+4) таких свойств лишены, от чего не удается выразить M без зависимости от x.

Трюк: поднимается на размерность выше

Если представить +4 как +4y, введя дополнительную координату y, выразив её так же через x и саму себя, то получится система линейных уравнений

x' = 3x + 4y \\ y' = \_x + \_y

которую можно выразить через матрицу 2x2, которая в свою очередь может выразить x' = 3x+4 и при этом не будет зависеть от x, т.е будет линейной трансформацией. Нижнюю строку я не заполнил конкретными числами, потому что на данный момент они не важны.

\begin{bmatrix} x'\\ y' \end{bmatrix} = \begin{bmatrix} 3 & 4 \\ \_ & \_ \end{bmatrix} \begin{bmatrix} x \\ y \end{bmatrix}

Так как матрица 2x2 умножается только на двумерный вектор, то необходимо предоставить не только х, но и вторую координату - y, а так как она учавствует в выражении +4y и мы хотим, чтобы это превратилось просто в +4, то вместе с неизвестным x на умножение с матрицей передаем единицу:

\begin{bmatrix} x'\\y' \end{bmatrix}= \begin{bmatrix} 3 & 4\\ \_ & \_ \end{bmatrix} \begin{bmatrix} x \\ 1 \end{bmatrix} \rightarrow \begin{array}{l} x' = 3\cdot x + 4\cdot 1\\y' = \_\cdot x + \_\cdot 1 \end{array}

Второе выражение в системе нам не интересно, оно введено только для того, чтобы иметь возможность получить матрицу, однако в результате вычислений будет возвращен двумерный вектор, с 3x+4 для x' и чем-то для y' и было бы сподручнее получить единицу в y' вместо непонятно чего, ведь в таком случае мы получим удобный вектор

\begin{bmatrix} x'\\1 \end{bmatrix}

который будет удобно умножать на любую другую матрицу далее. Чтобы получить единицу заполняем выражение соответствующими коэффициентами: y' = 1 = 0 x + 1 1

\begin{bmatrix} x'\\1 \end{bmatrix}= \begin{bmatrix} 3 & 4\\ 0 & 1 \end{bmatrix} \begin{bmatrix} x \\ 1 \end{bmatrix}

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

\begin{bmatrix} a & b\\0 & 1 \end{bmatrix}

Получается в матрице заключена линейная трансформация (a), нелинейная трансформация (b) и служебная строка (0 1) которая сохраняет для y' значение 1, чтобы вычисления x' проходили так, как мы ожидаем.

На самом деле трансформация - это просто хитрое слово, обозначающее функцию, но предполагаящая отображение некоторого движения. Вот как трансформация из примера выглядит визуально (https://www.geogebra.org/calculator/jvesjzyw):

\begin{bmatrix} 3 & 4 \\ 0 & 1 \end{bmatrix} \begin{bmatrix} 1 \\ 1 \end{bmatrix} = \begin{bmatrix} 7 \\ 1 \end{bmatrix}

Тот же трюк, но в двумерном пространстве

Имеем матрицу для вращения или масштабирования и вектор для перемещения

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

Матрица линейной трансформации выросла до 2х2 по понятным причинам двумерности пространства. Вектор b тоже вырос до двумерного и способен перемещать по обеим осям.

Вычисляемые значения для x' и y' будут такими же, как если бы мы считали по отдельности каждую трансформацию, а z' всегда будет равен 1 для удобства.

В трёхмерном пространстве ничего нового

Два преобразования, одно (линейное) выражено через матрицу, а другое (нелинейное) через вектор:

Два преобразования выраженных через одну матрицу более высокой размерности:

Полезные материалы

Computing 2D affine transformations using only matrix multiplication

https://medium.com/hipster-color-science/computing-2d-affine-transformations-using-only-matrix-multiplication-2ccb31b52181

Brilliant. Linear Transformations

https://brilliant.org/wiki/linear-transformations/

Explaining Homogeneous Coordinates & Projective Geometry

https://www.tomdalling.com/blog/modern-opengl/explaining-homogenous-coordinates-and-projective-geometry/

Nonlinear Transformation

https://stattrek.com/statistics/dictionary.aspx?definition=Nonlinear-Transformation

Can non-linear transformations be represented as Transformation Matrices?

https://math.stackexchange.com/a/455

Linear transformations and matrices | Essence of linear algebra, chapter 3

https://youtu.be/kYB8IZa5AuE

Подробнее..

Перевод Бесполезное представление, преобразовавшее математику

23.06.2020 14:06:23 | Автор: admin

Изначально от теории представлений отказались. Сегодня она играет важнейшую роль в большинстве областей математики.




Когда в конце XIX века впервые появилась теория представлений, многие математики сомневались в ценности этого подхода. В 1897 году английский математик Уильям Бёрнсайд писал, что сомневается в том, что эта необычная перспектива даст какие-то полезные результаты.

Бёрнсайд, по сути, говорил о том, что теория представлений бесполезна, сказал Джорди Уильямсон из Сиднейского университета в лекции 2015 года.

Прошло более ста лет после её дебюта, и теория представлений стала ключевым ингредиентом во множестве важнейших математических открытий. Однако её ценность сложно оценить с первого раза.

Не сразу становится понятно, что её стоит изучать, сказала Эмили Нортон из Кайзерслаутернского технического университета в Германии.

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

Математикам, по сути, про матрицы известно уже всё. Это одна из немногих математических тем, в которой мы хорошо и досконально разобрались, сказал Джаред Вайнштайн из Бостонского университета.

Чтобы понять, как матрицы могут представлять группы, стоит рассматривать каждый объект по очереди.

Возьмём сначала группы. Чтобы упростить пример, возьмём шесть симметрий равностороннего треугольника:
  • Две вращательных (на 120 и 240).
  • Три зеркальных (относительно линий, проведённых из каждой вершины через середину противоположной стороны).
  • Тождественная симметрия когда с треугольником ничего не происходит.




Шесть этих симметрий образуют замкнутую вселенную элементов группу формально именуемую S3. Это группа, поскольку любое количество этих симметрий можно применить к треугольнику последовательно и в любом порядке, а итоговый результат будет таким же, как если бы вы применили только одну. К примеру, если отразить треугольник, а потом повернуть его на 120, то вершины переориентируются таким же образом, как если бы вы применили другое отражение.

Делаю что-то одно, потом делаю что-то другое. Важно то, что в итоге получается всё равно симметрия треугольника, сказал Нортон.



Математики называют комбинацию из двух симметрий композицией. Одно действие из группы (отражение) соединяется с другим (вращение) и даёт третье (другое отражение). Вслед за математиками композицию можно считать умножением.

Нам нравится считать наши операции умножением, хотя это не перемножение чисел, а умножение преобразований, сказал Нортон.

Это легко увидеть, если рассмотреть ненулевые вещественные числа, также формирующие группу. У вещественных чисел есть нейтральный элемент число 1. Любое вещественное число, если его скомбинировать с 1, то есть, умножить на неё, остаётся неизменным. Также можно перемножать любую комбинацию вещественных чисел в любом порядке, и результат тоже всегда будет вещественным числом. Математики говорят, что группа вещественных чисел замкнута относительно умножения, то есть, из группы нельзя выйти, просто перемножая её элементы.

С момента открытия групп в 1830-х, они стали одним из наиболее важных объектов математики. Они кодируют информацию о простых числах, геометрических пространствах и вообще почти всего, что интересует математиков. Решение важной задачи часто превращается в изучение связанной с ней группы. Однако большинство групп гораздо сложнее понять, чем группу симметрий равностороннего треугольника. В группы Ли, к примеру, входит не шесть элементов, а бесконечное количество.

Иногда группы становятся чересчур сложными, сказал Вайнштейн.

И это подводит нас к теории представлений, превращающей загадочный периодами мир групп в хорошо известную нам территорию линейной алгебры.

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

Преобразование происходит при применении к вектору другой матрицы. К примеру, когда мы применяем к вектору матрицу

[2 0]
[0 2]

То он вытягивается в длину в два раза. Это пример линейного преобразования.



Другие матрицы выполняют другие линейные преобразования отражения, повороты и сдвиги. Есть и нейтральная матрица, оставляющая вектор без изменений (точно так же, как тождественная симметрия оставляет треугольник неизменным, а число 1 оставляет неизменными другие числа).

[1 0]
[0 1]

Линейная алгебра определяет арифметику, стоящую за этими преобразованиями. Матрицы можно перемножать, складывать и вычитать так же легко, как мы проделываем это с числами.

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

Представление даёт упрощённую картину группы, так же, как чёрно-белая фотография может служить недорогой имитацией оригинального цветного изображения. Можно сказать, что оно помнит некоторую базовую, но необходимую информацию о группе, забывая всё остальное. Математики стремятся избегать необходимости иметь дело со всеми сложностями группы; вместо этого они получают представление о её свойствах, изучая то, как она ведёт себя при превращении в упрощённый формат линейных преобразований.

Нам не нужно пытаться объятью всю группу сразу, сказал Нортон. Мы можем изучать её представление, меньшее по размеру, и всё равно что-то понять по поводу этой группы.

Почти всегда группу можно представить несколькими способами. К примеру, у S3 есть три разных представления через матрицы вещественных чисел: тривиальное, отражённое и знаковое.

Математики расставляют представления заданной группы в таблице таблице характеров где суммируется информация о группе. Строки обозначают каждое из различных представлений, а столбцы относятся к важным матрицам этих представлений матрице, сопоставленной нейтральному элементу группы, и матрицам, сопоставленным генерирующим элементам, порождающим все остальные элементы. Элементами таблицы служат значения, которые называют "следами" матриц, и подсчитывают через сумму диагональных элементов от левого верхнего угла к правому нижнему. Ниже приводится таблица характеров для трёх представлений S3.



Таблица характеров даёт упрощённую картину группы. Каждое из входящих в неё представлений даёт свою, отличающуюся от других информацию. Математики комбинируют различные перспективы, которые дают им эти представления, и получают общее впечатление о группе.

Много разных представлений помнят разные вещи, и если собрать всё это вместе, получится такая калейдоскопическая картинка вашей группы, сказал Нортон.

В приведённой выше таблице характеров математики сразу же узнают таблицу для S3. Однако иногда одна и та же таблица характеров может представлять разные группы при работе с упрощениями некая неоднозначность всегда возникает.

В таких неоднозначных случаях математики могут пользоваться дополнительными инструментами. Один из них изменение числовой системы, в рамках которой они создают своё представление. Вышеуказанное представление S3 получается при помощи матриц с вещественными числами в качестве элементов однако можно было бы использовать и комплексные числа (такие, у которых есть реальная и мнимая часть). Большая часть теории представлений их и использует.

Некоторые из самых продуктивных представлений не используют ни вещественные, ни комплексные числа. Они используют матрицы, элементы которых взяты из миниатюрных, или модульных числовых систем. Это мир арифметики циферблата, в котором 7+6 оборачивается вокруг 12-часового циферблата и даёт 1. У двух групп с одинаковыми таблицами характеров в вещественном представлении могут быть разные таблицы характеров в модульном представлении, что позволяет различать их.

Сегодня теория представлений является основным инструментом для множества областей математики: алгебры, топологии, геометрии, математической физики и теории чисел включая обширную программу Ленглендса.

Философия теории представлений начала с огромной скоростью поглощать огромные области математики во второй половине XX века, сказал мне Уильямсон.

Теория представлений и в частности, модульные представления сыграли важную роль в знаковом доказательстве Великой теоремы Ферма, полученном Эндрю Уайлсом в 1994 году. В задаче вставал вопрос о существовании решений уравнений вида an + bn = cn в целых числах. Уайлс доказал, что для n>2 таких решений не существует. Если говорить примерно, то он доказывал, что если бы такие решения существовали, привели бы к появлению группы эллиптической кривой с весьма необычными свойствами. Эти свойства были настолько необычными, что казалось возможным доказать невозможность существования подобного объекта. Однако напрямую доказать, что он не существует, оказалось слишком тяжело. Вместо этого Уайлс обратился к семейству модульных представлений, которое было бы связано с этой группой, если бы она существовала. Он доказал, что такого семейства модульных представлений быть не может, что означает, что не может существовать и группы (или эллиптической кривой), что означает, что и решений тоже не существует.

Что, в свою очередь, означает, что примерно через 100 лет после того, как Уильям Бёрнсайд отбросил теорию представлений как бесполезную, она оказалась критически важным компонентом, возможно, наиболее знаменитого доказательства XX века.

Я не мог придумать доказательства Великой теоремы Ферма, в котором бы нигде не использовалась теория представлений , сказал Вайнштейн.
Подробнее..

Что такое HDR10? Разбор

05.02.2021 14:16:53 | Автор: admin
70% информации о мире человек получает через зрение. Фактически глаза наш главный орган чувств.Но можем ли мы доверять нашему зрению?

Давайте взглянем на картинку. Вроде ничего необычного. Но что если я вам скажу, что ячейки A и B совершенного одного цвета.





На самом деле мы не всегда можем отличить светлое от темного. Далеко за примерами ходить не надо: помните сине-черное / бело-золотое платье или появившиеся чуть позже кроссовки?





И все современные экраны пользуются этой особенностью человеческого зрения. Вместо настоящего света и тени нам показывают их имитацию. Мы настолько к этому привыкли, что даже не представляем что может быть как-то иначе. Но на самом деле может. Благодаря технологии HDR, которая намного сложнее и интереснее, чем вы думаете.Поэтому сегодня мы поговорим, что такое настоящее HDR-видео, поговорим про стандарты и сравним HDR10 и HDR10+ на самом продвинутом QLED телевизоре!



На самом деле первое, что надо знать про HDR: это не просто штука, которая правильно хранит видео. Чтобы увидеть HDR-контент нам нужно две составляющие: сам контент, и правильный экран, который его поддерживает. Поэтому смотреть мы сегодня будем на QLED-телевизоре Samsung.

6 стопов SDR


Ежедневно наши глаза сталкиваются с экстремальными перепадами яркости. Поэтому человеческое зрение в ходе эволюции научилось видеть достаточно широкий динамический диапазон (ДД), то есть разницу улавливать разницу между разными уровнями яркости. Фотографы и киноделы знают, что ДД измеряется в ступенях экспозиции или стопах (f-stop).

Так сколько стопов видит человеческий глаз? Скажу так по разному.

Если завязать вам глаза, вывести в незнакомое место и резко снять повязку, то в эту секунду вы увидите 14 стопов экспозиции. Это не мало. Вот камера, на которую я снимаю ролики, видит только 12 стопов. И это ничто по сравнению с человеческим зрением, потому что оно умеет адаптироваться.

Спустя пару секунд, когда ваши глаза привыкнут к яркости и обследуют пространство вокруг, настройки зрения подкрутятся и вы увидите потрясающую игру света и тени из 30 стопов экспозиции!





Ух! Красота! Но когда мы смотрим видео на ТВ или на экране смартфона, нам остаётся довольствоваться только 6 стопами экспозиции, потому как видео со стандартным динамическим диапазоном или SDR больше не поддерживает.

Яркость


Почему так мало? Вопрос исторический и связан он с двумя этапами.

Стандарты современного SDR видео зародились еще в середине 20-го века, когда появилось цветное телевидение. Тогда существовали только ЭЛТ телевизоры, и они были очень тусклые. Максимальная яркость была 100 нит или кандел на квадратный метр. Кстати, кандела это свеча. Поэтому 100 кандел на квадратный метр буквально означает уровень яркости 100 свечей, расположенных на площади в 1 метр. Но если вам не нравится измерять яркость в свечах, вместо кандел на квадратный метр можно просто говорить ниты. Кстати в нашем телевизоре Samsung Q950T 4000 нит.

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

Одной из особенностей технологии QLED является высокая пиковая яркость. Это самые яркие ТВ на рынке, они даже ярче OLED.

Современные QLED-телевизоры способны выдавать целых 4000 нит яркости, что в 40 раз больше, чем заложено в стандарт SDR. Потрясающе показывай, что хочешь. Но по-прежнему 99% контента, который мы видим это SDR, поэтому смотря YouTube на своём потрясающем AMOLED-дисплее, вы фактически смотрите эмуляцию кинескопа из гостиной времен разгара холодной войны. Такие дела.

Глубина цвета


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

Тогда появился революционный стандарт цифровое телевидение высокой четкости HDTV, частью которого стала глубина цвета 8 бит.Это значит, что у каждого из базовых цветов красного, зеленого и синего может быть только 256 значений. Возводим 2 в 8-ю степень получается 256 это и есть 8 бит..

Итого на три канала, всего 16 777 216 миллионов оттенков.



Кажется, что это много. Но человек видит куда больше цветов. И все эти некрасивые ступенчатые переходы, которые часто можно заметить на видео и фотографиях и конечно в YouTube, спасибо его фирменному кодеку это как раз ограничения 8 бит.



Но самое интересное, что эти два ограничения: 6 стопов экспозиции и 8 бит на канал, не позволяли SD-видео сымитировать главную особенность человеческого зрения его нелинейность! Поэтому поговорим про восприятие яркости.

Восприятие яркости


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



Иначе, для человеческого глаза в тенях перепады между уровнями яркости будут уж слишком большие, в светах, наоборот, совершенно незаметные, особенно если у вас в распоряжении всего 256 значений, которые есть в распоряжения SDR видео.



Но в отличие от SDR HDR видео кодируется с глубиной цвета, как минимум 10 бит. А это 1024 значения на канал и итоговые более миллиарда оттенков (1024 x 1024 x 1024 = 1 073 741 824)





А предельная яркость изображения в HDR видео стартует от 1000 нит и может достигать 10000 нит. Это в 100 раз ярче SDR!

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



Метаданные


Итак, мы с вами выяснили, что возможности HDR сильно превосходят SDR, и HDR показывает куда более страшную и всю из себя контрастную картинку, но! Какая разница, какой там у тебя формат видео, SDR или HDR, если качество изображения всё равно зависит от экрана, на котором ты смотришь. На некоторых экранах SDR выглядит так насыщенно и контрастно, что HDR даже и не снилось.Всё так!

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

Но HDR-видео в отличие от SDR не просто выводит изображение на экран, но еще и умеет сообщать телевизору, как именно нужно его показывать! Делается это при помощи так называемых метаданных.



Они бывают двух видов.

Статические метаданные. Содержат в себе настройки настройки яркости и контраста всего видео целиком. Например, человек, который мастерил какое-нибудь атмосферное, темное кино может указать, что максимальная яркость в этом фильме всего 400 нит. Поэтому телевизор с яркостью 4000 нит не будет задирать яркость и превращать ваш хоррор-фильм в детский утренник. Или наоборот фильм с яркостью 4000 нит по максимуму раскроется не только на телевизоре, который тянет такую яркость, но и на более тусклом экране, так как картинка правильно сожмётся до возможностей телевизора.

Но бывают такие фильмы, которые в целом темные, но в них есть сцены с яркими вспышками света. Или например фильм про космос, в котором ярко сияют звезды. В таких случаях необходимо настроить яркость каждой сцены отдельно.

Для это существуют динамические метаданные. Они содержат в себе настройки каждого пикселя в каждом кадре фильма. Более того, эти метаданные содержат информацию на каком дисплее мастерился контент. А значит ваш дисплей может взять эти настройки и адаптировать изображение так, чтобы вы получили максимально приближенную к задумке автора картинку.

HDR10 и HDR10+


Самый распространённый формат с поддержкой статический метаданных это HDR10.Более того это самый распространенный HDR формат в принципе. Если видите наклейку HDR на телевизоре знайте: он поддерживает HDR10. Это его плюс.

Но поддержка только статических метаданных не позволяют назвать его настоящим HDR.Поэтому компания Samsung, совместно с 20th Century Fox и Panasonic решили исправить это недоразумение и добавили к HDR10 поддержку динамических метаданных, назвав новый стандарт HDR10+.



Получился он царский 10 бит, 4000 нит, более миллиарда оттенков.Но видна ли разница между HDR10 и 10+ на практике.

У нас есть QLED телевизор Samsung Q950T, который как раз поддерживает оба формата. Поэтому сравнение будет максимально корректным. Мы запустили кино, которые смастерили в HDR10 и HDR10+. И знаете, что я действительно увидел разницу.На этом телевизоре и HDR10 выглядит круто, а HDR10+ вообще разрывает шаблон. И дело не только в стандарте HDR10+.

Adaptive Picture




Дело в том, что HDR-контент существенно более придирчив к качеству дисплея, чем SDR. Например, яркость в HDR-видео указывается не в относительных значениях, то есть в процентах, а в абсолютных в нитах.Поэтому, хочешь не хочешь, но если в метаданных указано, что этот конкретный участок изображения должен светить 1000 нит нужно, чтобы телевизор сумел выдать такую яркость. Иначе, это уже будет не HDR.

А если, вдруг, вы смотрите видео днём, в ярко освещенной комнате, то нужно еще компенсировать окружающее освещение.Большинство устройств не справляются с этой задачей. Но, у QLED телевизоров Samsung, в этом плане есть, огромное преимущество.

Во-первых, в них используется технология Adaptive Picture, которая подстраивает яркость и контрастность изображения в зависимости от окружающего освещения.

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

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

Другие технологии




Естественно, это не единственная крутая технология внутри данного телевизора. Здесь установлен мощный нейропроцессор Quantum 8K, который в реальном времени умеет апскейлить 4K-контент до 8К. Причём он не просто повышает четкость изображения, он распознаёт разного типа текстуры и дополнительно их прорабатывает.Еще тут сверхширокие углы обзора, прекрасный объемный звук, который кстати тоже адаптируется под уровень шума в помещении в реальном времени. И масса других технологии, эксклюзивных для QLED-телевизоров Samsung.

Но главная технология сегодняшнего вечера HDR10+ и, что прекрасно это не эксклюзив.



HDR10+ это открытый и бесплатный стандарт, как и обычный HDR10. Всё это дает ему огромное преимущество перед, по сути, таким же, но платным Dolby Vision.Поэтому HDR10+ есть не только в телевизорах и смартфонах Samsung его поддерживают практически все производители телевизоров, смартфонов, камер, ну и, конечно, в этом формате снимаются и делаются фильмы. А значит у HDR10+ есть все шансы стать настоящим народным стандартом HDR, которым вы сможете насладиться на всех экранах страны, как больших, так и малых.
Подробнее..

Перевод Наглядно о том, почему трансформеры работают настолько хорошо

20.06.2021 18:15:44 | Автор: admin

Трансформеры за последние несколько лет штурмом захватили мир NLP, а сегодня они с успехом применяются в выходящих за рамки NLP приложениях. Они обладают такими возможностями благодаря модулю внимания, который схватывает отношения между всеми словами последовательностей. Но самый важный вопрос как именно трансформеры делают это? Попытаемся ответить и понять, почему трансформеры способны выполнять такие вычисления. Итак, цель статьи, чуть сокращённым переводом которой мы делимся к старту курса о машинном и глубоком обучении, разобраться не только с тем, как что-то работает, но и почему работает так. Чтобы понять, что движет трансформерами, мы должны сосредоточиться на модуле внимания. Начнём с входных данных и посмотрим, как они обрабатываются.


Как входная последовательность попадает в модуль внимания

Модуль внимания присутствует в каждом энкодере внутри стека каждого энкодера, а также внутри стека каждого декодера. Сначала внимательно посмотрим на энкодер.

Модуль внимания в энкодереМодуль внимания в энкодере

Для примера предположим, что мы работаем над задачей перевода с английского на испанский, где исходная последовательность слов The ball is blue, а целевая последовательность La bola es azul.

Исходная последовательность сначала проходит через слой векторного представления и позиционного кодирования, генерирующего векторы векторного представления для каждого слова последовательности. Векторное представление передаётся в энкодер, где вначале попадает в модуль внимания.

Внутри модуля внимания последовательность векторного представления проходит через три линейных слоя, создающих три отдельные матрицы запроса (Query), ключа (Key) и значения (Value). Именно эти три матрицы используются для вычисления оценки внимания [прим. перев. оценка определяет, сколько внимания нужно уделить другим частям входного предложения, когда мы кодируем слово в определённой позиции]. Важно помнить, что каждая "строка" этих матриц соответствует одному слову исходной последовательности.

Поток исходной последовательностиПоток исходной последовательности

Каждая входная строка это слово из последовательности

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

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

Расположение каждого слова в исходной последовательностиРасположение каждого слова в исходной последовательности

Каждое слово проходит серию обучаемых преобразований (трансформаций)

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

Линейные веса и веса векторного представления обученыЛинейные веса и веса векторного представления обучены

Ключевой вопрос заключается в том, как трансформер определяет, какой набор весов даст ему наилучшие результаты? Держите этот момент в памяти мы вернёмся к нему немного позже.

Оценка внимания это скалярное произведение матрицы ключа и матрицы запроса слов

Модуль внимания выполняет несколько шагов, но здесь мы сосредоточимся только на линейном слое и на оценке внимания.

Многоголовое вниманиеМногоголовое вниманиеРасчёт оценки вниманияРасчёт оценки внимания

Как видно из формулы, первый шаг в рамках модуля внимания умножение матрицы, то есть скалярное произведение между матрицей Query (Q) и транспонированием матрицы ключа Key (K). Посмотрите, что происходит с каждым словом. Итог промежуточная матрица (назовём её факторной матрицей [матрицей множителей]), где каждая ячейка это результат матричного умножения двух слов.

Скалярное произведение матрицы запроса и матрицы ключаСкалярное произведение матрицы запроса и матрицы ключа

Например, каждый столбец в четвёртой строке соответствует скалярному произведению между четвёртым словом запроса и каждым ключевым словом.

Скалярное произведение между матрицами запроса и ключаСкалярное произведение между матрицами запроса и ключа

Оценка внимания скалярное произведение между запросом-ключом и значением слов

Следующим шагом является матричное умножение между этой промежуточной матрицей множителей и матрицей значений (V), чтобы получить оценку внимания, который выводится модулем внимания. Здесь мы можем видеть, что четвёртая строка соответствует четвёртой матрице слов запроса, умноженной на все остальные ключевые слова и значения.

Скалярное произведение между матрицами ключа запроса и значенияСкалярное произведение между матрицами ключа запроса и значения

Получается вектор оценки внимания (Z), который выводится модулем внимания. Выходной результат можно представить следующим образом: для каждого слова это закодированное значение каждого слова из матрицы Значение, взвешенное матрицей множителей. Матрица множителей представляет собой точечное произведение значения запроса для данного конкретного слова и значения ключа для всех слов.

Оценка внимания это взвешенная сумма значения словОценка внимания это взвешенная сумма значения слов

Какова роль слов запроса, ключа и значения?

Слово запроса это слово, для которого мы рассчитываем внимание. В свою очередь слово ключа и значения это слово, на которое мы обращаем внимание, то есть определяем, насколько это слово соответствует слову запроса.

Оценка внимания для слова blue обращает внимание на каждое словоОценка внимания для слова blue обращает внимание на каждое слово

Например, для предложения The ball is blue строка для слова blue будет содержать оценку внимания для слова blue с каждым вторым словом. Здесь blue это слово запроса, а другие слова ключ/значение. Выполняются и другие операции, такие как деление и softmax, но мы можем проигнорировать их в этой статье. Они просто изменяют числовые значения в матрицах, но не влияют на положение каждой строки слов в ней. Они также не предполагают никаких взаимодействий между словами.

Скалярное произведение сообщает нам о сходстве слов

Итак, мы увидели, что оценка внимания отражает некоторое взаимодействие между определённым словом и каждым другим словом в предложении путём скалярного произведения с последующим их сложением. Но как матрица умножения помогает трансформеру определять релевантность между двумя словами?

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

Каждая ячейка представляет собой скалярное произведение двух векторов словКаждая ячейка представляет собой скалярное произведение двух векторов слов

Для получения скалярного произведения двух векторов мы умножаем пары чисел, а затем суммируем их.

  • Если два парных числа (например, a и d выше) оба положительны или оба отрицательны, произведение положительно. Произведение увеличит итоговую сумму.

  • Если одно число положительное, а другое отрицательное, произведение будет отрицательным. Произведение уменьшит итоговую сумму.

  • Если произведение положительное, то, чем больше два числа, тем больше их вклад в окончательную сумму.

Это означает, что, если знаки соответствующих чисел в двух векторах выровнены, итоговая сумма будет больше.

Как трансформер изучает релевантность между словами?

Скалярное произведение также применимо к оценке внимания. Если векторы для двух слов более выровнены, оценка внимания будет выше. Итак, какого поведения мы хотим от трансформера? Мы хотим, чтобы оценка внимания была высокой для двух релевантных друг другу слов в предложении. И мы хотим, чтобы оценка двух слов, не связанных друг с другом, была низкой.

Например, в предложении The black cat drank the milk слово milk очень релевантно к drank, возможно, немного менее релевантно для cat, и нерелевантно к black. Мы хотим, чтобы milk и drink давали высокую оценку внимания, чтобы milk и cat давали немного более низкую оценку, а для milk и black незначительную. Мы хотим, чтобы модель научилась воспроизводить этот результат. Чтобы достичь воспроизводимости, векторы слов milk и drank должны быть выровнены. Векторы milk и cat несколько разойдутся. А для milk и black они будут совершенно разными.

Давайте вернёмся к вопросу, который мы откладывали: как трансформер определяет, какой набор весов даст ему наилучшие результаты? Векторы слов генерируются на основе векторного представления слов и весов линейных слоёв. Следовательно, трансформер может изучить эти векторные представления, линейные веса и так далее, чтобы создать векторы слов, как требуется выше.

Другими словами, он будет изучать эти векторные представления и веса таким образом, что если два слова в предложении релевантны друг другу, то их векторы слов будут выровнены, следовательно, получат более высокe. оценку внимания. Для слов, которые не имеют отношения друг к другу, их векторы не будут выровнены и оценка внимания будет ниже.

Следовательно, векторные представления слов milk и drank будут очень согласованными и обеспечат высокую оценку внимания. Они будут несколько отличаться для milk и cat, производить немного более низкую оценку и будут совершенно разными в случае milk и black: оценка внимания будет низкой вот лежащий в основе модуля внимания принцип.

Итак, как же работает трансформер?

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

В этом кроется одна из причин введения трёх линейных слоёв и создания трёх версий входной последовательности: для запроса, ключа и значения. Такой подход даёт модулю внимания ещё несколько параметров, которые он может изучить, чтобы подстроить процесс создания векторов слов.

Самовнимание энкодера в трансформере

Внимание используется в трансформере в трёх местах:

  • Самовнимание в энкодере исходная последовательность обращает внимание на себя.

  • Самовнимание в декодере целевая последовательность обращает внимание на себя.

  • Энкодер-декодер-внимание в декодере целевая последовательность обращает внимание на исходную последовательность.

Внимание в ТрансформереВнимание в Трансформере

В самовнимании энкодера мы вычисляем релевантность каждого слова в исходном предложении каждому другому слову в исходном предложении. Это происходит во всех энкодерах стека.

Декодер самовнимания в трансформере

Большая часть того, что мы только что видели в энкодере самовнимания, применима и к вниманию в декодере, но с некоторыми существенными отличиями.

Внимание в декодереВнимание в декодере

В декодере самовнимания мы вычисляем релевантность каждого слова в целевом предложении каждому другому слову в целевом предложении.

Самовнимание декодераСамовнимание декодера

Энкодер-декодер модуля внимания в трансформере

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

Энкодер-декодер ВниманияЭнкодер-декодер Внимания

Заключение

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

Здесь мы видим, что за сложными идеями скрываются простые решения. Более того, есть ощутимая вероятность того, что вскоре понимание внутренних механизмов глубокого обучения станет второй грамотностью, как сегодня второй грамотностью стало знание ПК в целом и если вы хотите углубиться в область глубокого и машинного обучения, получить полное представление о современном ИИ, вы можете присмотреться к нашему курсу Machine Learning иDeep Learning, партнёром которого является компания NVIDIA.

Узнайте, как прокачаться и в других специальностях или освоить их с нуля:

Другие профессии и курсы
Подробнее..

Что делают 3D-сенсоры в смартфонах? РАЗБОР

25.09.2020 22:13:02 | Автор: admin
Все чаще мы видим в смартфонах так называемые 3D-сенсоры, или сенсоры глубины. Большинство из них также называют ToF-сенсорами аналогично одноименной технологии. По слухам, такой сенсор будет установлен и в новом iPhone (там он называется LiDAR, подробнее мы об этом рассказывали в другом материале). Эти сенсоры довольно дорого стоят, но зачем они нужны понятно не всем. Производители уверяют, что сенсоры позволяют делать лучше фото и портреты или добавляют фишки в дополненную реальность. Но так ли это на самом деле?



Сегодня обсудим, зачем нужны 3D-сенсоры в смартфонах, как это работает, ну и конечно, проведем несколько тестов и проверим заявления производителей.

Что такое 3D сенсор (сенсор глубины)


Для начала, давайте разберемся, а что такое 3D-сенсор? Фотокамеры захватывают проекцию окружающего мира на плоскость. По одной лишь фотографии не понять реальный размер объекта размером ли он с бутылку или с Пизанскую башню. И расстояние до него тоже не понять.



Для того, чтобы понимать реальные размеры объектов на фото, масштабы съемки, отличать, что ближе к камере, а что дальше, и нужны 3D-сенсоры.Они уже давно и активно применяются в робототехнике, автономном транспорте, играх, медицине и много где еще. Более того, наши глаза это тоже 3D сенсор. При этом, в отличие от LiDARа и ToF-сенсоров в смартфонах, глаза пассивный 3D-сенсор. То есть не излучающий никакого света, а работающий только на основе поступающего света. Только благодаря этому мы можем хоть как-то перемещаться в пространстве и взаимодействовать с окружающими объектами. Теперь 3D-сенсоры появились и в смартфонах.

Как работает ToF?


LiDAR в iPadе, а также все 3D-сенсоры в Android-смартфонах это time-of-flight или сокращенно ToF-сенсоры. Они определяют расстояния до объектов вокруг, напрямую измеряя сколько времени понадобится свету, чтобы долететь от камеры до объекта и вернуться обратно. Это очень похоже на эхо в пещере, оно тоже после отражения от стенок возвращается к нам с запаздыванием. Чтобы пролететь 1 метр свету нужно 3 наносекунды, для 1 см 30 пикосекунд. Вроде бы все понятно. Но есть проблема.

Это очень маленькие промежутки времени. Как камера может такое замерить? Не будет же она делать миллиард кадров в секунду, а потом их сравнивать? Есть 2 основных подхода для решения этой проблемы: dToF (direct ToF) и iToF (indirect ToF). И чтобы вас заинтриговать еще сильнее: абсолютное большинство Android-смартфонов используют как раз iToF сенсоры, тогда как LiDAR в Apple iPad и скорее всего в грядущих iPhone это редкий представитель семейства dToF сенсоров. Так чем же они отличаются?

iToF indirect ToF




Начнем с iToF. В таких сенсорах излучатель отправляет высокочастотный модулированный свет, то есть этот свет постоянно включается и выключается с частотой десятки миллионов раз в секунду. За счет того, что свету нужно время для полета до объекта и обратно, фаза, то есть вот это состояние где-то между включенностью и выключенностью, света, вернувшегося в камеру, немного отличается от фазы света в момент отправки. На сенсоре исходный и отраженный обратно от объекта сигналы накладываются друг на друга, и за счет этого определяется сдвиг фаз, который и позволяет понять расстояние до каждой точки объекта.

dToF direct ToF




dToF работает немного иначе. В таких сенсорах напрямую измеряется разница во времени между отправкой света и детектированием его отражения на сенсоре. Для этого используются так называемые SPAD: single photon avalanche diodes. Они могут детектировать крайне маленькие импульсы света, фактически даже ловить единичные фотоны. Такие SPAD расположены в каждом пикселе сенсора. А в качестве излучателя в таких сенсорах используются как правило так называемые VCSEL Vertical Cavity, Surface Emitting Laser. Это лазерный излучатель, подобный тем, что используются в лазерных мышках и много где еще. dToF сенсор в LiDAR разработан совместно с Sony и является первым массовым коммерческим dToF сенсором.

Можно лишь гадать, почему в iPad используется dToF сенсор, но давайте отметим преимущества такого сенсора. Во-первых, в отличие от iToF сенсора излучатель испускает не сплошную стену света, а лишь светит в отдельных направлениях, что позволяет экономить батарейку. Во-вторых, dToF сенсор меньше подвержен ошибкам в измерении глубины из-за так называемой multipath interference. Это типичная проблема iToF сенсоров. Она возникает из-за переотражения света между объектами перед попаданием обратно в сенсор и искажает измерения сенсора.

Как это работает, разобрались, давайте теперь посмотрим, а зачем вообще 3D-сенсоры используются в смартфонах.

Зачем это нужно в смартфонах



1. Безопасность




Первым массовым внедрением 3D-сенсоров в смартфонах мы обязаны Apple и технологии Face ID. Распознавание лиц при использованиитрёхмерных данных намного точнее и надежнее классического распознавания лиц по фото. Для Face ID Apple использует технологию структурированной подсветки, на ней мы остановимся подробнее как-нибудь в следующий раз.

2. AR




Большинство производителей заявляют, что именно более качественный и точный режим дополненной реальности является главной задачей 3D-сенсоров. Более того, это также поддерживается непосредственно компанией Google. Буквально недавно они представили грядущее обновление своей библиотеки дополненной реальности ARCore, позволяющее более реалистично размещать виртуальные объекты в реальности ивзаимодействовать с реальными объектами.

Для этой же задачи Apple встроили LiDAR в iPad Pro. Такое можно делать и без 3D-сенсора, но с ним все работает точнее и надежнее, плюс задача становится вычислительно сильно проще и разгружает процессор. 3D-сенсор выводит AR на другой уровень.

3. Улучшение фотографий




Ряд производителей, например, Samsung и HUAWEI заявляют, что 3D-сенсор используется в первую очередь для более качественного размытия фона и более точного автофокуса при съемке видео. Другими словами, он позволяет увеличить качество обычных фото и видео.

4. Прочее




Доступ к данным сенсоров у некоторых смартфонов открыт, поэтому появляется все больше приложений, предлагающих новые применения. Так, например, с помощью внешних приложений 3D-сенсор можно использовать для измерения объектов, трехмерного сканирования и motion tracking'а. Есть даже приложение, позволяющее сделать из своего смартфона прибор ночного видения.

Тесты


С тем как это работает в теории разобрались, давайте теперь посмотрим, как это работает на практике, и есть ли какой-то толк от этих дорогущих 3D-сенсоров в флагманах. Для тестов мы взялиRedmi Note 9S, у него есть ToF-сенсор и мы сделали несколько снимков в портретном режиме, но во втором случае просто закрыли 3D-камеру пальцем. И вот что получилось.



Всё просто размытие действительно больше и лучше, если ToF работает.



И для частоты эксперимента мы взяли Samsung Galaxy S20 Ultra, который также получил ToF-камеру.



И найдите хотя бы одно отличие?



Что получается? Дело в том, что в зависимости от производителя ToF-камера используется по-разному и в разной степени.

Можно сказать, что часть производителей смартфонов располагает ToF-датчики в своих смартфонов не для маркетинга, чтобы добавить ещё одну камеру, а скорее на всякий случай. А дальше уже алгоритмы решают использовать эту камеру или нет?



При этом на сегодняшний момент необходимости в LiDAR или ToF-камерах прямо нет. Так что это видимо чуть больше маркетинг.
Подробнее..

Mini-LED ЖК-дисплей на максималках. Разбор

05.04.2021 14:09:20 | Автор: admin
Технологию mini-LED незаслуженно обделили вниманием, ведь этом году она станет особенно актуальной. Вы наверное уже слышали, что такие дисплеи ждут в новых iPad Pro и MacBook! А телевизоры с mini-LED-матрицами уже появляются в продаже. Лучше ли они чем всеми любимый OLED?

Но что же такое mini-LED по своей сути? Главное не путайте ее с microLED и чуть позже поймете почему!


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

Вот вам первый сюрприз! mini-LED уходит корнями в традиционную технологию жидкокристаллических дисплеев Liquid Crystal Display с подсветкой. Эти самые мини-светодиоды работают так же, как и обычные светодиоды подсветки на LED-экранах.

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



Первое, что провернули технологи с mini-LED они в разы уменьшили сами элементы. Так, при диаметре всего около 200 микрон или 0,008 дюйма мини-светодиоды составляют пятую часть размера стандартных светодиодов, используемых в обычных ЖК-дисплеях.То есть мы поняли что уменьшение произошло в пять раз, закрепили!

Поскольку сами диоды меньше, на экране их можно разместить больше. Они также как и в LED-матрицах разделены на зоны подсветки, как раз за счет меньших размеров сами зоны тоже можно уменьшить и их количество возросло, что как раз очень важно для HDR контента.

Мы рассказывали об HDR и не раз, но я немного напомню, что самое важное скрывается в названии High Dynamic Range, то есть расширенный динамический диапазон.

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


Но, к сожалению, на ЖК-панелях достичь этого самого расширенного диапазона сложно из-за свойств самой технологии.Так как жидкокристаллические дисплеи идут с подсвечивающейся подложкой, по-настоящему, чёрного как на OLED там нет. Вам ли не знать, у кого смартфон с IPS-дисплеем. Поэтому производители идут на ухищрения, разбивая подсветку на зоны: чем больше зон подсветки, тем меньше ореолов на черном.

В чем же принципиальная разница mini-LED?В нём, этих зон существенно больше чем на LED-экранах как раз за счет мини-светодиодов. Каждая зона включается отдельно только там, где требуется. Получается прямо как волна на стадионе, когда нужно встать и включиться в неё, вы встаёте, а затем ждёте когда вновь до вас дойдёт очередь.

Полотно со светодиодами mini-LED может иметь более тысячи зон полного локального затемнения. К примеру, у LED таких зон может быть всего несколько десятков. А их отключение, в зависимости от качества дисплея, приводит к эффекту гало вокруг ярко освещённых объектов на тёмном фоне.

Такая система подсветки называется Local Dimming: те области, что не нужны для воспроизведения картинки просто отключаются и там как раз и возникает идеальный черный. И, вместе с запасом яркости, мы получаем тот самый диапазон по свету в итоге технология mini-LED готова к воспроизведению HDR-контента гораздо лучше обычного LCD.

Главные достоинства mini-LED




Подытожим главные достоинства по пунктам и немного сравним с OLED:

  1. В последних разработках mini-LED используется неорганический нитрид галлия (GaN), который не выцветает со временем, как OLED, и не становится жёлтым в местах, с часто используемыми светодиодами отличие от органических,
  2. Максимальная яркость составляет 4000 нит, что опять же выше чем у OLED.

Mini-LED умеет отображать HDR-контент, благодаря прокачанной системе Local Dimming по сравнению с обычными LED экранами, где зон подсветки существенно меньше, но тут он скорее проигрывает OLED-матрицам.

Производство mini-LED дешевле, чем производство OLED-матриц; то есть и цена готового продукта должна быть ниже.

Светодиоды сами по себе маленького размера, а значит позволяют сделать экран и само устройство тоньше.

Получается, все звезды сошлись: mini-LED это дешево, надежно, а еще мы получаем больший запас яркости и глубокий чёрный цвет (и это всё ещё технология на основе ЖК).

Но все ли так хорошо и стоит ли переставать копить на OLED и бежать в магазин за mini-LED телевизорами?

Главные проблемы mini-LED




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

Поэтому все сводится к тому, что mini-LED это некий компромисс он уже гораздо лучше LED и LCD, но ещё не OLED.

В конечном итоге всё сводится к тому что mini-LED дает превосходное качество изображения без больших затрат и рисков выгорания. Таким образом, все получили правильный баланс цена/качество/надёжность.

Так было бы в идеальном мире, но с ценой все тоже не так гладко, мы еще к этому перейдем!

Важный момент сравнения с OLED: последний далеко не всегда является предпочтительным вариантом для дисплеев ноутбуков и планшетов с высокой плотностью пикселей, особенно если необходимо добиться максимально возможной яркости.

Сравнение mini-LED и microLED




Существует утверждение, что mini-LED это некая переходная технология между LCD и microLED, однако если вы смотрели наш разбор microLED, то понимаете, что это не совсем так!

Mini-LED и MicroLED разные по своей природе. Первый основан на ЖК-технологии с использованием диодов меньшего размера для подсветки. Второй является эволюционным развитием OLED, в котором используются неорганические ещё более мелкие и яркие отдельные светодиоды красного, зеленого и синего цветов для прямого излучения света.

Другими словами, каждый пиксель излучает свой собственный свет в microLED, в то время как Mini-LED по-прежнему использует ЖК-матрицу для фильтрации подсветки, но подсветка предлагает больше контроля, чем традиционный ЖК-дисплей.То есть, если заглянуть в ближайшее будущее, то LED-дисплеи эволюционируют в mini-LED, а OLED в MicroLED. Немного обидно, что названия такие похожие но, по сути, мы опять получим две основные технологии, как и сейчас.

Будущие продукты на mini-LED




Как начнётся переход на mini-LED и в каких именно продуктах?

По сообщениям издания DigiTimes тайваньская компания Ennostar начала производство mini-LED дисплеев для будущего 12,9-дюймового iPad Pro, который выйдет уже совсем скоро, в конце первого или второго квартала этого года.

Джон Проссер также делал анонсы в Твиттере, которые напрямую связаны с mini-LED. Он подтвердил, что iPad Pro (2021) станет первым планшетом Apple с mini-LED дисплеем.Он даже назвал месяц: новый iPad выйдет уже в апреле!Но я бы не стал верить этому на 100%.

Помимо нового iPad Минг-Чи Куо предрекает выход новых моделей MacBook, которые будут представлены во второй половине этого года, также с новым типом дисплеев. Аналитик ожидает, что экраны новых 14-дюймовых и 16-дюймовых MacBook будут также выполнены по технологии mini-LED.

Из того, что уже представили на mini-LED, можно сделать список:

  • TCL представила на CES 2021 новую серию телевизоров с mini-LED;
  • Philips также показала два новый телевизора MiniLED 9636 и 9506;
  • LG показала линейку светодиодных телевизоров QNED Mini LED;
  • Samsung представила телевизоры линейки 2021 4K и 8K Neo QLED. В них Samsung будет использовать Quantum Mini LED собственная форма технологии, которая в сочетании с технологией квантовой матрицы и процессором Neo Quantum делает черные области экрана полностью чёрными (в них почти не будет серых зон от подсветки работающих областей), а яркость теоретически может быть выше, чем у конкурирующих самосветящихся OLED панелей.

И тут стоит вернуться к вопросу цен



Модели от Samsung с 8K-дисплеями Mini-LED будут стоить от $3500 до $9000 (от ~260 000 рублей до ~670 000 рублей) в зависимости от диагонали (65, 75 и 85 дюймов). Модели с 4K соответственно $1599,99, $2199,99, $2999,99 и $4499,99 за диагонали 55", 65", 75" и 85". LG и Philips пока ещё не объявили официальных цен на свои mini-LED телевизоры, но что-то подсказывает, что цена будет в том же диапазоне.

А теперь ради интереса давайте сравним народный 4K mini-LED телевизор от Samsung с диагональю 55" с аналогичной моделью от LG, но только с технологией OLED. За пример возьмём модель OLED55BXRLB 2020-го года выпуска, которая максимально схожа по характеристикам.



Вес, размер и разрешение безрамочного экрана (3840 2160), поддержка HDR то, что идентично в обоих моделях. Вплоть до того размеры телевизоров отличаются всего на пару миллиметров в ширину и на десять в глубину. Да, у модели Samsung целых четыре разъёма HDMI, тогда как у LG их всего два. Но зато у LG на борту Bluetooth 5.0, а у Samsung старый протокол версии 4.2. Но это всё мелочи, стоит лишь перейти к цене.

OLED-модель LG продаётся в России за 119 990 рублей, в то время как Samsung только-только начала продавать mini-LED модели за границей, где ту самую народную модель с диагональю 55" можно приобрести за те же 119 000 рублей в пересчёте на наши деньги. И это цена по курсу, наверняка, в России она будет дороже за счет дополнительных затрат на доставку, налоги и так далее.

Итоги




Вот тебе и более дешевая технология, понятно что она еще новая и Samsung будет держать планку.Хотя уже сейчас понятно, что производство mini-LED панелей должно быть дешевле, чем производство OLED, даже сейчас.

Другое дело, что пройдёт несколько лет, и Samsung уже нужно будет следить за предложениями своих конкурентов, да и технологию mini-LED точно обкатают и наладят массовое производство. Остаётся лишь ждать
Подробнее..

Что такое microLED и почему это круто? Разбор

16.12.2020 14:07:22 | Автор: admin
Уже не первый год утечки кричат, что Apple инвестирует много миллионов долларов в компании по разработке дисплеев на основе microLED.

Многие аналитики, в том числе анонимный китайский инсайдер @L0vetodream, заявляли в Твиттере, что в Apple Watch Series 6 будет совершенно новый дисплей, но этого не произошло.

Возможно виноват COVID-19, который затормозил процессы в технологической сфере и уже по новым данным нам известно, что новый тип дисплеев, microLED, мир увидит в гаджетах от яблочной компании не раньше 2023 года и, возможно, в совершенно новом гаджете!


Прошу не путать с miniLED, хоть названия и похожи разница колоссальная. Сегодня мы заглянем в настоящее будущее дисплеев и разберемся во всём, как вы любите.

Почему не развивать дальше OLED?




Прежде чем отправиться в будущее давайте разберемся с проблемами настоящего. Сейчас идет эпоха OLED, но мы по-прежнему миримся с некоторыми болячками данных экранов: выгорание, время отклика, яркость, да и энергопотребление неплохо было бы понизить! И часть из этих проблем ушла бы в прошлое с уменьшением числа светодиодов!

Вы спросите, а почему нельзя было дальше развивать OLED просто уменьшая светодиоды?Дело в том, что если уменьшить размер элемента снизится количество производимого света. А если повысить мощность, чтобы компенсировать уменьшение света увеличится энергопотребление и нагрев, что в разы снизит срок службы органических соединений, который на фоне неорганических и так слишком мал.

Получается, что OLED в тупике но почему же microLED видится как единственная правильная альтернатива и какие же продукты с этими экранами стоит ждать в первую очередь?



Что такое microLED?


Хоть о технологии мы услышали недавно microLED начали создавать ещё в далёком 2000-ом году, два профессора в Канзасском государственном университете Хунсин Цзян и Цзинюй Линь. Всеэти 20 лет технология совершенствовалась. Если всё начиналось с простых несенсорных панелей с буквально несколькими субпикселями, крошечными огоньками красного, зелёного и синих цветов, то теперь это уже настоящее поле из миллионов таких огоньков.



К слову, только в 2011 году группа учёных наконец преодолела планку разрешения 640 на 480 пикселей в формате Video Graphics Array или VGA, где были хромовые синие и зеленые микродисплеи, способные передавать видео.Основная сложность в процессе создания таких дисплеев заключается в том, что. microLED использует очень маленькие светодиоды субпикселей, тех самых: RGB.Их размеры составляют порядка 5 микрон, у OLED размеры выше в разы красный 64 на 46 мкм, зелёный 95 на 15 мкм, синий 95 на 49 мкм. (порядка 5 микрон в сравнении с миллиметровыми пикселями LED).

Кроме того время их отклика вместе с тем в разы меньше. И это один из первых бонусов, о котором мы еще поговорим подробнее.

Копнем глубже, и разберемся из чего же делаются и те, и другие светодиоды ведь именно материалы стали ключом к уменьшению размера.

MicroLED в отличие от OLED в качестве пикселей использует не органические светодиоды, а диоды на основе нитрида галлия, который широко используется для создания светодиодов полупроводниковых лазеров и сверхвысокочастотных транзисторов, в общем, для всего того, где нужна высокая точность и резкость.Такие диоды очень малы около одной десятой толщины человеческого волоса!

В чём главный плюс в microLED от того, что используется неорганический светодиод?




Да в том, что он просто не выцветает в процессе использования, как его органический конкурент OLED.

Чтобы было проще понять, представьте: на солнце лежат две футболки одна из 100% хлопка, а вторая синтетическая. Так вот та, что выполнена из натурального хлопка, выцветет или выгорит, а синтетическая продолжит лежать как ни в чём не бывало.Примерно то же происходит и с дисплеями у OLED при длительном использовании будет постепенно проявляться те самые выцветшие пиксели, вы их заметите по жёлтому оттенку на дисплее.

microLED придёт на смену OLED?


А теперь посмотрим что же мы получим при переходе от OLED к MicroLED. Внимание на табличку.



В итоге мы получаем: более высокую яркость, эффективность, скорость, высокую термостабильность и контрастность.

Так, например, компания LuxVue, купленная Apple, в какой-то момент сообщила, что разработанная ею технология в девять раз ярче, чем OLED и LCD!

Да-да, вы не ослышались, Apple уже купила компанию по производству microLED! То есть уже с 2023 года в гаджетах изКупертино могут стоять собственные microLED-матрицы.

Продукты на microLED




Но если не заглядывать в будущее, что мы имеем сегодня на microLED?

Первым, кто попытался (именно попытался) представить технологию microLED свету, была компания Sony и их телевизор Crystal LED Display в 2012 году. В нём компания использовала всего 6,22 миллиона микросветодиодов, но исходя из тех показателей, что были заложены в модели, контрастность изображения по сравнению с ЖК-дисплеями стала в 3,5 раза выше, цветовой диапазон в 1,4 раза выше, углы обзора составляли более 180 градусов, а также вышло более низкое энергопотребление (менее 70 Вт) по сравнению с моделями на LCD.

Лёд тронулся благодаря Sony, но у телевизора безусловно присутствовали детские болезни, а главное, дисплей был целиком воспроизведён из одного куска microLED-панели, а не был модульным, какэто предусматривается изначально.



Но прошло 5 лет, и Samsung ответила Sony, выпустив 146-дюймовый дисплей под названием Стена. И здесь корейская компания уже продемонстрировала возможность собирать экран под свои нужды и по необходимым размерам.



Хочешь небольшой телевизор с microLED на кухню? Да запросто! А, хочешь из тех же частей дособрать огромный телевизор в гостиную? Легко! Похоже, что использование модульного подхода становится промышленным стандартом для производства больших экранов.

Но увы, даже такой подход слишком дорого обходится потенциальному массовому покупателю чего уж говорить, Стена выставлялась на продажу исключительно под заказ и ценник на них составлял от 490 000 долларов, а заканчивался на отметке в 1,68 млн долларов! И это без учёта налогов.

Почему же так дорого и где другие гаджеты с microLED-ом?

Трудности microLED


Технология хоть и новая, но трудности с выходом на массовый рынок всё те же, что и когда-то были и с OLED-ом. Всё дело в том, что производить в огромных количествах на первых порах и под каждого конкретного производителя (той же Apple) и его гаджеты, очень трудно!

Заводов ещё слишком мало, производство не такое масштабное, отсюда и цена! Сейчас, когда OLED-дисплеи стали массовыми цена постепенно опускается всё ниже и ниже, а сами дисплеи проверены временем, производителям проще сделать выбор в пользу имеющихся технологий.

Но уже сейчас сами создатели технологии microLED заявляют: В связи с быстрым прогрессом, достигнутым в последнее время в этой области, вопрос уже не в том, сможет ли microLED, а в том, когда данные дисплеи проникнут на массовые рынки для различных применений. Получается, это уже вопрос времени!

Будущее с microLEDКакие же устройства будут первыми массовыми юзерамиmicroLED-а?




Еще раз упоминая доклад по этой технологии, процитирую: Внастоящее время microLED находится под пристальным вниманием почти всех крупных компаний в области технологий для умных часов, смартфонов,умных очков, приборных панелей и пико-проекторов и 3D/AR/VR дисплеев.

Почему именно эти области?Говоря о часах или Apple Watch, которые часто всплывали в слухах там важнейшими параметрами являются энергопотребление и яркость microLED даст прирост по обоим пунктам.

iPhone само собой перейдет на microLED, но тут нужно будет обеспечить огромные объемы производства.Что действительно интересно загадочные Apple Glass могут также стать носителем microLED, на это даже намекает схематичное изображение в том самом докладе, оно перед вами.



Другое подтверждение далее по тексту: microLED был исследован в качестве источника света для применения в оптогенетике и для связи с видимым светом.

Если оптогенетика это перспективное направление в медицине, то вот последняя фраза про связь с видимым светом намекает нам, что эти дисплеи, из-за своих конструктивных особенностей, будут использоваться не только в наших смартфонах, но и в умных очках, будь-то VR или AR.

Говоря другими словами, глаз находится в непосредственной близости от экрана и он способен разглядеть рисунок, в то время как расположение диодов OLED бы мешало погружению. У ЖК-дисплеев такой проблемы нет, но там по-прежнему нет и идеального черного.У microLED маленькие диоды, рисунок будет замечен меньше и черный также идеальный еще и время отклика выше одни бонусы.

Выводы




Подведём итог. microLED исправляет проблемы OLED, такие как выгорание, у него более высокая яркость и контрастность, а также возможность уменьшать или увеличивать дисплей под свои задачи модульность.Осталось удешевить производство, чем сейчас и занимаются Apple и Samsung, инвестировав в данную технологию уже несколько заводов переквалифицировались в производство microLED-дисплеев.

Но это не единственный тип дисплея неизученный нами: еще же есть какой-то miniLED.
Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru