Любительское ракетостроение, как я делаю ракеты и мои ошибки на которых я учусь (part 1)

image

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

Корпус — варианты материала и различные факторы выбора корпуса

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

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

image

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

image

Виды топлива и двигателей

Топливо

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

Состав этого топлива следующий: 70% калиевой селитры, 25% сахарной пудры и 5% древесного угля. Это топливо сильно воспламеняется при малых температурах. Будьте максимально аккуратны.

image

Двигатели

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

image

Пробные запуски и возможная причина неудач

Вот видео первого пробного запуска двигателя от моей ракеты Starship-1

В видео видно что в начале двигателю не хватает тяги и он поднимается только когда заканчивается топливо. Скорее всего проблема недостатка тяги возникла из-за маленького отверстия под сопло. В результате была маленькая струя подачи тяги и двигатель поднялся в воздух только когда заканчивалось топливо. Но проблема скорее всего не только в подаче тяги, но и в массе двигателя. Эта тяга не могла поднять ПВХ трубу ещё и топливо в нагрузку.

Вывод: проблемы с двигателем возникли в результате:

  1. Малой тяги из-за мелкого отверстия под сопло.
  2. Массы топлива и ПВХ трубы.

ссылка на оригинал статьи https://habr.com/ru/post/486462/

SSD для геймеров и хранение данных будущего: Seagate на CES 2020

CES — всегда самая ожидаемая выставка начала года, крупнейшее событие технологического мира. Именно там впервые появляются гаджеты и концепты, которые из будущего сразу шагают в реальный мир и меняют его. У выставок такого масштаба есть только один недостаток: будь то CES, IFA или MWC, информационный поток во время таких мероприятий настолько большой, что может накрыть похлеще «Девятого вала» Айвазовского. Пропустить важный анонс или презентацию можно очень легко, тем более что в России в это время было небольшое постпраздничное похмелье. Поэтому итоги будут подведены ещё не раз. Мы тоже не остались в стороне от CES и сегодня расскажем о новинках SSD.

Устройства, которые показывают на CES, можно смело разделить на две категории:

  • Те, что никогда не увидят свет либо будут интересны очень ограниченному кругу пользователей — всевозможные «умные» унитазы и прочие диковины.
  • Релизы от крупных компаний, которые с большой вероятностью появятся на прилавках в самом обозримом будущем. 

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

SSD для геймеров

Среди новинок — внешние твердотельные накопители FireCuda Gaming SSD и BarraCuda Fast SSD, а также док-станция FireCuda Gaming Dock.FireCuda Gaming SSD, FireCuda Gaming Dock и BarraCuda Fast SSD

В основе FireCuda Gaming SSD лежит база от другого премиального накопителя Seagate — Seagate FireCuda NVMe 510. Устройство может похвастаться наличием технологии SuperSpeed USB 20 Гбит/с (по интерфейсу USB 3.2 Gen 2×2), максимальная поддерживаемая скорость чтения — 2000 МБ/с. 

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

Накопитель появится в продаже уже в марте, будет доступно три версии — на 500 ГБ ($190), 1 ТБ ($260) и 2 ТБ ($500).

Спецификация для FireCuda Gaming SSD 2 ТБ (PDF)

FireCuda Gaming SSD был специально создан для работы с новой док-станцией FireCuda Gaming Dock (у них даже подсветка синхронизируется и может быть кастомизирована геймером для создания эффекта погружения в игровую реальность).

FireCuda Gaming Dock — симбиоз накопителя (4 ТБ) и концентратора, к которому по одному кабелю Thunderbolt 3 можно подключить всю периферию. Но помимо портов (1 × Thunderbolt 3, 1 × DisplayPort 1, 4 × USB 3.1 Gen2, 1 × USB 3.1 Gen2 для зарядки аккумулятора, 1 × RJ-45 и 2 аудиоразъёма) внутри есть слот расширения для скоростных накопителей (M.2 NVMe)

Подробнее про FireCuda Gaming Dock
Спецификация (PDF)

Следующая новинка, BarraCuda Fast SSD — более портативное решение, которое без проблем поместится в карман:

Накопитель оснащен разъёмом USB 3.1 Gen2 Type-C и поддерживает скорость чтения/записи до 540 МБ/с. Использование файловой системы exFAT делает возможной работу накопителя как с Windows, так и с компьютерами Mac (сразу после распаковки). Светодиодная подсветка делает накопитель визуально эффектнее.

Этот SSD создан не столько для геймеров, сколько для активных пользователей, которым важно всегда иметь необходимые файлы под рукой — например, для дизайнеров, геймдевов, фотографов, монтажеров и т.д. Не зря при покупке дают в подарок подписку на Adobe Creative Cloud (план для фотографов). О бэкапах тоже позаботились — резервное копирование осуществляется при помощи утилиты Seagate Toolkit.

BarraCuda Fast SSD имеет ёмкость 500 ГБ, 1 или 2 ТБ, цены — $95, $170 и $300 соответственно.

Спецификация (PDF)

Ещё больше решений для хранения данных

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

Более подробная презентация
image
Шпаргалка: кто есть кто

Кликабельно:

Согласно отчёту IDC, с 2019 по 2025 год объём данных (созданных, записанных и  воспроизведённых) во всём мире вырастет с 41 зеттабайта (ЗБ) до 175 ЗБ. Такой рост данных произойдёт благодаря четвёртой волне промышленной революции (ИТ 4.0) — этому поспособствуют сети домов и городов, заводов и автомобилей с ИИ, СМИ и всевозможные развлечения. 

Подробнее

Среди решений — Lyve Drive, высокоскоростные карты CFexpress (ёмкостью 1 ТБ) и портативный картридер. А также автономное решение для хранения данных Lyve Drive Shuttle, которое позволяет легко и быстро загрузить необходимые файлы с DAS, NAS и других внешних хранилищ. Lyve Drive Shuttle представлен в двух ёмкостях (8 или 16 ТБ), поддерживает как жёсткие диски, так и SSD-накопители. 

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

image

Подробнее о Lyve Drive Shuttle
Спецификация для Lyve Drive Shuttle

Lyve Drive Mobile Array

Ещё одна наша новинка на CES, буквально монстр — высокопроизводительный герметичный массив Lyve Drive Mobile Array. Он состоит из 6 отсеков для накопителей — на выставке мы показали решение с шестью 18-терабайтными (суммарно на 108 ТБ) жёсткими дисками Exos (читайте обзор на Хабре) на основе технологии термомагнитной записи с нагревом носителя HAMR.

Lyve Drive Modular Array

Lyve Drive Modular Array — ещё один высокопроизводительный массив, который отличается возможностью гибкой настройки. Его можно сконфигурировать для конкретного бизнес-процесса, под накопители предусмотрено четыре отсека. В рамках CES была показана версия с жёстким диском корпоративного класса Seagate Exos 2X14 — это первый из всех накопителей, который работает с технологией MACH.2.

Lyve Drive Rackmount Receiver

В качестве вишенки на торте были представлен высокопроизводительный монтируемый в 4U-стойку хаб для приёма данных. Он оснащён двумя массивами Lyve Drive, с помощью которых можно осуществлять перенос файлов прямо в структуру центра обработки данных без использования кабелей. 

Следующий этап эволюции данных

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

Один из трендов сейчас — автономные транспортные средства — мало кто знает, но и здесь наша компания приняла участие: вместе с партнёром Renovo мы работаем над самоуправляемыми автомобилями. На CES 2020 было продемонстрировано комплексное решение из средств управления данными, программного обеспечения и систем автомобильной безопасности, которое позволяет формировать целые автомобильные парки из беспилотных автомобилей.

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

Научно-исследовательский институт Монтерей-Бэй (MBARI) занимается глубоководными исследованиями и соответственно накапливает огромный объём данных, которые необходимо надёжно хранить и обрабатывать. Новейшие решения Seagate призваны решить проблему и обеспечить исследовательские группы быстрым и эффективным сбором данных, а также их переносом в вычислительные центры.

Также без решений Seagate не обойдутся производства нового уровня — заводы, на которых большинство процессов завязано на интернете вещей, поэтому поток данных с датчиков оказывается колоссальным. Это не что иное как четвёртая волна промышленной революции в ИТ, где подключено будет всё: дома, города, производственные предприятия, транспортные средства и т.д. И весь этот объём данных (до 175 зеттабайт к 2025 году!) тоже нужно будет организовывать и хранить. Мы готовы к этим вызовам!

Ну и куда же сейчас без 5G — в этом направлении работают не только производители смартфонов и комплектующих для них. На CES 2020 наша компания представила микромодульный периферийный дата-центр от компании Vapor IO — с его помощью можно размещать данные ближе к конечным точкам, что повышает эффективность обработки информации.

Немного развлечений

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

Для кого-то CES — это показ ИТ-моды haute couture, те устройства и гаджеты, которые хороши и привлекательны, но созданы исключительно как концепты и вряд ли будут жить. Для нас CES — это настоящий прет-а-порте, все экземпляры можно брать прямо со стендов компании и использовать в компании, для гейминга, в крутом НИИ и т.д. Потому что мы создаём будущее для реальной жизни в настоящем и рады каждый год представлять что-то революционное. И, заметьте, это только начало года.

ссылка на оригинал статьи https://habr.com/ru/company/seagate/blog/486108/

Получены самые детальные снимки поверхности Солнца

Только что выпущенные первые снимки с солнечного телескопа Даниэля К. Иноуйе от Национального научного фонда (NSF) раскрывают беспрецедентные детали поверхности Солнца и демонстрируют потрясающий результат, полученный этим выдающимся 4-метровым солнечным телескопом. Солнечный телескоп Иноуйе (DKIST) на вершине вулкана Халеакала, на гавайском острове Мауи, откроет новую эру солнечной науки и сделает шаг вперед в понимании Солнца и его влияния на нашу планету.

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

Активность на Солнце, известная как космическая погода, может влиять на всевозможные системы на Земле. Магнитные извержения на Солнце могут повлиять на воздушные судна, нарушить спутниковую связь и привести к выходу из строя электрических сетей, вызывая длительные отключения электроэнергии и отключая такие технологии, как GPS.

Первые снимки с солнечного телескопа Иноуйе показывают крупный план поверхности Солнца, что может предоставить важные детали для ученых. Изображения показывают картину турбулентной «кипящей» плазмы, которая покрывает всё Солнце. Клетчатые структуры — каждая размером с Техас — являются признаком интенсивных движений, которые переносят тепло изнутри Солнца на его поверхность. Эта горячая солнечная плазма поднимается в ярких центрах «ячеек», охлаждается, а затем погружается под поверхность в темных полосах в процессе, известном как конвекция.

Можно разглядеть крошечные детали, размером с остров Манхэттен
Можно разглядеть крошечные детали, размером с остров Манхэттен

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

Расширение знаний

Солнце — наша ближайшая звезда — гигантский ядерный реактор, который сжигает около 5 миллионов тонн водородного топлива каждую секунду. Оно делало это около 5 миллиардов лет и будет продолжать еще 4,5 миллиарда лет. Вся эта энергия излучается в космос во всех направлениях, и крошечная часть, которая поражает Землю, делает возможной жизнь. В 1950-х годах ученые выяснили, что солнечный ветер дует от солнца к краям солнечной системы. Они также впервые пришли к выводу, что мы живем в атмосфере этой звезды. Но многие из наиболее важных процессов на Солнце продолжают сбивать ученых с толку.

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

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

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

— Все дело в магнитном поле, — сказал Томас Риммеле, директор солнечного телескопа Иноуйе, — Чтобы разгадать самые большие загадки Солнца, мы должны не только четко видеть эти крошечные структуры на расстоянии 93 миллионов миль (почти 150 миллионов километров), но и очень точно измерять напряженность их магнитного поля, направление вблизи поверхности и отслеживать поле, которое распространяется на корону — внешнюю атмосферу Солнца.

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

Инженерия

Для достижения полученных результатов этот телескоп потребовал много новых важных подходов к его конструкции и конструированию. Построенный Национальной солнечной обсерваторией и управляемый Ассоциацией университетов для исследований в области астрономии (AURA), солнечный телескоп Иноуйе сочетает в себе 13-футовое (4-метровое) зеркало — самое большое в мире для солнечного телескопа — с беспрецедентными условиями просмотра на саммите в Халеакала, на высоте 10 000 футов (более 3 000 метров).

Обсерватория Халеакала — Экрем Канли
Обсерватория ХалеакалаЭкрем Канли

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

Солнечный телескоп Даниэля К. Иноуйе
Солнечный телескоп Даниэля К. Иноуйе

Купол, охватывающий телескоп, покрыт тонкими охлаждающими пластинами, которые стабилизируют температуру вокруг телескопа, чему способствуют жалюзи внутри купола, которые обеспечивают тень и циркуляцию воздуха. «Тепловая остановка» (высокотехнологичный металл с водяным охлаждением в форме пончика) блокирует бóльшую часть солнечной энергии от главного зеркала, что позволяет ученым изучать определенные области солнца с беспрецедентной ясностью.

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

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

Новая эра солнечной астрономии

Новый наземный солнечный телескоп Иноуйе будет работать с космическими инструментами солнечного наблюдения, такими как Solar Probe (Паркер) — НАСА (в настоящее время находится на орбите вокруг Солнца) и Solar Orbiter (SolO) — ЕКА / НАСА (скоро будет запущен). Три инициативы по наблюдению за солнечной энергией расширят границы исследований солнечной энергии и улучшат способность ученых прогнозировать космическую погоду.

— Это захватывающее время для физика солнечной энергетики, — сказал Валентин Пиллет, директор Национальной солнечной обсерватории NSF, — Солнечный телескоп Иноуйе обеспечит дистанционное зондирование внешних слоев Солнца и магнитных процессов, которые в них происходят. Эти процессы распространяются в солнечную систему, где миссии Solar Probe и Solar Orbiter будут измерять их последствия. В целом, они представляют собой поистине многопоточное предприятие для того, чтобы понять, как звезды и их планеты магнитно связаны.

— Эти первые снимки — это только начало, — сказал Дэвид Бобольц, директор программы в Отделе астрономических наук NSF, который наблюдает за строительством и эксплуатацией объекта, — В течение следующих шести месяцев команда ученых, инженеров и техников телескопа Иноуйе продолжит его испытания и ввод в эксплуатацию, чтобы подготовить телескоп к использованию международным научным сообществом по солнечной энергии. Солнечный телескоп Иноуйе будет собирать больше информации о нашем Солнце в течение первых 5 лет его существования, чем все солнечные данные, собранные с тех пор, как Галилей впервые направил свой телескоп на Солнце в 1612 году.

Активность на Солнце
На этом снимке, снятом с длиной волны 789 нанометров (нм), мы впервые видим объекты размером всего 30 км (18 миль). Изображение показывает образец турбулентного, «кипящего» газа, который покрывает все солнце. Клетчатые структуры — каждая размером с Техас — являются признаком интенсивных движений, которые переносят тепло изнутри Солнца на его поверхность. Горячий солнечный материал (плазма) поднимается в ярких центрах «ячеек», охлаждается и затем опускается под поверхность в темных полосах в процессе, известном как конвекция. В этих темных полосах мы также видим крошечные, яркие маркеры магнитных полей. Считается, что эти яркие пятнышки никогда прежде не видели такой ясности, чтобы направлять энергию во внешние слои солнечной атмосферы, называемые короной. Эти яркие пятна могут быть причиной того, почему температура солнечной короны составляет более миллиона градусов.

ссылка на оригинал статьи https://habr.com/ru/post/486472/

Робокары Waymo (Google) начинают развозить посылки в Фениксе, США

Компания Waymo продолжает развивать свои робокары. Определенный прогресс есть, несмотря на все сложности. Так, сейчас роботизированные автомобили этой компании будут доставлять посылки для UPS в Фениксе, США.

Изначальный маршрут будет не слишком длинным — автомобили Chrysler Pacifica с автоматической системой управления станут перевозить посылки внутри системы UPS, не доставляя их получателям. При этом на первом этапе работы в машинах будут находиться операторы, которые готовы перехватить управление, если что-то пойдет не так.

Скорее всего, до конечного потребителя робокары не будут добираться и через время — ведь довезти груз мало, нужно еще доставить его до двери. А здесь уже робот-автомобиль не справится.

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

Робомобили Waymo будут действовать иначе. В пункте А в них загрузят посылки, машина довезет их до пункта Б, где будет произведена разгрузка. Если все пройдет хорошо, Waymo и UPS станут сотрудничать и по другим направлениям грузоперевозок.

Waymo сейчас тестирует способы практического использования своих транспортных средств. В течение двух лет компания проверяет в работе полуавтоматические грузовики. Они катаются по дорогам Феникса и близлежащих регионов. С Waymo в качестве перевозчика грузов сотрудничают Walmart, AutoNation и Valley Metro.

А вот с сервисом такси Waymo One у компании проблемы. Его не получается масштабирвать. Изначально планировалось, что полностью автоматизированные такси начнут работу уже в конце 2018 года. Но дедлайн был нарушен, сервис запустили в бета-режиме, причем с оператором на водительском сидении. Да и доступны такие такси далеко не для всех, а лишь для ограниченного количества бета-тестеров.

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

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

Что хорошо — так это желание Waymo делиться своими наработками. Не так давно компания открыла доступ к своему датасету, который предназначен для обучения алгоритмов беспилотных автомобилей. Он состоит из примерно тысячи двадцатисекундных записей, которые собраны с пяти лидаров и такого же количества камер во время поездок по городам США. Погодные условия при этом самые разные.

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


ссылка на оригинал статьи https://habr.com/ru/company/madrobots/blog/486480/

Реализация поиска печатей на OpenCV без нейронок, регистрации и смс


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

Большинство приемов, описанных здесь, можно применить и вне задачи поиска печатей. Например:

  • цветовая сегментация;
  • поиск круглых объектов / окружностей;
  • конвертация изображения в полярную систему координат;
  • пересечение объектов, Intersection over Union (IoU, Коэффициент Жаккара).

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

Примеры кода будут представлены на Python и C#. Для Python потребуется пакет opencv-python и numpy, для C# — OpenCvSharp и opencv.

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

Забегая вперед скажу, что алгоритм работает только с цветными изображениями (так как основан на HLS-сегментации), а для поиска окружностей используется преобразование Хафа. Изначальное качество прототипа было не очень высоким из-за ложных срабатываний на шуме, оставшемся после сегментации цвета, и ложных срабатываний на рукописном тексте.

Решили фильтровать ложные срабатывания. Использовали несколько подходов – проверку на заполненность области и перевод из полярной системы координат в прямоугольную.

Что, кого и как? Начнем по порядку.

Оценка работы алгоритма

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

Для начала мы набрали документов, разметили, написали скрипт на python для проверки и оценки качества. Наш алгоритм возвращал описывающий прямоугольник для печати (на самом деле, можно было бы использовать и круг, но размечать прямоугольниками проще и быстрее). Далее мы сравнивали эталонные прямоугольники и найденные алгоритмом с помощью коэффициента Жаккара (или же Intersection over Union), насколько точно мы попали при поиске.

Коэффициент Жаккара не выглядит сложным и представляет собой отношение пересечения множеств над их объединением:

Для изображений это выглядит примерно так:

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

Далее подбираем приемлемый для нас порог точности (нас устроил 0.6) и считаем полноту, точность и F1-меру по найденным объектам (в нашем случае — печатям).

Скрипт для оценки с помощью IoU

import sys from collections import namedtuple  Metrics = namedtuple("metrics", ["tp", "fp", "fn"])  def bb_intersection_over_union(a, b):    # Координаты заданы в виде верхнего левого и правого нижнего угла прямоугольника.    # 0 - координата X для верхнего левого угла,    # 1 - координата Y для верхнего левого угла,    # 2 - координата X для правого нижнего угла,    # 3 - координата Y для правого нижнего угла.    x_a = max(a[0], b[0])    y_a = max(a[1], b[1])    x_b = min(a[2], b[2])    y_b = min(a[3], b[3])     # Площадь пересечения.    inter_area = max(0, x_b - x_a + 1) * max(0, y_b - y_a + 1)     # Площади прямоугольников.    a_area = (a[2] - a[0] + 1) * (a[3] - a[1] + 1)    b_area = (b[2] - b[0] + 1) * (b[3] - b[1] + 1)     # Intersection over Union.    iou = inter_area / float(a_area + b_area - inter_area)     return iou  def same_stamp(a, b):    """Проверка, что печати находятся в одном и том же месте"""    iou = bb_intersection_over_union(a, b)    print(f'iou: {iou}')    return iou > 0.6  def compare_stamps(extracted, mapped):    """    Посчитать метрики    :param extracted: Печати, извлеченные алгоритмом.    :param mapped: Размеченные (эталонные) печати.    """    tp = []    fp = []    fn = list(mapped)    for stamp in extracted:        for check in fn:            if same_stamp(stamp, check):                tp.append(check)                fn.remove(check)                break        else:            fp.append(stamp)    return Metrics(len(tp), len(fp), len(fn))  def compare(file, sectors):    """    Посчитать метрики для конкретного файла.    :param file: Путь до файла.    :param sectors: Размеченные печати.    """    print(f'file: {file}')    try:        stamps = extract_stamps(file) # Это метод, который возвращает нам координаты печатей.        metrics = compare_stamps(stamps, [ss for ss in sectors if 'stamp' in ss['tags']])        return file, metrics    except:        print(sys.exc_info())        return file, Metrics(0, 0, 0)  if __name__ == '__main__':    file_metrics = {}     # dataset - словарь, который содержит путь до файлов в паре с координатами заранее размеченных (эталонных) печатей.    for file, sectors in dataset.items():        file_metrics[file] = compare(file, sectors)     # Подсчет точности, полноты и F1-меры.    total_metrics = Metrics(*(sum(x) for x in zip(*file_metrics.values())))    precision = total_metrics.tp / (total_metrics.tp + total_metrics.fp) if total_metrics.tp > 0 else 0    recall = total_metrics.tp / (total_metrics.tp + total_metrics.fn) if total_metrics.tp > 0 else 0    f1 = 2 * precision * recall / (precision + recall) if (precision + recall) > 0 else 0     print('precision\trecall\tf1')    print('{:.4f}\t{:.4f}\t{:.4f}'.format(precision * 100, recall * 100, f1 * 100).replace('.', ','))    print('tp\tfp\tfn')    print('{}\t{}\t{}'.format(total_metrics.tp, total_metrics.fp, total_metrics.fn))     print('tp\tfp\tfn')    for file in dataset.keys():        metric = file_metrics.get(file)        print(f'{metric.tp}\t{metric.fp}\t{metric.fn}')     print(f'precision: {precision}, recall: {recall}, f1: {f1}, {total_metrics}')

HLS-сегментация

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

Разберем же все по кусочкам.

Начнем с HLS палитры. Сама аббревиатура расшифровывается как Hue, Lightness, Saturation, что переводится как тон, светлота, насыщенность. Изобразить данное цветовое пространство можно так:

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

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

Отделение цвета (Python)

def colored_mask(img, threshold = -1):    # Размытие для удаления мелких шумов.    denoised = cv2.medianBlur(img, 3)    cv2.imwrite('denoised.bmp', denoised)     # Сохранение в ЧБ для получения маски.    gray = cv2.cvtColor(denoised, cv2.COLOR_BGR2GRAY)    cv2.imwrite('gray.bmp', gray)     # Получение цветной части изображения.    adaptiveThreshold = threshold if threshold >= 0 else cv2.mean(img)[0]    color = cv2.cvtColor(denoised, cv2.COLOR_BGR2HLS)    mask = cv2.inRange(color, (0, int(adaptiveThreshold / 6), 60), (180, adaptiveThreshold, 255))     # Создание маски цветной части изображения.    dst = cv2.bitwise_and(gray, gray, mask=mask)    cv2.imwrite('colors_mask.bmp', dst)    return dst

Отделение цвета (C#)

private void ColoredMask(Mat src, Mat dst, double threshold = -1) {  using (var gray = new Mat())  using (var color = new Mat())  using (var mask = new Mat())  using (var denoised = new Mat())  {    // Размытие для удаления мелких шумов.    Cv2.MedianBlur(src, denoised, 3);   denoised.Save("colors_denoised.bmp");     // Сохранение в ЧБ для получения маски.    Cv2.CvtColor(denoised, gray, ColorConversionCodes.BGR2GRAY);    gray.Save("colors_gray.bmp");     // Получение цветной части изображения.    var adaptiveThreshold = threshold < 0 ? src.Mean()[0] : threshold;    Cv2.CvtColor(denoised, color, ColorConversionCodes.BGR2HLS);    Cv2.InRange(color, new Scalar(0, adaptiveThreshold / 6, 60), new Scalar(180, adaptiveThreshold, 255), mask);     // Создание маски цветной части изображения.    Cv2.BitwiseAnd(gray, gray, dst, mask);    dst.Save("colors_mask.bmp");  } }

В результате мы получим нечто похожее на это:

Из важных аспектов хочу отметить, что тон для HLS в OpenCV задан значениями не от 0 до 360, а от 0 до 180. Причина банальна — разработчики хотели вместить доступный диапазон в uint8/uchar/byte, которые вмещают значения от 0 до 255, и поэтому поделили 360 на 2.

Поиск окружностей

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

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

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

Поиск окружностей через преобразование Хафа (Python)

# mask - маска, полученная после сегментации; # method: метод поиска окружностей (в OpenCV реализован только Gradient); # dp: разрешение, используемое для детектирования центров кругов (1 — одинаково с исходным изображением, 2 — половина высоты/ширины и т.д. Чем ниже это значение (т.е. выше разрешение), тем больше “голосов” нужно отдать какому-либо объекту, чтобы принять его за круг. Это повышает точность, но плохо “пропечатанные” окружности могут не найтись); # minDist: минимальное расстояние между окружностями (мы брали % от ширины изображения); # param1: верхнее пороговое значение, передаваемое детектору границ Кенни (нижнее пороговое значение будет в 2 раза меньше); # param2: суммирующее пороговое значение детектированя центров; # minRadius: минимальный радиус круга; # maxRadius: максимальный радиус круга; circles = cv2.HoughCircles(mask, cv2.HOUGH_GRADIENT, 1, 20, param1, param2, minRadius, maxRadius)  # Отобразим найденные окружности. circles = np.uint16(np.around(circles)) cimg = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR) for i in circles[0,:]:     cv2.circle(cimg,(i[0],i[1]),i[2],(165,25,165),2)

Поиск окружностей через преобразование Хафа (C#)

// mask - маска, полученная после сегментации; // method: метод поиска окружностей (в OpenCV реализован только Gradient); // dp: разрешение, используемое для детектирования центров кругов (1 — одинаково с исходным изображением, 2 — половина высоты/ширины и т.д. Чем ниже это значение (т.е. выше разрешение), тем больше “голосов” нужно отдать какому-либо объекту, чтобы принять его за круг. Это повышает точность, но плохо “пропечатанные” окружности могут не найтись); // minDist: минимальное расстояние между окружностями (мы брали % от ширины изображения); // param1: верхнее пороговое значение, передаваемое детектору границ Кенни (нижнее пороговое значение будет в 2 раза меньше); // param2: суммирующее пороговое значение детектирования центров; // minRadius: минимальный радиус круга; // maxRadius: максимальный радиус круга; var houghCircles = Cv2.HoughCircles(morphed, HoughMethods.Gradient, 1, max, cannyEdgeThreshold, houghThreshold, min, max);  // Отобразим найденные окружности. foreach (var circle in houghCircles)  Cv2.Circle(morphed, circle.Center, (int)circle.Radius, new Scalar(165, 25, 165), 2);

Пробуем и получаем вот это:

Как видно из результата, не всё так гладко, как хотелось бы. Мы нашли окружность совсем не там, где хотели, а на месте шума. Да, мы могли бы подобрать идеальные коэффициенты для данного документа, где удалился бы весь шум, но остались печати. Ко всему пространству документов такой подход не применим (где-то печати “улетают” с документов из-за слишком больших порогов при отделении цвета, где-то шум принимается за окружность).

Фильтрация

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

Первый заключается в том, чтобы проверить на заполненность ту область, которую мы считаем за круг. Так как шум обычно представлял из себя “небольшое” скопление пикселей, вооружились теорией, что такие ложные участки будут не сильно заполнены. В итоге — вырезаем круг, проверяем.

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

Проверка на заполненность (Python)

def equals(first, second, epsilon):    diff = cv2.subtract(first, second)    nonZero = cv2.countNonZero(diff)    area = first.size * epsilon    return nonZero <= area  for i in circles[0, :]:    empty = np.zeros((256, 256, 1), dtype="uint8")    cv2.circle(empty, (i[0], i[1]), i[2], (255, 255, 255), -1)    crop = img * (empty.astype(img.dtype))     cv2.imwrite('crop.bmp', crop)     if not equals(crop, empty, threshold):        result.append(i)

Проверка на заполненность (C#)

foreach (var circle in circles) {   var x = (int) circle.Center.X;   var y = (int) circle.Center.Y;   var radius = (int) Math.Floor(circle.Radius);    using (var empty = Mat.Zeros(src.Rows, src.Cols, MatType.CV_8UC1))   using (var mask = empty.ToMat())   using (var crop = new Mat())   {     // Вырезание круга (печати) для следующей проверки.     Cv2.Circle(mask, x, y, radius, Scalar.White, -1);     src.CopyTo(crop, mask);      crop.Save("crop.bmp");      // Проверка на заполненность пикселями.     if (!MatEquals(crop, empty, threshold))     result.Add(circle);   } }  private bool MatEquals(Mat a, Mat b, double epsilon = 0.0) {   var notEquals = a.NotEquals(b);   var nonZero = Cv2.CountNonZero(notEquals);   var area = a.Rows * epsilon * a.Cols;   return nonZero <= area; }

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

А что если мы возьмем все имеющиеся контуры на изображении, впишем в них эллипсы и посмотрим насколько эллипс – круг, а точнее – отношение малой (minor) оси к большой (major) (можно было бы сразу вписывать окружности, но тогда был шанс напороться на большой шум, который был бы воспринят как печать).

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

Нехитрым способом (трешхолдами) отсеиваем неблагородные эллипсы, объединяем вложенные друг в друга круги, и voila – выкидываем кучу ложных срабатываний.

Фиолетовые круги – преобразование Хафа, зеленый – эллипс с внутренним кругом, синий – эллипс без внутренних кругов, голубой – новый контур, который получился после объединения с эллипсом.

Поиск кругов по вписанным в контуры эллипсам (Python)

segments = [] contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for contour in contours:    if contour.shape[0] < 5:        continue     ellipse = cv2.fitEllipse(contour)    width = ellipse[1][0]    height = ellipse[1][1]    minor = min(width, height)    major = max(width, height)     if minor / 2 > minorMin and major / 2 < majorMax:        r1 = math.fabs(1 - math.fabs(major - minor) / max(minor, major))        cv2.ellipse(src, ellipse, (255, 0, 0), 3)         if r1 > roundness:            segments.append((ellipse[0], major / 2))            cv2.ellipse(src, ellipse, (0, 255, 0), 3)    else: cv2.ellipse(src, ellipse, (0, 0, 255), 1)  cv2.imwrite('test_res.bmp', src)

Удаление вложенных кругов (Python)

def distance(p1, p2):    return math.sqrt(math.pow(p2[0] - p1[0], 2) + math.pow(p2[1] - p1[1], 2))  def isNested(inner, outer, epsilon):    distance = distance(inner[0], outer[0])    radius = outer[1] * epsilon    return distance < radius and inner[1] < radius - distance  nested = [] for i in inner:    for o in outer:        if (isNested(i, o, 1.3)):            if (distance(i[0], i[1]) < 30 and i[1] / o[1] > 0.75):                nested.append(i)            else: nested.append(o)

Поиск кругов по вписанным в контуры эллипсам (C#)

Cv2.FindContours(src, out var contours, hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple);   foreach (var contour in contours)   {     // Эллипс можно построить минимум по 5 точкам.     if (contour.Height < 5)     continue;      var ellipse = Cv2.FitEllipse(contour);     var minor = Math.Min(ellipse.Size.Width, ellipse.Size.Height);     var major = Math.Max(ellipse.Size.Width, ellipse.Size.Height);      if (minor / 2 > minorSize && major / 2 < majorSize)     {     // Отношение малой оси к большой. Чем больше значение, тем больше эллипс похож на круг.     var r1 = Math.Abs(1 - Math.Abs(major - minor) / Math.Max(minor, major));     if (r1 > roundness)     {         var circle = new CircleSegment(ellipse.Center, major / 2);         segments.Add(circle);     }     }     contour.Dispose();   } }

Удаление вложенных кругов (C#)

private bool IsCirclesNested(CircleSegment inner, CircleSegment outer, double epsilon) {   var distance = inner.Center.DistanceTo(outer.Center);   var secondRadius = outer.Radius * epsilon;   return distance < secondRadius && inner.Radius < secondRadius - distance; }  var nested = new List<CircleSegment>(); foreach (var i in inner) foreach (var o in outer) {   if (IsCirclesNested(i, o, 1.3))   {     if (i.Center.DistanceTo(o.Center) < 30 &&         i.Radius / o.Radius > 0.75)     nested.Add(i);     else nested.Add(o);   } }  return outer.Union(inner).Except(nested).ToList();

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

В данном методе на помощь нам приходит щепотка “математической магии”, а именно перевод из одной системы координат в другую, конкретно в логарифмическую-полярную систему. Я могу понять удивление некоторых “чем это вообще может помочь”? С помощью этого мы “выворачиваем” печать. Но зачем? Это легко позволяет понять, является ли что-то на объекте круглым. Покажу на примере:

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

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

Теперь ближе к реальности — берем наше предположение, полученное после поиска кругов с помощью преобразования Хафа, вырезаем его и переводим в полярную систему координат (выворачиваем наизнанку). Дальше, используя всё то же преобразование Хафа, находим прямые линии (в статьях, которые я приводил выше также описано, что стоит за этим, рекомендую почитать).

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

Перевод в полярную систему координат (Python)

maxRadius = math.sqrt(math.pow(src.shape[0], 2) + math.pow(src.shape[1], 2)) / 2 magnitude = src.shape[0] / math.log(maxRadius) center = (src.shape[0] / 2, src.shape[1] / 2) polar = cv2.logPolar(src, center, magnitude, cv2.INTER_AREA)

Перевод в полярную систему координат (C#)

var maxRadius = Math.Sqrt(Math.Pow(stampImage.Width, 2) + Math.Pow(stampImage.Height, 2)) / 2; var magnitude = stampImage.Width / Math.Log(maxRadius); var center = new Point2f(stampImage.Width / 2, stampImage.Height / 2); Cv2.LogPolar(stampImage, cartesianImage, center, magnitude, InterpolationFlags.Area);

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

Применяем оператор Собеля и находим линии с помощью преобразования Хафа:

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

Контуры и поиск прямых линий (Python)

# Поиск границ. sobel = cv2.Sobel(polar, cv2.CV_16S, 1, 0) kernel = cv2.getStructuringElement(shape=cv2.MORPH_RECT, ksize=(1, 5)) img = cv2.convertScaleAbs(sobel) img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) img = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1] img = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel) img = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)  # Поиск вертикальных линий. def is_vertical(img_src, line):    tolerance = 10    coords = line[0]    angle = math.atan2(coords[3] - coords[1], coords[2] - coords[0]) * 180.0 / math.pi    edge = img_src.shape[0] * 0.66    out_of_bounds = coords[0] < edge and coords[2] < edge    return math.fabs(90 - math.fabs(angle)) <= tolerance and not out_of_bounds  lines = cv2.HoughLinesP(img, 1, math.pi / 180, 15, img.shape[0] / 5, 10) vertical = [line for line in lines if is_vertical(img, line)] correct_lines = len(vertical)

Контуры и поиск прямых линий (C#)

// Поиск границ. using (var sobel = new Mat()) using (var kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(1, 5))) {   Cv2.Sobel(img, sobel, MatType.CV_16S, 1, 0);   Cv2.ConvertScaleAbs(sobel, img);   Cv2.Threshold(img, img, 0, 255, ThresholdTypes.Binary | ThresholdTypes.Otsu);   Cv2.MorphologyEx(img, img, MorphTypes.Open, kernel);   Cv2.MorphologyEx(img, img, MorphTypes.Close, kernel); }  // Поиск вертикальных линий. bool AlmostVerticalLine(LineSegmentPoint line) {   const int tolerance = 10;   var angle = Math.Atan2(line.P2.Y - line.P1.Y, line.P2.X - line.P1.X) * 180.0 / Math.PI;   var edge = edges.Width * 0.66;   var outOfBounds = line.P1.X < edge && line.P2.X < edge;   return Math.Abs(90 - Math.Abs(angle)) <= tolerance && !outOfBounds; } var lines = Cv2.HoughLinesP(img, 1, Math.PI / 180, 15, img.Width / 5, 10); var correctLinesCount = lines.Count(AlmostVerticalLine);

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

  • это работает только на цветных документах (хотя можно попробовать извлекать и без отделения цвета, но результаты намного хуже);
  • размер печати зависит от размера документа (так что если у вас маленькая печать на ватмане — скорее всего она пролетит мимо);
  • рукописка и подписи остаются на документе, бывает, срабатывает на них даже после фильтрации;
  • ну и решение всё равно чувствительно к шумам, особенно к синим.

Итак, возвращаясь к вопросу из начала статьи — “почему не нейроночки?”. Потому что:

  • не нужно большое количество данных;
  • не нужна разметка для получения результата (только для проверки метрик);
  • не нужно обучать нейронку;
  • работает быстрее.

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

ссылка на оригинал статьи https://habr.com/ru/company/directum/blog/486476/