Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrong proportions of dewarped images #5

Open
noobie-iv opened this issue Jan 3, 2025 · 252 comments
Open

Wrong proportions of dewarped images #5

noobie-iv opened this issue Jan 3, 2025 · 252 comments
Labels
enhancement New feature or request process Solution at work

Comments

@noobie-iv
Copy link
Member

Sample images:

Dewarp-1
Dewarp-2

Results:

The width should increase when unfold curved image, but it doesn’t:

01

The width should not decrease when unfold flat image, but it does:

02

@zvezdochiot
Copy link
Member

zvezdochiot commented Jan 3, 2025

Hi @noobie-iv .

В STEX эта проблема по большей части решается режимом "Уместить" (Affine) в "Макетировании страницы". Но здесь такого нет, так что решать надо как то "на месте". Хоть корректировку пропорции ручную вводить:

float delta = 0.0f; /* params */
float scale_X = 1.0f + delta;
float scale_Y = 1.0f / scale_X;

@noobie-iv
Copy link
Member Author

@zvezdochiot

Ручную корректировку же после прикручивать надо, потому что сразу ее не видно. А это как раз новая стадия нужна.

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

Например, вот квадрат, вид наискосок:

Перспектива

01

Развертка

02

"Какие тут уши, тут бы пальцы не обжечь (с)"

@zvezdochiot
Copy link
Member

zvezdochiot commented Jan 3, 2025

@noobie-iv , сразу (рефлекторно) возникает мысль о необходимости новый репы: scantailor-testing. И вот туда всё это "добро" плодить и "чудить": dataset0001, dataset0002, ... А в дальнейшем уже ссылаться на них.

Но сама идея верная.

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

p1,p2,p3,p4 - четыре угла
count = count(p1,p2,p3,p4) = 4
mx = (p1.x + p2.x + p3.x + p4.x) / count
my = (p1.y + p2.y + p3.y + p4.y) / count
sx = sqrt(sum((p{1,2,3,4}.x - mx)^2) / count)
sy = sqrt(sum((p{1,2,3,4}.y - my)^2) / count)

wn = 2 * sx
hn = 2 * sy

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

PS: Твоя модель понятна и во всех смыслах интересна. Но! Явно теряется общий масштаб. Это будет проблемой? Ещё как. Здесь тоже надо покумекать. Равенство площадей?

@noobie-iv
Copy link
Member Author

Вот набор тестов под перспективу:
PerspectiveTestSet.zip
(STEX тоже лажает)

Sample

@zvezdochiot
Copy link
Member

@noobie-iv say:

Вот набор тестов под перспективу:

В STEX автомат только на 4х из 13 сработал (причём на одной криво). И да. Пропорции не особо алё.

@noobie-iv
Copy link
Member Author

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

@zvezdochiot
Copy link
Member

zvezdochiot commented Jan 3, 2025

@noobie-iv say:

А результаты выходят один другого хуже.

Вы будете смеяться с моей истории, но в STU автомат сработал на 8ми из 13. Сделал всё ровно, но пропорции никакущие. В STA тестить не хочу - он частенько падает на этом.

PS: Искривления же "на ровном месте" в STEX связаны уже не с автоматом, а с DistorsionModel. Она генериться из трёх линий: верхней, нижней и "средней", в координатах от 0 до 1. Надо трассировать её в Generatrix или обратной, смотреть что не так.

@zvezdochiot
Copy link
Member

Hi @noobie-iv .

Вставил в Generatrix и обратную код от Tulon-а: STEX: release qt5. Ни шиша. Кривизна та же самая. Откуда? Хз.

@noobie-iv
Copy link
Member Author

Набор тестов под развертку: WarpTestSet.zip

Sample2

@zvezdochiot
Copy link
Member

zvezdochiot commented Jan 3, 2025

@noobie-iv say:

Набор тестов под развертку

С исправленным XSpline там, где сработал автомат:

  • 1-0001 - норм
  • 1-0003 - выпрямил, но буквы слева широкие, справа - узкие, корекция глубины не помогает
  • 1-0005 - норм
  • 1-0008 - верх кривой на пол буквы
  • 1-0011 - верх кривой на пол буквы
  • 2-0001 - выпрямил, но буквы поцентру широкие, по краям - узкие, корекция глубины не помогает
  • 2-0002 - верх, лево и право кривы на пол буквы, слишком широкий
  • 2-0003 - выпрямил, но буквы слева широкие, справа - узкие, корекция глубины не помогает
  • 2-0004 - выпрямил, но буквы слева широкие, справа - узкие, корекция глубины не помогает, уже предыдущего
  • 2-0005 - право криво на пол буквы
  • 2-0008 - кривой на одну букву везде
  • 2-0010 - право криво на пол буквы, узковат
  • 2-0011 - кривой на пол буквы везде

PS: STU выпрямил полностью без кривизы (по краям кое-где чуть-чуть): 1-0001, 1-0003, 1-0004, 1-0005, 1-0008, 1-0010, 1-0011, 2-0001, 2-0003, 2-0004, 2-0008, 2-0010. Но пропорции (не только наружные, но и внутренние) просто ни к чёрту.

@noobie-iv
Copy link
Member Author

И это еще точный цилиндр. А ему еще можно перекос устроить, чтобы 4 вершины из плоскости закрутились.

WarpTestRotatedSet.zip

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

@zvezdochiot
Copy link
Member

zvezdochiot commented Jan 3, 2025

@noobie-iv say:

гладкие кривые разворачиваются во что-то ломано-перекошенное

Да я уже "ручками пошалил" и увидел. Как и сказал ранее - DistortionModel сбоит. Попробую конечно разобраться, но... там же сплошные плюсы! X(

PS: А DataSet хорош! Давно надо было его сделать.

PS2: "По секрету" расскажу: походу GaussBlur() от Tulon-а тоже слегка шальной, но это уже мелочи.

@zvezdochiot
Copy link
Member

zvezdochiot commented Jan 3, 2025

@noobie-iv say:

А ему еще можно перекос устроить, чтобы 4 вершины из плоскости закрутились.

С исправленным XSpline картинка практически идентична STEX. Так что мерж прошёл вполне себе успешно.

@noobie-iv
Copy link
Member Author

@zvezdochiot

Примитивный тест с перспективой.

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

001

В результате вид из обеих камер одинаковый:

002
003

А реальные пропорции разные:

004

При этом равномерная сетка на обоих "листах" в камеру тоже выглядит одинаково, фокус с "восприятием глубины" не прокатит.

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

@zvezdochiot
Copy link
Member

@noobie-iv say:

просто по координатам вершин восстановить пропорции не получится

Просто по координатам углов нет. Но ты забыл про псевдоцилиндр. Ежели в blender рассматривать не лист, а цилиндр, то кое что с этого выжать можно. Да потребуется допущение: ты должен как будто бы знать форму цилиндра (откуда?). Но то, что по одному снимку нельзя восстановить объёмную картину - это известно изначально.

@zvezdochiot
Copy link
Member

zvezdochiot commented Jan 4, 2025

Hi @noobie-iv .

Тестирование бэтки.

Правда не самой бэтки, а current.

Материал для тестирования

set0002 из scantailor-testing

Тестирование

  1. current:

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

На этом тестирование прекратил. Результата нет.

  1. current + исправление XSpline, позаимствованное в STEX:

set0002-20250104-std.pdf

Данный результат отражает все текущие недостатки и недоработки STD.

  1. STEX 1.2024.11.18 (last). Для сравнения:

set0002-20250104-stex.pdf

Без постабработки в GraphicsMagick и GIMP.

@zvezdochiot
Copy link
Member

Hi @noobie-iv .

Первый более-менее вменяемый отклик по тестированию на Руборде.

@noobie-iv
Copy link
Member Author

@zvezdochiot

на Руборде

Я заглядываю туда иногда. Смотрю, уже целое стадо ишаков завести можно, починки с моей скоростью на год наберется. (Кстати, для потерявших на руборде стили под виндами - совет: стили выбираются там же, где и темная тема).

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

Статейка попалась про подбор положения камеры, как раз по двум точкам схода, для перспективы в самый раз будет:
Camera calibration using two or three vanishing points
А если считать, что у цилиндра все углы в плоскость попадают - можно и для него так же камеру выставить, по 4 углам. Плюс дополнительный множитель по ширине за счет кривизны листа. Возможно, на первое время пойдет.

@zvezdochiot
Copy link
Member

zvezdochiot commented Jan 4, 2025

@noobie-iv , про стили в соседний "Bug report" (ха-ха) сказануть не хочешь? 😄

PS: Залью ка сюда: Camera_calibration_using_two_or_three_vanishing_points.pdf

PS2: А что по моему тестированию? Вопросы то должны быть. Али нет?

@noobie-iv
Copy link
Member Author

@zvezdochiot

Со стилями все просто. То, что можно поменять через QSS - я поменял. А текст в эскизах - это элементы типа QGraphicsSimpleTextItem, они в Qt, судя по гуглу, стилями не настраиваются в принципе, потому что не наследники от QWidget. И их цвета тупо захардкожены в ThumbnailSequence.cpp, под светлую тему, потому и на стили не реагируют. Со ссылками на главной странице та же фигня была, их пришлось заменить на кнопки из-за этого, одним из первых коммитов перед применением стилей. И, чтобы "просто починить текст", надо устраивать целую городильню с новым самодельным классом-наследником, ручными свойствами и отловом событий (paint-hover-хз-что-еще), чтобы вовремя менять цвета, типа такого:
https://stackoverflow.com/questions/56441849/qt-get-stylesheet-border-color
Это не слишком сложно, но потом ведь точно обнаружится, что под виндами оно работает те так, как под линуксами. А потом еще и еще. Так что в отложенных лежит.

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

@noobie-iv
Copy link
Member Author

@zvezdochiot

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

Краткий обзор формул:
Из фото в 3D, ч.2: калибровка камеры

Список методов вообще:
Camera Pose Estimation from

@zvezdochiot
Copy link
Member

zvezdochiot commented Jan 4, 2025

@noobie-iv say:

А вот формулы, по которым развертка сейчас считается

Залью сюда же: camera_calibration-habr.com.pdf

PS: Плохо, что формулы в виде изображений, а не SVG.

@noobie-iv
Copy link
Member Author

@zvezdochiot

Конкретно на хабре еще и в формулах опечатки. Оригиналы, судя по виду, из справки по OpenCV притырены.
Camera Calibration and 3D Reconstruction

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

@zvezdochiot
Copy link
Member

zvezdochiot commented Jan 4, 2025

@noobie-iv . Не-не-не! Не лезь в OpenCV!

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

PS: Залью ка сюда: OpenCV-Camera_Calibration_and_3D_Reconstruction.pdf ("распечатка" не очень, но уж как получилось).

@noobie-iv
Copy link
Member Author

@zvezdochiot

Про память был хороший вопрос в багтрекерах какого-то из тейлоров. "Почему при 100G оперативки нужно постоянно ждать перезагрузки одних и тех же файлов?" Могу от себя добавить, что на современных мониторах эскизов на экране помещается больше, чем у ST в кеше (там 40 элементов ограничение стоит), и тот все время по диску шарит. Старенький он уже, мало что помнит 😄

Но CV я, конечно, никуда прикручивать не буду, мне бы то, что взялся, как-нибудь закончить. Просто там, возможно, формулы подсмотреть получится. Либо в исходниках, либо в списке литературы, я не шарил еще.

@zvezdochiot zvezdochiot added the enhancement New feature or request label Jan 4, 2025
@zvezdochiot
Copy link
Member

zvezdochiot commented Jan 5, 2025

@noobie-iv say:

Бага дальше сидит, на стадии развертки

Короче. Есть код:

HomographicTransform<2, double>
CylindricalSurfaceDewarper::fourPoint2DHomography(
boost::array<std::pair<QPointF, QPointF>, 4> const& pairs)
{
Matrix<double, 8, 8> A;
Matrix<double, 8, 1> b;
int i = 0;
typedef std::pair<QPointF, QPointF> Pair;
BOOST_FOREACH(Pair const& pair, pairs)
{
QPointF const from(pair.first);
QPointF const to(pair.second);
A.row(i) << -from.x(), -from.y(), -1, 0, 0, 0, to.x()*from.x(), to.x()*from.y();
b[i] = -to.x();
++i;
A.row(i) << 0, 0, 0, -from.x(), -from.y(), -1, to.y()*from.x(), to.y()*from.y();
b[i] = -to.y();
++i;
}
auto qr = A.colPivHouseholderQr();
if (!qr.isInvertible())
{
throw std::runtime_error("Failed to build 2D homography");
}
Matrix<double, 8, 1> const h(qr.solve(b));
Matrix3d H;
H << h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], 1.0;
return HomographicTransform<2, double>(H);
}

Это не что иное, как нахождение коэффициентов аффинного преобразования четырёхугольника в квадрат. И используется QR-разложение из Eigen. Но матрица 8x8 на треть состоит из нулей. И это не очень хорошо. Да, проверка на валидность вроде есть, но проверка проверке рознь. А прикрутить SVD из того же Eigen на место QR я чего то не смог (не понимаю я эту плюсовую дичь).

То же самое и с кривыми, только там матрица попроще (3x3):

HomographicTransform<1, double>
CylindricalSurfaceDewarper::threePoint1DHomography(
boost::array<std::pair<double, double>, 3> const& pairs)
{
Matrix<double, 3, 3> A;
Matrix<double, 3, 1> b;
int i = 0;
typedef std::pair<double, double> Pair;
BOOST_FOREACH(Pair const& pair, pairs)
{
double const from = pair.first;
double const to = pair.second;
A.row(i) << -from, -1, from * to;
b[i] = -to;
++i;
}
auto qr = A.colPivHouseholderQr();
if (!qr.isInvertible())
{
throw std::runtime_error("Failed to build 2D homography");
}
Matrix<double, 3, 1> const h(qr.solve(b));
Matrix2d H;
H << h[0], h[1], h[2], 1.0;
return HomographicTransform<1, double>(H);
}

Такие вот дела.

@noobie-iv
Copy link
Member Author

@zvezdochiot

Поможет или нет - не знаю, но пусть будет. Это dewarp, вырезанный из STEX в отдельную программу. Все проще, чем из ST запускать. Не проверял, насколько он рабочий. Можно сдать в поликлинику для опытов.

dewarp.tar.gz

@zvezdochiot
Copy link
Member

zvezdochiot commented Jan 5, 2025

Hi @noobie-iv .

Хмм. При трассировке mapGeneratrix() и threePoint1DHomography() через qDebug() на Warp-3-rotated-0008.png нигде аномальных значений не получил. Но!:

Warp-3-rotated-0008-curve
Warp-3-rotated-0008-dewarp

Аномалия явным образом существует. Но возникает она походу не на этапе расчёта HomographicTransform, а на этапе её применения к изображению.

"Чем дальше, тем чуднее и чуднее....". И где теперь искать эту "падлу"?

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

@noobie-iv
Copy link
Member Author

@zvezdochiot

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

dewarp

@noobie-iv
Copy link
Member Author

@zvezdochiot

Никому нельзя верить, даже книжкам из тырнета. Все формулы с гомографиями, видимо, приводят под калибровку, когда размеры образца известны. А в ST гомография вычисляется на условный единичный квадрат. Чтобы привести его к прямоугольнику, надо сначала смасштабировать его. Получаются формулы:

[F    ][R11 R12 R13 Tx][Sx     ][x]
[  F  ][R21 R22 R23 Ty][  Sy   ][y]
[    1][R31 R32 R33 Tz][    Sz ][z]
                       [      1][1]

Гомография тогда записывается:

[h11 h12 h13]   [F·Sx·R11 F·Sy·R12 F·Tx]
[h21 h22 h23] = [F·Sx·R21 F·Sy·R22 F·Ty]
[h31 h32 h33]   [  Sx·R31   Sy·R32   Tz]

И формула для нахождения фокуса (из условия ортогональности R11·R12 + R21·R22 + R31·R32 = 0):

F²·Sx·Sy·R11·R12 =    h11·h12
F²·Sx·Sy·R21·R22 =    h21·h22
F²·Sx·Sy·R31·R32 = F²·h31·h32
---------------------------------------------
Σ F²·Sx·Sy·0 = h11·h12 + h21·h22 + F²·h31·h32

         h11·h12 + h21·h22
F² = (-) -----------------
             h31·h32

Формулы для нахождения размеров листа (из условия единичности векторов R11² + R21² + R31² = 1 и R12² + R22² + R32² = 1):

F²·Sx²R11² =    h11²
F²·Sx²R21² =    h21²
F²·Sx²R31² = F²·h31²
----------------------------------
Σ F²·Sx²·1 = h11² + h21² + F²·h31²

             h11² + h21²
Sx² = h31² + -----------
                 F²

F²·Sy²R12² =    h12²
F²·Sy²R22² =    h22²
F²·Sy²R32² = F²·h32²
----------------------------------
Σ F²·Sy²·1 = h12² + h22² + F²·h32²

             h12² + h22²
Sy² = h32² + -----------
                 F²

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

@zvezdochiot
Copy link
Member

zvezdochiot commented Jan 28, 2025

@noobie-iv say:

при вырождении в линию не находится ни прямая, ни обратная матрицы.

Что указывает на недоопределённость системы. Я бы "боролся" с этим "злоупотреблением" определёнными величинами. А именно: есть исходный четырёхугольник и есть единичный квадрат (он свободен от пропорций и в данном случае это хорошо). Я бы пытался вычленить из этой связки углы, как будто бы в реальности имеется некий квадрат, который мы повернули так, что наблюдается этот самый четырёхугольник. Используя эти самые углы искал бы пересечения линий, направленных "вглубь" от точек кривых до прямой, соединяющей концы кривой. Отношение отрезка от кривой до прямой к длине прямой и брать как глубину в единичном квадрате. Недоопределённость системы в этом случае резко падает.

Не всё учтено в данной схеме и длину линии надо брать не непосредственную, а приведённую (в зависимости от положения на единичном квадрате), но это уже "мелочи".

@noobie-iv say:

Если бы последний коэффициент в гомографии принимать не условную единицу

Уж не прямое ли это "указание" попытаться перейти от F к FOV?

@noobie-iv
Copy link
Member Author

@zvezdochiot

искал бы пересечения линий

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

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

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

Забавно, но в учебниках начерталки для метода архитекторов есть примечание. Бывают точки, которые тяжело получить построением. Для них архитекторы делают исключение: их не строят, а вычисляют. Вот переход в 3D, видимо, и будет таким исключением. Планирую концы образующей выносить на фото из 3D. А уж полученная образующая всегда под хорошим углом пойдет - так же, как линия в плоскости листа в алгоритме сейчас. Возможен, конечно, вариант, что и образующая пройдет сквозь камеру, когда книга в лягушачьей перспективе сфотографирована - если фотограф работал лежа на столе. Придется этот случай в руководстве пользователя оговаривать как недопустимый 😄

Уж не прямое ли это "указание" попытаться перейти от F к FOV?

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

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

@zvezdochiot
Copy link
Member

zvezdochiot commented Jan 28, 2025

@noobie-iv say:

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

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

Только вот на единичном квадрате в принципе искать глубину - доаольно бесполезное занятие. Другое дело наоборот - по гомографии вычленить углы поворотов вокруг 3х осей (как будто такой квадрат реально существует) и уже на исходном четырёхугольнике строить линии от кривых по направлению "оси z" этого квадрата к линии, соединяющей концы кривой.

Я вижу это как то так. Но глубоко не копал.

@noobie-iv
Copy link
Member Author

@zvezdochiot

никаких пересечений сейчас не ищется

Внутри mapGeneratrix образующая выносится на фото, пересекается с трассировками, переносится обратно для уточнения середины. Нет только построения поправки на смещение из плоскости листа. Из-за этого лист обрабатывается почти как плоский. Только образующие чуть сдвигают к краям через Mapper - но это учитывает только разность длин, и не учитывает перспективных искажений. Можно посмотреть set0004 - там видно, что идеально разворачивается сине-белая подложка, которая лежит в плоскости углов. Это потому что строятся нормали по черным стрелкам, а надо по красным:

Image

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

на исходном четырёхугольнике строить линии от кривых по направлению "оси z"

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

@zvezdochiot
Copy link
Member

@noobie-iv say:

На исходном четырехугольнике ось Z будет точкой.

Неверно, это в квадрате она будет точкой. Но после поворота квадрата вокруг 3х осей до совпадения с исходным четырёхугольником это будет совсем уже не точка, а более чем линия, что то вроде стрелок Z на первой части твоего рисунка. При этом не интересует ни верхняя, ни нижняя кривая в отдельности, а интересует самое что ни на есть среднее из двух кривых, потому как "глубина" в псевдоцилиндрической модели относится к столбцу целиком. Такие вот дела. 😄

@noobie-iv
Copy link
Member Author

@zvezdochiot

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

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

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

самое что ни на есть среднее из двух кривых

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

Для начала меня устроит Mapper с сохраненными fx. Потом поправлю его под красные стрелки по лучшему из двух сечений - тогда вертикальный масштаб будет снят с фото, а не назначен как попало через DepthPerseption (да еще с грубой обрезкой под +-0.5, как сейчас).

@zvezdochiot
Copy link
Member

@noobie-iv say:

как попало через DepthPerseption (да еще с грубой обрезкой под +-0.5, как сейчас).

Так там значения сейчас в пределах до 0.1 (максимум до 0.15). Я трассировал, так что знаю. 😄

@noobie-iv
Copy link
Member Author

@zvezdochiot

Так там значения сейчас в пределах до 0.1

CylindricalSurfaceDewarper::initArcLengthMapper(...)
{
...
    double elevation = m_depthPerception * (1.0 - (y2 - y1));
    elevation = qBound(-0.5, elevation, 0.5);
...
}

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

@noobie-iv
Copy link
Member Author

@zvezdochiot

И еще про фокус. В формуле квадрат фокуса может стать отрицательным. Например, если нарисовать четырехугольник как попало. Или обрезать фото до обработки. Вот размеры Sx, Sy стабильны - там строго сумма квадратов. Даже ноль не получится, потому что суммируются проекции единичного вектора. А фокус придется вписывать в допуск MIN-MAX.

Важно: фокус портится и в случае, когда координаты на фото отсчитываются не от центра, а от края. Вот на тех гомографиях, что вычисляются сейчас, фокус легко улетает в минус. Но model должна вернуть пользователям гомографию "от угла", а внутри пусть считает как хочет. Пользователи - это dewarper, thumnail, imageview, и никому не интересно добавлять-вычитать центры туда-сюда на каждый пиксель.

Так что понадобятся переходы центр-угол. Если есть исходная гомография:

[h11 h12 h14]
[h21 h22 h24]
[h31 h32 h34]

то координаты по ней вычисляются так:

    h11·x + h12·y + h14
x = -------------------
    h31·x + h32·y + h34

    h21·x + h22·y + h24
y = -------------------
    h31·x + h32·y + h34

А если я добавляю к координате x на фото смещение Δx, то получится:

         h11·x + h12·y + h14
x + Δx = ------------------- + Δx
         h31·x + h32·y + h34

         h11·x + h12·y + h14 + (h31·x + h32·y + h34)·Δx
x + Δx = ---------------------------------------------- 
                      h31·x + h32·y + h34

         (h11 + h31·Δx)·x + (h12 + h32·Δx)·y + (h14 + h34·Δx)
x + Δx = ----------------------------------------------------
                      h31·x + h32·y + h34

Аналогично для y:

         (h21 + h31·Δy)·x + (h22 + h32·Δy)·y + (h24 + h34·Δy)
y + Δy = ----------------------------------------------------
                      h31·x + h32·y + h34

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

[h11 + h31·Δx    h12 + h32·Δx     h14 + h34·Δx]
[h21 + h31·Δy    h22 + h32·Δy     h24 + h34·Δy]
[      h31             h32              h34   ]

Аналогично, для полной матрицы преобразований перенос начала координат по фото делается так:

[h11 + h31·Δx    h12 + h32·Δx     h13 + h33·Δx    h14 + h34·Δx]
[h21 + h31·Δy    h22 + h32·Δy     h23 + h33·Δy    h24 + h34·Δy]
[      h31             h32              h33             h34   ]

@zvezdochiot
Copy link
Member

zvezdochiot commented Jan 28, 2025

@noobie-iv say:

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

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

Наименее плохое определение: фокус в квадрате - это оношение площади линзы к её кривизне. Только так. Все остальные "упрощения" и взятие корней - это уже математика, а не физика.

@noobie-iv
Copy link
Member Author

@zvezdochiot

Итого идея такая:

  1. У меня есть гомография pln2img, посчитанная по 4 точкам от угла
  2. Я перевожу ее в центральную pln2img_centered, приняв Δx = -image.width/2, Δy = -image.height/2, по формулам переноса.
  3. По центральной гомографии нахожу F, Sx, Sy.
  4. Масштаб по z, видимо, надо принимать равным x: Sz=Sx, тогда сечение будет равных масштабов в длину и по высоте.
  5. Восстанавливаю столбцы R1 и R2 в матрице поворота, поделив на F,Sx,Sy, нахожу третий столбец векторным произведением и домножением на F и Sz.
  6. Добавляю третий столбец в гомографию, и получаю полную матрицу преобразования mdl2img_centered.
  7. Перевожу матрицу из центральных координат в угловые с обратными смещениями - получаю окончательно mdl2img.
  8. mdl2img будет сохранена рядом с pln2img.

Это общая идея. Надо еще просчитать тестовый пример. Сдается, там половину действий сократить можно.

На выходе у меня есть 3D-модель листа (Sx, Sy, Sz - его размеры, arcLengthMapper хранит профиль сечения). Размеры получены исходя из условной единицы в гомографии. Т.е. таким был бы лист на фото, если бы находился на расстоянии 1 от камеры. А mdl2img позволяет любую точку с модели спроецировать на фото.

Так что mapGeneratrix:

  • Запрашивает высоту у arcLengthMapper, и переносит точки (x,0,h), (x,0.5,h), (x,1,h) на фото с помощью новой mdl2img.
    В идеальном мире края попали бы на трассировку, но в реале будут отклонения, поэтому:
  • По перенесенным точкам ищет пересечения с трассировками.
  • Вычисляет линейную гомографию "образующая на фото -> образующая в квадрате" по 3 точкам.
  • По линейной гомографии возвращает пересечения на квадрат
  • Исправляет положение середины пропорционально смещениям концов на квадрате
  • Возвращает исправленную середину в (x, y_c, h) в 3D через mdl2img
  • Строит окончательную гомографию по точкам (x,0), (x,y_c), (x,1) - (пересечение1),(исправленная_середина),(пересечение_2)

Ибо изначально фокус - нефизический

Он найден из уравнения "Оси x,y на фото перепендикулярны в модели". Если минус - значит, "такой проекции не может быть физически". В реале - обрезанное фото, или линзовые искажения, или еще что - надо тестить. При отрицательном фокусе отрицательные размеры вылезут, кривые нормали и т.п. Расчет пойдет вразнос. Так что либо коррекция, либо вылет.

@zvezdochiot
Copy link
Member

@noobie-iv say:

Восстанавливаю столбцы R1 и R2 в матрице поворота, поделив на F,Sx,Sy, нахожу третий столбец векторным произведением и домножением на F и Sz.

Вот здесь мне показалось странным: "поделив на F... и домножением на F". А оно точно надо?

@noobie-iv say:

При отрицательном фокусе отрицательные размеры вылезут

Не говори ГОП, ... сначала "прыгни".

@noobie-iv
Copy link
Member Author

@zvezdochiot

"поделив на F... и домножением на F". А оно точно надо

Это все математик, укушенный единицей. Из-за единицы вместо F в гомографии не все элементы умножены на F. А третий орт восстанавлиивается только умножением чистых R. Приходится частично делить и частично умножать, формулы где-то выше.

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

сначала "прыгни".

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

@zvezdochiot
Copy link
Member

zvezdochiot commented Jan 28, 2025

@noobie-iv say:

Это пришелец из 4 измерения?

Нет. Это означает, что кто то из h31·h32 получился (почему то, а почему?) не с тем знаком. Учитывая, что "химия" именно по этой оси, то ничего неожиданного. Вариант - менять знак какой то из них. Какой?

Откуда это исходит? А от туда же: ежели взять z, нормированные не по 1, а по F, то получим:

h11·h12 + h21·h22 + h31·h32 = 0

Такие вот дела. 😄

@noobie-iv
Copy link
Member Author

@zvezdochiot

менять знак какой то из них

Нельзя поменять знак одной из них. Они все - элементы матрицы поворота. У нее 9 значений, но только 3 независимых. Остальные связаны единичностью и взаимной ортогональностью. Обязательно нужно получить 3 единичных взаимно ортогональных вектора на выходе. F, Sx, Sy из этих дополнительных условий и выведены. Стоит поменять что-то одно - сломается что-то другое.

Вот h11·h12 + h21·h22 + h31·h32 = 0 - это условие ортогональности осей X,Y. И если его удается выполнить только с отрицательными квадратами - значит, значения вычислены не через "масштаб-поворот-смещение-проекция", а каким-то другим способом, который игнорировал дополнительные ограничения. Навскидку - искажения или обрезание. Может, бывает еще что-то.

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

Image

А как выдумал контур из головы - сразу минусы и огреб.

@zvezdochiot
Copy link
Member

zvezdochiot commented Jan 28, 2025

@noobie-iv say:

Вот h11·h12 + h21·h22 + h31·h32 = 0 - это условие ортогональности осей X,Y.

Верно. И добавление сюда нормировочного коэффициента F^2 это условие никак не меняет. А "химия" в алгоритме имеет место быть в z. Более того, как я уже говорил, F^2 - это площадь. Так что минус относится не к ней, а точно к h31·h32. Такие вот дела. 😄

@noobie-iv
Copy link
Member Author

@zvezdochiot

Формулы вроде контачат. Единичный куб восстанавливается по фото, и вставляется обратно.

Image

Во вложении - xlsx, gnumeric должен открывать, если отлаживаться понадобится: H2H3.zip

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

Из приятного - от перемещений гомографий туда-обратно на пол-фото они не меняются. Так что надо всего один новый столбец вычислить. Коэффициенты h, смещенные к центру -> F,Sx,Sy - > столбцы R1,R2 -> столбец R3 -> столбец H3 -> смещение H3 к углу -> вставка в mdl2img, и готово. Делов на одну дополнительную функцию.

@zvezdochiot
Copy link
Member

@noobie-iv say:

gnumeric должен открывать

Да, вполне открывает.

@noobie-iv
Copy link
Member Author

@zvezdochiot

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

PerspectiveTransform
CylindricalSurfaceDewarper::calcMdlToImgTransform(
    HomographicTransform<2, double> const& pln2img,
    QPointF const& img_center)
{
    Matrix<double, 3, 3> const& hmat = pln2img.mat();

    double const& dx = img_center.x();
    double const& dy = img_center.y();

    double const  h00 = hmat(0, 0) - hmat(2, 0) * dx;
    double const  h10 = hmat(1, 0) - hmat(2, 0) * dy;;
    double const& h20 = hmat(2, 0);

    double const  h01 = hmat(0, 1) - hmat(2, 1) * dx;
    double const  h11 = hmat(1, 1) - hmat(2, 1) * dy;;
    double const& h21 = hmat(2, 1);

    double const F_square_min = 1 * 1;
    double const F_square_max = 1000 * 1000;
    double const F_square = qBound( 
        F_square_min,
        - (h00 * h01 + h10 * h11) / (h20 * h21),
        F_square_max
    );
    double const F = std::sqrt(F_square);

    double const Sx_square = h20 * h20 + (h00 * h00 + h10 * h10) / F_square;
    double const Sx = std::sqrt(Sx_square);
    
    double const Sy_square = h21 * h21 + (h01 * h01 + h11 * h11) / F_square;
    double const Sy = std::sqrt(Sy_square);

    double const Sz = Sx;

    double const k = Sz / (Sx * Sy);
    double const h02 = (h10 * h21 - h11 * h20) * k;
    double const h12 = (h01 * h20 - h00 * h21) * k;
    double const h22 = (h00 * h11 - h01 * h10) * k / F_square;

    Matrix<double, 3, 1> const hvec(
        h02 + h22 * dx,
        h12 + h22 * dy,
        h22
    );

    return PerspectiveTransform(hmat, hvec);
}

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

@zvezdochiot
Copy link
Member

zvezdochiot commented Jan 30, 2025

@noobie-iv say:

Как бы тут физику подхимичить?

Ты накладываешь ограничения на квадрат фокуса. Но может стоит накладывать ограничение не на него, а на второй элемент размеров? Что то типа от 0.1 до 10.0 в долях от первого элемента? Да и не стоит ли подвергнуть анализу эти самые элементы (первый и второй) по отдельности на вполне конкретном set0001?

@noobie-iv
Copy link
Member Author

noobie-iv commented Jan 30, 2025

@zvezdochiot

Размеры будут использованы для вычисления пропорций листа, и больше нигде не понадобятся. А вот фокус, так или иначе, попадает в нормаль к листу. И, если он, например, 1e-16, то нормаль оказывается какой-то великоватой. По такой нормали точки с модели будут проецироваться за пределы фото, и вся развертка будет битая. Или наоборот, в точку стянется. И я все не могу въехать, физически тут фокус бывает кривой, или я где в формулах накосячил. Я несколько книжек по машинной графике бегло пролистал, но нигде подробностей не нашел.

@zvezdochiot
Copy link
Member

@noobie-iv say:

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

Ты не уловил смысл, сказанного мной. Попробую разжевать.

Предлагаемое тобой отсечение фоеуса понятно, но и только.

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

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

@noobie-iv
Copy link
Member Author

@zvezdochiot

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

Image

Необходимо править и алгоритм построения сечения. И тут обратно возникает вопрос - как снять сечение с фото, если будут два плохих ракурса.

Бывают "мусорные ветки", которые можно временно залить, чтобы просто показать, а потом стереть?

@zvezdochiot
Copy link
Member

@noobie-iv

Бывают "мусорные ветки", которые можно временно залить, чтобы просто показать, а потом стереть?

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

А ежели нужно показать что то на материале, тогда пользуй scantailor-testing, которрый всегда можно удалить и создать по новой с обнулённой историей. Или вообще новую репу, типа scantailor-wrong. 😄

@noobie-iv
Copy link
Member Author

@zvezdochiot

Ок, тогда вот демка: change_dewarp_model

С дефолтным построителем глючит. Но если я вбиваю фиксированное сечение:

CylindricalSurfaceDewarper::initArcLengthMapper(...)
{
    m_arcLengthMapper.addSample(0.00, 0.00);
    m_arcLengthMapper.addSample(0.25, 0.08);
    m_arcLengthMapper.addSample(0.50, 0.10);
    m_arcLengthMapper.addSample(0.75, 0.08);
    m_arcLengthMapper.addSample(1.00, 0.00);

    m_directrixArcLength = m_arcLengthMapper.totalArcLength();
    m_arcLengthMapper.normalizeRange(1);
}

То в принципе получаю то, что хотел:

Image

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

И где фокус неправильно ловится (одноосевой поворот) - сетка ложится немного мимо. Это, видимо, выносом фокуса в настройки починить можно будет.

@zvezdochiot
Copy link
Member

@noobie-iv say:

Ок, тогда вот демка: change_dewarp_model

Роман, не дели на 2, когда float или double. Умножай на половину (0.5f).

@noobie-iv
Copy link
Member Author

@zvezdochiot

Добавил тестовое чтение профиля с фото: 895d0fd

Image

Image

Базовая идея простая: из модели я выношу на фото единичные габариты профиля (0,0,0)(0,1,0)(0,0,1)(0,1,1), строю обратную гомографию по 4 точкам, и по ней переношу трассировку обратно в габарит - получается сечение с фотографии. На первой картинке единичные габариты отрендерены пунктиром.

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

В этой простой идее есть места для спотыканий:

  1. Сечение может пройти сквозь камеру, и тогда гомография не обращается. Я оцениваю этот случай по проекции левой и правой сторон габарита на нормаль к секущей - img_bound_left_vector.dot(img_directrix_normal_vector). Если проекция не вписалась в допуск, надо чуть повернуть сечение. Видимо, надо добавить еще две точки - (0,1,1)(1,1,1) - это плоскость, проходящая горизонтально через верх габарита, вынести их на фото, построить новую гомографию с листа на плоскость, и перенести пересечения боковых сторон этой плоскости с линией допуска - тогда на плоскости получатся точки, до которых надо повернуть габарит. Выбираю худшую из них dz, и заново выношу на фото (0,dz,1)(1,dz,1). Строю новую обратную гомографию, по которой можно безопасно переносить сечение.
  2. Сечение после переноса может вылететь за габариты вверх/вниз - тогда надо смасштабировать его по вертикали.
  3. Сечение после переноса может вылететь за габариты влево/вправо - тогда надо сделать перекос типа x += kxy, подобрав k по худшей из точек.
  4. Пункты 2,3 можно провернуть с уже перенесенным сечением, или исправить габарит до трапеции, вынести его на фото, и повторно перенести профиль.
    Обработка спотыканий пока не написана, но в целом, видимо, идея рабочая, буду переписывать начисто.

@zvezdochiot
Copy link
Member

zvezdochiot commented Feb 13, 2025

Hi @noobie-iv .

На всякий. Устранение неправильной растеризации:

// Called for points where pixel density reaches the lower or upper threshold.
auto const processCriticalPoint =
[&generatrix, &dst_y_range, model_domain_top, model_domain_height]
(double model_y, bool upper_threshold)
{
if (!generatrix.pln2img.mirrorSide(model_y))
{
double const dst_y = model_domain_top + model_y * model_domain_height;
double const second_deriv = generatrix.pln2img.secondDerivativeAt(model_y);
if (std::signbit(second_deriv) == upper_threshold)
{
if (dst_y > dst_y_range.first)
{
dst_y_range.first = std::min((int)std::ceil(dst_y), dst_y_range.second);
}
}
else
{
if (dst_y < dst_y_range.second)
{
dst_y_range.second = std::max((int)std::floor(dst_y), dst_y_range.first);
}
}
}
};

заменить на:

        // Called for points where pixel density reaches the lower or upper threshold.
        auto const processCriticalPoint =
            [&generatrix, &dst_y_range, model_domain_top, model_domain_height]
            (double model_y, bool upper_threshold)
        {
/*
            if (!generatrix.pln2img.mirrorSide(model_y))
            {
                double const dst_y = model_domain_top + model_y * model_domain_height;
                double const second_deriv = generatrix.pln2img.secondDerivativeAt(model_y);
                if (std::signbit(second_deriv) == upper_threshold)
                {
                    if (dst_y > dst_y_range.first)
                    {
                        dst_y_range.first = std::min((int)std::ceil(dst_y), dst_y_range.second);
                    }
                }
                else
                {
                    if (dst_y < dst_y_range.second)
                    {
                        dst_y_range.second = std::max((int)std::floor(dst_y), dst_y_range.first);
                    }
                }
            }
*/
        };

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

@noobie-iv
Copy link
Member Author

@zvezdochiot

На всякий

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

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

Любимый неисправленный глюк на сегодня - в коммите a40f54c (.2.14: rename from STU to STD). После замены "universal" на "deviant" слетел UI: плавающие панели перестали плавать и прилипли, а стили по умолчанию больше не грузятся - это то, на что в руборде жаловались "стиль win98". У меня даже нет идей, что вообще могло сломаться.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request process Solution at work
Projects
None yet
Development

No branches or pull requests

4 participants