Прочитав свежую статью про обои в разных окружениях, начиная с Microsoft Windows 11 и методах их смены, я заинтересовался — нет ли приложения, которое может выставлять не готовые обои из папки или подкачивать из ресурса, а создавать их периодически, используя любой доступный AI сервис.

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

Я уже писал плагин для Visual Code для проверки правописания и переводов русский-английский, так что OpenAI ключ у меня есть. Будем пробовать DALL-E 3, к которому этот ключ подходит. На Reddit упоминали, что DALL-E умеет создавать бесшовные плиточные изображения, что будет здорово для генерации обоев. Это впоследствии не подтвердилось, как я ни старался. Так что окончательный вариант работает с полным форматом изображения.

Самым простым вариантом мне показалось написать PowerShell скрипт и посадить его на расписание (task scheduler), чтобы он запускался сам каждый день и менял обои.

Отправной точкой является документ, описывающий современный API DALL-E 3.

Вот, собственно, и весь код получения изображения от DALL-E на PowerShell:

$body = @{
    "model"   = "dall-e-3"
    "prompt"  = "$prompt --ar 16:9"
    "size"    = "1792x1024"
    "style"   = "vivid"
} | ConvertTo-Json

$response = Invoke-RestMethod -Uri "https://api.openai.com/v1/images/generations" `
    -Method Post `
    -Headers @{ "Authorization" = "Bearer $apiKey"; "Content-Type" = "application/json" } `
    -Body $body

$imageUrl = $response.data[0].url

В переменную $prompt мы положим наш промпт. О разрешении хотелось бы сказать особо. Максимальное разрешение, поддерживаемое на данный момент DALL-E, есть 1792x1024. Но с ним возникают проблемы — через раз создается квадратное изображение, с полями по бокам. Проблема известная, описана тут. Помогает совет дополнить промпт указанием "--ar 16:9" в конце.

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

$chars = "abcdefghijklmnopqrstuvwxyz0123456789"
$randomString = -Join ((1..8) | ForEach-Object { $chars[(Get-Random -Maximum $chars.Length)] })
$outputFile = "$outputDir\dalle_generated_$randomString.jpg"

Ну, и осталось полученное изображение установить на десктоп:

$code = @"
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SystemParametersInfo(int uAction, int uParam, string lpvParam, int fuWinIni);
"@
$type = Add-Type -MemberDefinition $code -Name "Wallpaper" -Namespace "Win32" -PassThru
$SPI_SETDESKWALLPAPER = 0x0014
$SPIF_UPDATEINIFILE = 0x01
$SPIF_SENDCHANGE = 0x02
$type::SystemParametersInfo($SPI_SETDESKWALLPAPER, 0, $outputFile, $SPIF_UPDATEINIFILE -bor $SPIF_SENDCHANGE)

Я выбрал простой метод API SystemParametersInfo, но он не позволяет произвольно выставить, на какой монитор из имеющихся поставить обои — он ставит на все одновременно. Более сложный метод, который позволяет работать с произвольными мониторами и менять способы отображения обоев, описан у Pete Hinchley. У него создается полная обертка для COM на .NET. Для моих целей простого метода достаточно, не хочу слишком усложнять код.

Мой промпт — вкусовщина. Люблю обои в буквальном смысле, с текстурой бумаги и низким контрастом, чтобы не отвлекало и не мешало разглядеть иконки. "A full-sized wallpaper with flowers and birds and leaves. Muted dark colors, with the texture of rough paper."

Вот так выглядит основной экран:

в процессе написания статьи
в процессе написания статьи

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

Запускаем скрипт в task scheduler (внимание на командную строку):

настройка ежедневного запуска скрипта
настройка ежедневного запуска скрипта

Вот ссылка на гитхаб с исходником скрипта. Нужен только один файл, .ps1

Что в планах: работать со всеми мониторами независимо, используя обертку Windows API от Pete Hinchley (ссылка выше) и назначать на разные мониторы разные изображения автоматически. Еще надо в свободный день развернуть Stable Diffusion и поиграться с ним из PowerShell. Но я с самого начала не рассчитывал на Stable Diffusion — он требует серьезного GPU и много памяти. Предвижу много возни с настройкой, да и не на каждом десктопе или лаптопе найдется подходящая конфигурация. Но было бы интересно попробовать.

Добавлено 2024/10/15

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

крестики - места проверки на наличие полей
крестики - места проверки на наличие полей

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

$image = [System.Drawing.Image]::FromFile($fullName)
$points = @(
    [System.Drawing.Point]::new(3, 3),
    [System.Drawing.Point]::new(3, 257),
    [System.Drawing.Point]::new(3, 512),
    [System.Drawing.Point]::new(3, 766),
    [System.Drawing.Point]::new(3, 1020),
    [System.Drawing.Point]::new(1788, 5),
    [System.Drawing.Point]::new(1788, 257),
    [System.Drawing.Point]::new(1788, 512),
    [System.Drawing.Point]::new(1788, 766),
    [System.Drawing.Point]::new(1788, 1020)
)

$greenValues = $points | ForEach-Object { $image.GetPixel($_.X, $_.Y).G }
$maxDifference = 0
for ($i = 0; $i -lt $greenValues.Length - 1; $i++) {
    for ($j = $i + 1; $j -lt $greenValues.Length; $j++) {
        $difference = [Math]::Abs($greenValues[$i] - $greenValues[$j])
        if ($difference -gt $maxDifference) {
            $maxDifference = $difference
        }
    }
}

return $maxDifference -ge 24

Меня просили создать побольше примеров природы, чтобы оценить качество генерации. Я начал с леса, постепенно усложняя промпт и пытаясь добиться фотореалистичности. Признаюсь — это затягивает!

я старался
я старался

Кто захочет оценить возможности DALL‑E 3 — полсотни лесных пейзажей в разрешении 1792×1024 в репозитарии, в папке «nature». Использованный промпт (с незначительными вариациями) — в самом скрипте.

Удачи в изучении PowerShell и творчестве!

Комментарии (10)


  1. Terranz
    14.10.2024 10:23

    Пожалуйста, не надо называть простую нейронку - искусственным интеллектом


  1. Gremlinquisitor
    14.10.2024 10:23

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


    1. Einherjar
      14.10.2024 10:23

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


      1. Gremlinquisitor
        14.10.2024 10:23

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


        1. Z-StyLe
          14.10.2024 10:23

          Косвенно настроить тематику можно - оценивая фотографии (нравится/не нравится). На рабочем столе для этого по иконке "Learn about this picture" в правом верхнем углу надо кликнуть правой кнопкой мышки, что откроет окно с описанием фото. А в экране входа в систему, достаточно просто навести курсор.


  1. ImagineTables
    14.10.2024 10:23

    Очень интересно. А можно показать примеры? Только не лучшие, а просто первые десять на заданную тему (например, “Nature”). Заранее большое спасибо!


    1. wmlab Автор
      14.10.2024 10:23

      Конечно, можно.

      strange jungle overhead golden hour lighting wide angle field of view infinity vanishing point

      Вот первые несколько, как есть.

      сразу неплохо
      сразу неплохо
      тут поля, несмотря на --ar16:9
      тут поля, несмотря на --ar16:9
      тоже ничего
      тоже ничего
      поля тут тоже есть, но "спрятаны" тенью
      поля тут тоже есть, но "спрятаны" тенью

      По поводу раздражающих полей, которые иногда появляются — ничего, кроме постобработки, в голову не приходит (поставить ImageMagick, кропить новое изображение по сплошному цвету, и если обрезанное изображение меньше, чем исходное — поля есть. Сразу удалять и заказывать новое). Но это нарушает принцип легкости использования. Так что надо смириться и подождать, когда DALL‑E починят. Хороший знак — на эту особенность много жалоб. Как вариант сейчас — делать квадратные обои 1024×1024, и показывать их верхний угол в настройках. Тогда с пропорциями все нормально, но разрешение теряется.


    1. wmlab Автор
      14.10.2024 10:23

      A dense thicket of a mysterious forest, fantastical and diverse trees, bushes, ferns, vines, a fallen tree. Dawn, rays of sunlight breaking through the foliage, view from below, from the ground, wide-angle lens, light mist

      сложнее промпт - больше деталей на обоях
      сложнее промпт - больше деталей на обоях


      1. ImagineTables
        14.10.2024 10:23

        А что насчёт вот такого типичного?

        Если взять 100К фоток, и пропустить их через нейросеть («обучить» на них) для решения проблем с копирайтом, выйдет что-нибудь хорошее в количестве хотя бы 5%? Пока закон это позволяет?


  1. Astus
    14.10.2024 10:23

    Еще надо в свободный день развернуть Stable Diffusion и поиграться с ним

    Тоже задумывался над чем-то подобным, локально на Stable Diffusion, раз в несколько часов/дней тихо в фоне генерить (и сразу ресайзить) обоину с последующим размещением. Дальше обдумывания у меня не зашло, т.к. рабочий стол вижу от силы пару секунд/минут в день, а то и вовсе только после редких перезагрузок.
    Но Ваш вариант с удовольствием бы посмотрел.