1с изменить размер картинки программно

Обновлено: 06.07.2024

Изменение размера изображения с учётом содержимого (Content Aware Image Resize), жидкое растяжение (liquid resizing), ретаргетинг (retargeting) или вырезание шва (seam carving) относятся к методу изменения размера изображения, где можно вставлять или удалять швы, или наименее важные пути, для уменьшения или наращивания изображения. Об этой идее я узнал из ролика на YouTube, от Shai Avidan и Ariel Shamir.

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

Для подопытной картинки, я поискал по запросу 1 "sample image" , и нашел её 2 :

image

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

Самые важные функции в lib.rs могли бы быть такими:

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

Библиотека image от разработчиков “Piston” кажется подойдет, поэтому мы добавим в наш Cargo.toml запись: image = "0.12" . Быстрый поиск в документации это все, что требуется для того, чтобы написать функцию загрузки изображения:

Это элегантно? Нет. Это будет работать? Возможно.

После запуска, Image::gradient_magnitune берёт наше изображение птицы и возвращает это:

image

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

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

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

Давайте найдем S:

И вот оно! Мы видим, что есть путь, с суммой всех ячеек пути равной 8, и то, что этот путь начинается в верхнем правом углу. Для того, чтобы найти путь, мы могли бы запомнить, в какую сторону мы пошли для каждой ячейки (влево, вниз или вправо), но нам это не нужно: мы просто выберем соседа снизу с наименьшим весом, потому что значения веса клеток в таблице S указывают на кратчайший путь от текущей ячейки к самой нижней. Также обратите внимание, что есть два пути, которые в сумме дают 8 (у этих путей различаются две нижние ячейки).

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

После запуска, мы можем преобразовать таблицу DPTable обратно в GradientBuffer , и записать его в файл. Пиксели в изображении ниже — веса пути, разделенные на 128.

image

Эту картинку можно описать так: белые пиксели — это клетки, которые имеют наибольший вес. Градиент этих пикселей более детализирован, что говорит о высокой скорости изменений цвета (и именно эти участки картинки мы хотели бы сохранить).

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

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

Чтобы увидеть, что выбранные пути более-менее правдоподобны, я сгенерировал их
10 штук, и покрасил жёлтым:

image

По-моему, похоже на правду!

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

Наконец настало время. Теперь мы можем удалить строку из изображения, или вызвать в цикле эту функцию и удалить, скажем, 200 строк:

image

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

image

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

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

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

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

Просто немного копипасты!

Теперь, возможно мы хотим окно изменяемого размера. Мы можем быстро накидать новый проект с использованием контейнера sdl2 .

Вот и все. Один день работы, немного знаний по sdl2 , image , и небольшой опыт написания постов в блоге.

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

  1. Почему-то, duckduck-коед не работает, и гугль тоже, если используется глагол.[↑][↑]
  2. Мне интересно, есть ли более простой способ! Кроме того,
    сохранение результата градиента походу нереально, потому-что функция возвращает
    ImageBuffer поверх u16 , в то время как ImageBuffer::save требует, чтобы
    основные данные были в u8 . Я также не мог разобраться, как создать
    DynamicImage (у которого также есть a::save с более понятным интерфейсом)
    от ImageBuffer , ведь это возможно. [↑]

Благодарю все сообщество русскоязычных растаманов ruRust.
Выражаю отдельную благодарность:

Платформа 1С версии 8.х предоставляет слабые возможности по работе с изображением.
Для работы с изображениями можно использовать библиотеку Windows Image Acquisition Automation Library. Библиотеку с описанием можно скачать здесь (в Windows 7 уже входит в состав дистриботива).

Разместил: E_Migachev  Версии: | 8.x | 8.2 УП |  Дата: 18.07.2012   Прочитано: 19656

Распечатать

Похожие FAQ

17 правил для составления оптимального ЗАПРОСа к данным базы 1С  42
Для формирования и выполнения запросов к таблицам базы данных в платформе 1С используется специальный объект языка программирования Запрос . Создается этот объект вызовом конструкции Новый Запрос . Запрос удобно использовать, когда требуется получ 1C и Google Maps  20
была поставлена задача отображения на географической карте медицинских учреждений. После обзора предлагаемых решений был выбран сервис google. Но так же подобного рода подход будет работать и с картами сервиса yandex. Во время решения задачи было реш COM-подключение к базе 7.7 из 8.2 1С  6
Если код выполняется на стороне клиента, то необходимо наличие базы 7.7 на локальной машине. Пример (На форме объекта присутствует реквизит Таблица(ТаблицаЗначений)): НаКлиенте Процедура Загрузки() ПутьКБазе=" D:ВашаБаза1с77" ; Пользователь= Cклонения по падежам  6
НаКлиенте Процедура Команда1(Команда) ФИО = " Иванов Иван Иванович" ; Падеж = 2; Пол = 1; Результат = СклонениеФИО(ФИО, Падеж, пол); Сообщить(Результат); КонецПроцедуры НаСервере Функция СклонениеФИО(ФИО, Падеж, пол) Результат = " " ; Google maps : вывод точек на карту и режим панорамы  7
В отличие от яндекс карт в GMaps можно использовать панорамы - за что им большой плюс! Надеюсь в яндексе прочитают этот пост и тоже когда-нибудь это сделают! Для клиента нужно было сделать вывод объектов на карту С возможностью просмотра панора Посмотреть все результаты поиска похожих

Читайте также: