Автор Тема: Модифицирование Scan Tailor  (Прочитано 69708 раз)

monday2000

  • Администратор
  • *****
  • Сообщений: 985
    • AOL клиент - -
    • Yahoo клиент - -
    • Просмотр профиля
    • Создание книг в электронном виде из бумажных книг (в формате DjVu)
    • E-mail
Re: Модифицирование Scan Tailor
« Ответ #75 : 18 Мая 2013, 17:10:54 »
Я сделал новый вид Dewarping'а. Я назвал его "краевой деворпинг" (marginal dewarping). Его идея очень проста: используется синяя сетка искривления, точнее, её самая верхняя и самая нижняя горизонтальные синие линии.
 
На каждую из этих синих линий программа ставит дополнительные 4 красные точки (в добавок к 2 уже имеющимся крайним слева и справа). Дополнительные точки ставятся с той стороны страницы, где искривление - самое большое (около корешка книги), т.е. для левой страницы точки ставятся с правой стороны, для правой - с левой.
 
Далее эти красные точки просто программно выставляются на верхнюю и нижнюю изогнутую кромку страницы. Т.е. верхняя горизонтальная синяя линия выставляется (по своим красным точкам) по верхней горизонтальной кромке книги, а нижняя - по нижней.
 
Этот метод деворпинга имеет ограничения: он работает, естественно, только для тех сканов, где есть чётко выраженные верхняя и нижняя изогнутые кромки книг - а фон этих кромок должен быть примерно чёрным.
 
Но очень многие сырые сканы удовлетворяют подобному условию.

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

monday2000

  • Администратор
  • *****
  • Сообщений: 985
    • AOL клиент - -
    • Yahoo клиент - -
    • Просмотр профиля
    • Создание книг в электронном виде из бумажных книг (в формате DjVu)
    • E-mail
Re: Модифицирование Scan Tailor
« Ответ #76 : 18 Мая 2013, 17:12:24 »
Приведу наиболее интересные отрывки из моей переписки с Tulon'ом (автором Scan Tailor) относительно деворпинга:

Можно ли сделать консольную версию СТ-деворпинга?

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

Как перенести в консольную версию синюю сетку?

Цитировать
Сетка переносится без особых проблем. Берется неискженная сетка
и искажается с помощью объекта DewarpingPointMapper. Для его построения нужна DistortionModel - это верхняя и нижняя кривая плюс две линии - левая и 
правая граница контента.

С чего начать перенос в консольную версию?

Цитировать
Советую начать как раз с определения вертикальных границ (DetectVertContentBounds.cpp). Все остальное зависит он него. Потом продвигайтесь в сторону трассировки строк текста (TextLineTracer.cpp, TextLineRefiner.cpp, TopBottomLineTracer.cpp).

Красные точки ведут себя ужасно капризно.

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

Цитировать
Синяя сетка - это всего лишь сэмплинг модели искажения. Захочется больше узлов - просто измените константу.

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

Во многих статьях строки текста аппроксимируются линейно-квадратичным сплайном вида y = ax*x + bx + c.

Цитировать
Это весьма простая модель, которая не справится с сильным изгибом.

У Вас по какой схеме всё работает?

Цитировать
Я не использую квадратичные сплайны. В моей схеме:
1. Делается грубое обнаружение строк. Получаем polyline. О плавности на
этом этапе речь не идет.
2. С помощью сдвоенных змей (coupled snakes) улучшаем наш polyline.
3. Подгоняем (fitting) X-spline произвольной сложности, даже не столько ради
дополнительной плавности (хотя это тоже), сколько для возможности ручной правки.
4. Выбираем пару лучших сплайнов (чем они дальше друг от друга, тем 
лучше), а остальные отбрасываем.

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

http://iupr1.cs.uni-kl.de/~shared/publications/2009-bukhari-cbdar-dewarping-document-image.pdf

Общую модель искажений - отсюда:
http://pdf.aminer.org/000/292/904/a_cylindrical_surface_model_to_rectify_the_bound_document_image.pdf
От себя добавил коррекцию перспективы (homographic transform).

Вы говорили, что сложно определить вертикальную границу текста. А как же линия сопряжения двух соседних страниц книги?

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

Кстати - сплошные чёрные полосы должны очень часто попадать на сырые сканы.

Цитировать
Как я уже сказал выше, я их тоже использую, если TopBottomLineTracer их находит.

Насколько я понимаю, всё, что мне нужно -  это просто программно поработать нужным образом с объектом distortion_model внутри OutputGenerator::processWithDewarping ?

Цитировать
Для начала нужно откуда-то получить параметры модели, а именно две
кривые (просто набор точек - polyline) и параметр depth perception. 
Предполагается, что если соединить первые точки этих двух кривых, получим левую вертикальную границу контента. Если последние точки - тогда правую.

Вопрос только в том - а как с ним работать программно?

Цитировать
Строго говоря DistortionModel вам не обязательно использовать. Он 
существует главным образом для сохранения / загрузки из проекта, а также для проверки равенства моделей. Математика деварпинга находится в классе 
CylindricalSurfaceDewarper, который параметризуется не DistortionModel, а отдельными его элементами.

Или же, может быть, надо не с красными точками работать - а, скажем, напрямую с узлами сетки? Вот я вижу в классе DistortionModel есть свойство Curve m_topCurve - значит, надо, видимо, программно переопределить как-то m_topCurve - чтобы сетка выше задралась?

Цитировать
Curve - это что-то типа union { Spline; Polyline }. Есть Spline - хорошо. Нет Spline - сойдет и Polyline. Опять-же, Curve существует главным образом для сохранения в проект и для проверки одинаковости.

CylindricalSurfaceDewarper принимает не XSpline и не Curve, а просто std::vector<QPointF>.

m_topSpline.spline() возвращает некий класс XSpline - кстати, я так и не 
 понял - а что же такое X-spline?

Цитировать
X-spline достаточно новый сплайн - в 90х его по моему придумали. Используют в основном в видео-редакторах для интерполяции выделения между ключевыми кадрами. Я про него только потому и знаю, что на работе мы как раз пишем видеоредактор.
А вообще он гораздо мощнее B-spline'а по многим параметрам.

Мне с чем работать - с m_xspline или с m_polyline (чтобы двигать красные точки)?

Цитировать
Красные точки - это контрольные точки XSpline, но програмно я бы стал 
работать с Polyline, поскольку там все ясно и предсказуемо. Повторю, что если бы не необходимость визуального редактирования, никаких сплайнов я бы вообще делать не стал. Сплайн все равно в конечном итоге конвертируется 
(сэмплируется) в polyline (то есть в просто набор точек).

А что такое controlPointTension - что значит "Tension"?

Цитировать
А это как раз то, что делает X-Spline мощнее B-Spline. Если tension <= 0,
то кривая будет проходить через данную контрольную точку. То есть красная 
точка будет на синей кривой. Чем ближе tension к -1, тем более сглаженным будет проход.
При tension = 0 проход будет совсем угловатым, как в многоугольнике.
При tension > 0 кривая уже не будет проходить через контрольную точку, но 
будет как бы притягиваться к ней пружиной. Чем ближе tension к единице, тем 
слабее пружина. Те XSpline, которые внутри Curve - у них у крайних точек tension 0, а у остальных 1. Почему не -1? Работать бы работало, но нужно было бы больше контрольных точек для достижения нужного эффекта. Опять же, вам класс Curve не особенно нужен, так что вам никто не мешает заиметь свой XSpline со своими параметрами. А можно и вовсе без него обойтись.

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

Цитировать
Синяя сетка - понятие чисто эфемерное. Есть модель, которая может варпить или деварпить любую точку. Мы ей говорим - вот тебе матрица 30x30 точек в виде неискаженной решетки. Искази каждую из этих точек, а мы это потом нарисуем поверх изображения, соединяя точки (для простоты) прямыми линиями.

Размеры матрицы задаются в файле DewarpingView.cpp:
int const num_vert_grid_lines = 30;
int const num_hor_grid_lines = 30;

Красные точки так просто вверх не поднимешь - а они друг с другом взаимосвязаны формулой сплайна (X-сплайна?)

Цитировать
Не парьтесь со сплайнами - они для людей, а не для программ. Генерируйте простой polyline в виде набора точек.

Так всё-таки с чем именно мне работать - с DistortionModel или с 
 CylindricalSurfaceDewarper?

Цитировать
От CylindricalSurfaceDewarper вы все равно никуда не убежите, а вот
DistortionModel не особенно нужна, если переносить dewarping
в консольную программу.

Я бы рекомендовал сразу выкидывать XSpline из объекта Curve, и впоследствии работать только с polyline. То есть когда закончите строить свою DistortionModel, XSpline'а в ней не будет вообще - только polyline.

Кстати прилично работающий алгоритм для подгонки сплайнов был изобретен только в 2002 году, а мне пришлось серьезно подучить матанализ, чтобы его 
реализовать.
Так или иначе, вы сделали как я советовал - забить на XSpline и работать 
только с polyline.

Так что же это получается - выходит, что красные точки добавляются только на XSpline - а на polyline их не добавишь? Значит, мне недостаточно работы с одной только полилинией - придётся оперировать ещё и х-сплайном?

Цитировать
Только если вас чем-то не устраивает авто-подогнанный сплайн.

Кстати, а как Ваш автоматический деворпинг - добавляет ли он вообще хоть когда-нибудь красные точки? Умеет ли он это делать, и где и как он это делает?

Цитировать
Там происходит ровно то же самое, что и у вас - автоподгонка сплайна.
Количество контрольных точек этого сплайна зашито в код:
int const initial_spline_points = 5;
в DistortionModelBuilder.cpp

Есть ещё старый исходный код Dewarping от Rob с форума diybookscanner.org. Скажите - деворпинг в Скан Тейлоре - это его потомок или нет? Другими словами, есть ли мне смысл переносить Dewarping от Rob в консольное приложение - или сразу деворпинг из Скан Тейлора туда перенести? Какова взаимосвязь между этими 2-мя деворпингами?

Цитировать
Деварпинг от Rob'а больше похож на деварпинг от Leptonica, чем на тот,
что в Scan Tailor'е. И у Rob'а (точно) и в Leptonica (не уверен, но догадываюсь),
если хоть одна линия текста была плохо протрассирована, результат будет паршивым.
В ST есть неплохая вероятность, что эта плохая линия не будет выбрана в качестве одной из двух репрезентативных. Еще у Rob'а гораздо более сложная 
математическая модель сплайна. Если в Leptonica это просто сегмент параболы, то у Rob'а - сложная нелинейная функция, в которой есть и степени, и синус, и чего там только нет.
В результате приходится использовать сложный алгоритм нелинейной 
оптимизации Levenberg-Marquard, который весьма неторопливо работает, и не гарантирует (как и другие алгоритмы) нахождения глобального оптимума.

Кстати, а как Ваш автоматический деворпинг - добавляет ли он вообще хоть когда-нибудь красные точки? Умеет ли он это делать, и где и как он это делает?

Цитировать
Не добавляет. Процедура подгонки сплайна работает так:
Создается сплайн в виде прямой линии, начинающийся и заканчивающийся там же, где и polyline. Количество контрольных точек (тех самых, которые красные)
и соответствующие им значения tension выбираются заранее. Начальное 
положение контрольных точек - равномерно по прямой. Про значения tension я уже писал.
Затем алгоритм подгонки начинает двигать существующие контрольные точки,
чтобы приблизить форму сплайна к форме polyline.

А количество узлов полилинии и количество контрольных точек сплайна (красных точек) обязано совпадать?

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

Что будет, если оставить на сплайне только 2 красные точки - начальную и конечную?

Цитировать
Сплайн с двумя контрольными точками не будет иметь кривизны - это просто отрезок прямой. Насколько я помню - initNewSpline используется только для ручного редактирования результата авто-деварпинга. Авто-деварпинг все равно будет генерировать сплайны с 5 контрольными точками. Число 5 выбрано 
потому, что 4 не хватало при сильном искривлении. А в общем - чем меньше, тем лучше.

Я хотел сконвертировать каждый добавленный мною узел полилинии в красную точку.

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

Каково соотношение между ними? Т.е. между узлами полилинии и красными точками? Обязателен ли порядок следования точек внутри полилинии - или важны лишь координаты? Т.е. если я хочу добавить среднюю точку между концами (как полилинии, так и х-сплайна) - мне надо сделать insert, а просто push_back не подойдёт?

Цитировать
У polyline - чем больше точек, тем лучше (потомучто будет лучше качество деварпинга, но производительность может пострадать), а у spline - чем меньше, тем лучше, потому-что будет проще редактировать вручную. Для polyline push_back подойдет. У XSpline свой API.

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

Цитировать
Алгоритм автоподгонки все сделает за вас (кроме определения оптимального количества красных точек).

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

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

В этом и есть суть моего вопроса - как и где грамотно сформировать distortion_model на основании расставленных красных точек, чтобы скан начал реально деворпиться по моей синей сетке?

Цитировать
DistortionModel - это всего-лишь пара объектов Curve. Объект Curve можно построить из XSpline. Ну а XSpline можно построить путем планомерного 
добавления контрольных точек. Но осторожнее с параметром tension у контрольных точек - при загрузке проекта делается предположение, что у крайних точек tension будет 0, а у остальных 1. Но tension равный 1, это approximating режим, а в этом режиме контрольные точки будут не на сплайне! То есть то, что вы пытаетесь сделать, работать не будет. Вот если 
в Curve::deserializeXSpline() поменять tension с 1 на -1, тогда может и будет, если в других местах нет подобных предположений.

Всё же с полилинией не следует работать, а работать надо всё-таки непосредственно с красными точками - так точней.

Цитировать
Красные точки и не должны быть на линии, при этом сплайн, порожденный ими - будет. Сплайн, контрольные точки которого всегда находятся на самом сплайне называется interpolating spline. У которого не находятся - approximating spline. X-spline может работать в обоих режимах, чего кстати не умеет ни один другой сплайн. Более того, можно часть контрольных
точек сделать interpolating, а другую часть approximating. Контролируется это параметром tension, про который я уже писал. Так вот, СТ конфигурирует две 
крайние контрольные (красные) точки как interpolating, а остальные - как 
approximating. Мог бы я все точки сделать interpolating? Мог, но тогда 5ти 
не хватило бы для сильных искривлений, так что пришлось бы делать 6 или 7.

Думаю, надо теперь как-то попытаться заняться улучшением Вашего автоматического деворпинга. У Вас есть какие-нибудь идеи?

Цитировать
Надо улучшать определение вертикальных границ, при этом не используя рамку 
контента. Это позволит в будущем перенести деварпинг на стадию Deskew. 
Сложных случаев два класса:
1. Мало строк текста или строки не выровнены по правому краю.
2. Строк хватает, но есть контент, вылезающий за логическую вертикальную 
границу.
Тот алгоритм, который сейчас в основной ветке ST, может справиться с 
первым случаем (но правда использует рамку контента для очистки мусора по 
краям). Для второго класса можно использовать преобразование Хафа, но 
такого алгоритма, который работал бы в обоих случаях мне пока придумать не 
удалось.

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

А почему нельзя принять вертикальные границы просто вертикальными?

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

Ваш автоматический деворпинг не замечает малых искривлений концов строки.

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

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

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

Мне нужно изображение с вкладки Dewarping стадии Output - хотя бы внутри Task.

Цитировать
Изображение, которое передается в DewarpingView - это самое что ни на есть оригинальное изображение страницы (или разворота) прочитанное с диска.
Оно передается в Task::process() как часть объекта FilterData.
Уже при отрисовке оно обрубается по краям (в зависимости от режима разреза)
и вращается на нужный угол. DistortionModel однако задан именно в координатах исходного, неповернутого и необрезанного изображения, так что обрезать вам его никакого смысла нет, разве-что повернуть на 90 градусов при 
необходимости, чисто для удобства.
« Последнее редактирование: 30 Мая 2013, 20:04:13 от monday2000 »

monday2000

  • Администратор
  • *****
  • Сообщений: 985
    • AOL клиент - -
    • Yahoo клиент - -
    • Просмотр профиля
    • Создание книг в электронном виде из бумажных книг (в формате DjVu)
    • E-mail
Re: Модифицирование Scan Tailor
« Ответ #77 : 18 Мая 2013, 17:36:39 »
Вот код краевого деворпинга:

OutputGenerator::processWithDewarping(.....
......

//begin of modified by monday2000
//Marginal_Dewarping
}
else if (dewarping_mode == DewarpingMode::MARGINAL)
{
BinaryThreshold bw_threshold(64);
BinaryImage bw_image(input.grayImage(), bw_threshold);

QTransform transform = m_xform.preRotation().transform(bw_image.size());
QTransform inv_transform = transform.inverted();

int degrees = m_xform.preRotation().toDegrees();
bw_image = orthogonalRotation(bw_image, degrees);

setupTrivialDistortionModel(distortion_model);

PageId const& pageId = *p_pageId;

int max_red_points = 5; //the more the curling the more this value

XSpline top_spline;

std::vector<QPointF> const& top_polyline = distortion_model.topCurve().polyline();

QLineF const top_line(transform.map(top_polyline.front()), transform.map(top_polyline.back()));

top_spline.appendControlPoint(top_line.p1(), 0);

if (pageId.subPage() == PageId::SINGLE_PAGE || pageId.subPage() == PageId::LEFT_PAGE)
{
for (int i=29-max_red_points; i<29; i++)
top_spline.appendControlPoint(top_line.pointAt((float)i/29.0), 1);
}
else
{
for (int i=1; i<=max_red_points; i++)
top_spline.appendControlPoint(top_line.pointAt((float)i/29.0), 1);
}

top_spline.appendControlPoint(top_line.p2(), 0);

for (int i=0; i<=top_spline.numSegments(); i++) movePointToTopMargin(bw_image, top_spline, i);

for (int i=0; i<=top_spline.numSegments(); i++)
top_spline.moveControlPoint(i,inv_transform.map(top_spline.controlPointPosition(i)));

distortion_model.setTopCurve(dewarping::Curve(top_spline));

//bottom:

XSpline bottom_spline;

std::vector<QPointF> const& bottom_polyline = distortion_model.bottomCurve().polyline();

QLineF const bottom_line(transform.map(bottom_polyline.front()), transform.map(bottom_polyline.back()));

bottom_spline.appendControlPoint(bottom_line.p1(), 0);

if (pageId.subPage() == PageId::SINGLE_PAGE || pageId.subPage() == PageId::LEFT_PAGE)
{
for (int i=29-max_red_points; i<29; i++)
bottom_spline.appendControlPoint(top_line.pointAt((float)i/29.0), 1);
}
else
{
for (int i=1; i<=max_red_points; i++)
bottom_spline.appendControlPoint(top_line.pointAt((float)i/29.0), 1);
}

bottom_spline.appendControlPoint(bottom_line.p2(), 0);

for (int i=0; i<=bottom_spline.numSegments(); i++) movePointToBottomMargin(bw_image, bottom_spline, i);

for (int i=0; i<=bottom_spline.numSegments(); i++)
bottom_spline.moveControlPoint(i,inv_transform.map(bottom_spline.controlPointPosition(i)));

distortion_model.setBottomCurve(dewarping::Curve(bottom_spline));

if (!distortion_model.isValid()) {
setupTrivialDistortionModel(distortion_model);
}

if (dbg) {
QImage out_image(bw_image.toQImage().convertToFormat(QImage::Format_RGB32));
for (int i=0; i<=top_spline.numSegments(); i++) drawPoint(out_image, top_spline.controlPointPosition(i));
for (int i=0; i<=bottom_spline.numSegments(); i++) drawPoint(out_image, bottom_spline.controlPointPosition(i));
dbg->add(out_image, "marginal dewarping");
}
//end of modified by monday2000
}

//begin of modified by monday2000
//Marginal_Dewarping
void
OutputGenerator::movePointToTopMargin(BinaryImage& bw_image, XSpline& spline, int idx) const //added
{
QPointF pos = spline.controlPointPosition(idx);

for (int j=0; j<pos.y(); j++)
{
if (bw_image.getPixel(pos.x(),j) == WHITE)
{
int count = 0;
int check_num = 16;

for (int jj=j; jj<(j+check_num); jj++)
{
if (bw_image.getPixel(pos.x(),jj) == WHITE)
count++;
}

if (count == check_num)
{
pos.setY(j);

spline.moveControlPoint(idx,pos);

break;
}
}
}
}

void
OutputGenerator::movePointToBottomMargin(BinaryImage& bw_image, XSpline& spline, int idx) const //added
{
QPointF pos = spline.controlPointPosition(idx);

for (int j=bw_image.height()-1; j>pos.y(); j--)
{
if (bw_image.getPixel(pos.x(),j) == WHITE)
{
int count = 0;
int check_num = 16;

for (int jj=j; jj>(j-check_num); jj--)
{
if (bw_image.getPixel(pos.x(),jj) == WHITE)
count++;
}

if (count == check_num)
{
pos.setY(j);

spline.moveControlPoint(idx,pos);

break;
}
}
}
}

void
OutputGenerator::drawPoint(QImage& image, QPointF const& pt) const
{
QPoint pts = pt.toPoint();

for (int i=pts.x()-10;i<pts.x()+10;i++)
{
for (int j=pts.y()-10;j<pts.y()+10;j++)
{

QPoint p1(i,j);

image.setPixel(p1, qRgb(255, 0, 0));

}
}
}
//end of modified by monday2000

yuree

  • Постоялец
  • ***
  • Сообщений: 172
    • Просмотр профиля
    • E-mail
Re: Модифицирование Scan Tailor
« Ответ #78 : 20 Мая 2013, 14:09:01 »
Ещё один глюк, из последней версии. Хотя помню подобное и в ранней было.
Было:


Стало:


Сам файл:
http://rghost.ru/46129191
« Последнее редактирование: 20 Мая 2013, 14:16:08 от yuree »

monday2000

  • Администратор
  • *****
  • Сообщений: 985
    • AOL клиент - -
    • Yahoo клиент - -
    • Просмотр профиля
    • Создание книг в электронном виде из бумажных книг (в формате DjVu)
    • E-mail
Re: Модифицирование Scan Tailor
« Ответ #79 : 20 Мая 2013, 22:43:13 »
yuree
Исправил. Залил на оффсайт:

https://sourceforge.net/projects/scantailor/files/scantailor-devel/featured/

yuree

  • Постоялец
  • ***
  • Сообщений: 172
    • Просмотр профиля
    • E-mail
Re: Модифицирование Scan Tailor
« Ответ #80 : 21 Мая 2013, 01:23:26 »
yuree
Исправил. Залил на оффсайт:

https://sourceforge.net/projects/scantailor/files/scantailor-devel/featured/

Спасибо. Завтра Сегодня днём потестю.
А скажите, кроме меня ещё кто-то фиксы Вам шлёт по СТ? Не-ну просто интересно)

monday2000

  • Администратор
  • *****
  • Сообщений: 985
    • AOL клиент - -
    • Yahoo клиент - -
    • Просмотр профиля
    • Создание книг в электронном виде из бумажных книг (в формате DjVu)
    • E-mail
Re: Модифицирование Scan Tailor
« Ответ #81 : 21 Мая 2013, 08:13:04 »
yuree
Цитировать
А скажите, кроме меня ещё кто-то фиксы Вам шлёт по СТ?
На руборде ещё.

yuree

  • Постоялец
  • ***
  • Сообщений: 172
    • Просмотр профиля
    • E-mail
Re: Модифицирование Scan Tailor
« Ответ #82 : 21 Мая 2013, 15:09:46 »
На руборде ещё.

Я так понимаю Вы не ведёте статистику исправлений. Или ведёте?

monday2000

  • Администратор
  • *****
  • Сообщений: 985
    • AOL клиент - -
    • Yahoo клиент - -
    • Просмотр профиля
    • Создание книг в электронном виде из бумажных книг (в формате DjVu)
    • E-mail
Re: Модифицирование Scan Tailor
« Ответ #83 : 22 Мая 2013, 15:51:16 »
Я обнаружил и исправил баг с неправильной отрисовкой квадро-зон при определённых обстоятельствах. Исправленную версию залил на оффсайт.

yuree
Не веду. А для чего?


yuree

  • Постоялец
  • ***
  • Сообщений: 172
    • Просмотр профиля
    • E-mail
Re: Модифицирование Scan Tailor
« Ответ #84 : 22 Мая 2013, 18:48:54 »
Я обнаружил и исправил баг с неправильной отрисовкой квадро-зон при определённых обстоятельствах. Исправленную версию залил на оффсайт.

Спасибо.

Цитировать
yuree
Не веду.

Понятно.

Цитировать
А для чего?

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

monday2000

  • Администратор
  • *****
  • Сообщений: 985
    • AOL клиент - -
    • Yahoo клиент - -
    • Просмотр профиля
    • Создание книг в электронном виде из бумажных книг (в формате DjVu)
    • E-mail
Re: Модифицирование Scan Tailor
« Ответ #85 : 30 Мая 2013, 20:06:48 »
Продолжение - наиболее интересные отрывки из моей переписки с Tulon'ом (автором Scan Tailor) относительно деворпинга:

Что-то я совсем не пойму - зачем надо вычислять вертикальные границы контента

Цитировать
Этого требует выбранная мной модель искажения.

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

Цитировать
Я имел в виду, что вертикальные границы *изображения* - это не то же самое, что вертикальные границы *контента*. Поэтому нельзя первое использовать там, где ожидается второе.

А если же какая-то строка текста короче предыдущей - то всё равно следует принять её границу так же, как и у верхней.

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

Если же самая верхняя строка - длинная, а самая нижняя - короче её, и причём модель искривления строится по этим 2 строкам - тогда ИМХО надо проинтерполировать линию искривления короткой строки так, чтобы её длина достигла длины линии искривления длинной строки.

Цитировать
Именно так. Сейчас это побочный эффект от подгонки сплайнов.

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

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

После деворпинга результат потребовал Deskew.

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

Выходит, надо добавить полноценное определение deskew - после моего деворпинга? Как бы это сделать покрасивей?

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

57an

  • Постоялец
  • ***
  • Сообщений: 201
    • Просмотр профиля
    • Djvu Bookmarker on SF.net
Re: Модифицирование Scan Tailor
« Ответ #86 : 22 Июня 2013, 09:08:38 »
Поддержу вопрос о логе изменений.

Выкладываются ли изменения STF с помощью системы контроля версий на SF или github, чтобы можно было посмотреть, что и как менялось в более удобном формате, через тот же diff3, чем пробираясь через лес комментариев (которые в таком случае вообще оказались бы ненужными)?

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

И еще по экспорту:
Напрашиваются хотя бы всплывающие подсказки к опциям Разделять смешанный вывод (зачем нужно не разделять, куда - в 1 или 2 - пойдут такие неразделенные файлы) и Папка экспорта по-умолчанию (где именно она располагается по-умолчанию).
Непонятно что будет, если не задать директорию вывода - по-моему напрашивается флажок по аналогии с Faststone Image Viewer -  если директория не задается появляется надпись, что будет использоваться директория (кстати также косяк - в одном окне одни и те же сущности называются по-разному - папка и директория, если что, то я за папки) открытого в настоящий момент проекта.
Ну и нужен флажок переименования файлов папки pic для Djvu Imager (в идеале - и для FSD). Есть огромное количество пользователей, которые не смогут добавить суффикс .sep сами.
Когда процесс экпорта завершен, нужно возвращать состояния окна к изначальному (сбрасывать прогресс-бар и убирать счетчик страниц), иначе кажется, что процесс завис на последней странице. Вместо всплывающего окна о завершении экспорта можно  было использовать стандартную фичу ST - мигание в панели Пуск.

57an

  • Постоялец
  • ***
  • Сообщений: 201
    • Просмотр профиля
    • Djvu Bookmarker on SF.net
Re: Модифицирование Scan Tailor
« Ответ #87 : 22 Июня 2013, 09:20:25 »
Пустые файлы в папке картинок должны создаются независимо от флажка создавать пустые задние субсканы.

Если при запущенном экспорте нажать кнопку закрыть STF падает.

SI{AY

  • Новичок
  • *
  • Сообщений: 6
    • Просмотр профиля
Re: Модифицирование Scan Tailor
« Ответ #88 : 23 Июня 2013, 01:01:38 »
была бы полезной возможность пройтись и отметить где будут иллюстрации до обработки файлов. А то каждый раз ждать...

yuree

  • Постоялец
  • ***
  • Сообщений: 172
    • Просмотр профиля
    • E-mail
Re: Модифицирование Scan Tailor
« Ответ #89 : 23 Июня 2013, 01:12:51 »
была бы полезной возможность пройтись и отметить где будут иллюстрации до обработки файлов. А то каждый раз ждать...

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