LINUX.ORG.RU

Про генерацию картинок...

 ,


1

2

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

PS

Про фракталы знаю, но они слишком психоделичны при закраске обычно. Хочется чего-то более монохромного.

PPS

Для поиграться (не все знают Julia, которую очень любит автор алгоритма, и C++ overkill, ИМХО), дам вам кодец на третьем питоне, который прост как доска, написанный на коленке по мотивам ссылки с хабры.

from PIL import Image
import sympy
import random

x = 1600  # разрешение по оси x
y = 900  # разрешение по оси y
background_color = (0, 0, 0, 255)  # цвет фона RGBA
front_color = (109, 167, 65, 255)  # цвет рисунка RGBA
shift_x = random.randint(0, 10000)  # сдвиг по оси x
shift_y = random.randint(0, 10000)  # сдвиг по оси y
im = Image.new('RGBA', (x, y))  # создание "пустой" картинки в RGBA формате
for i in range(0, x):
    for j in range(0, y):
        if sympy.isprime((i + shift_x) ^ (j + shift_y)):
            im.putpixel((i, j), front_color)
        else:
            im.putpixel((i, j), background_color)
im.save(f'img_x{shift_x}_y{shift_y}.png')  # сохранение картинки

PPPS

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

★★★★★

Души нет. Надоест.

dave ★★★★★
()

какие интересные штуки вы знаете для генерации нескучных обоев?

Конформные отображения © со случайными параметрами древнерусских узоров © — математично и духовноскрепно.

quickquest ★★★★★
()
Ответ на: комментарий от quickquest

Интересно, не знал про них. Хотя, нет, знал, но забыл.

peregrine ★★★★★
() автор топика
Последнее исправление: peregrine (всего исправлений: 1)
Ответ на: комментарий от LINUX-ORG-RU

Чёт херня одна :D

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>



enum{R,G,B,A};


void generate_tga(unsigned int width,unsigned int height, char* filename, unsigned char (*r)(int type,int x,int y,int w,int h),
                                                                          unsigned char (*g)(int type,int x,int y,int w,int h),
                                                                          unsigned char (*b)(int type,int x,int y,int w,int h),
                                                                          unsigned char (*a)(int type,int x,int y,int w,int h)) 
{
    char *  i  = malloc(sizeof(char) * ((width*height) * 4));
    //pre
    for(int x = 0; x < width; x++)
    for(int y = 0; y < height; y++)
    {
      i[x * 4 + y * width * 4 + 0] = r(R,x,y,width,height);
      i[x * 4 + y * width * 4 + 1] = g(G,x,y,width,height);
      i[x * 4 + y * width * 4 + 2] = b(B,x,y,width,height);
      i[x * 4 + y * width * 4 + 3] = a(A,x,y,width,height);
    }

  unsigned char xa= width % 256;
  unsigned char xb= (width-xa)/256;
  unsigned char ya= height % 256;
  unsigned char yb= (height-ya)/256;
  unsigned char header[18] = {0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, xa, xb, ya, yb, 32, 0};

  FILE * file = fopen(filename, "wb");
  assert(file);
  fwrite(header,1, sizeof(header), file);

  fwrite(i,1, width * height * 4, file);
  fclose(file);
  free(i);
  
}


unsigned char gen0(int type,int x,int y,int w ,int h)
{
    switch (type) {
        case R:return x+y%255 ;
        case G:return x-y%255 ;
        case B:return x-y%255 ;
        case A:return x+y%255 ;
        default: return 0;
    }
    return 0;
}


unsigned char gen1(int type,int x,int y,int w ,int h)
{

    srandom(x+y);

    switch (type) {
        case R:return (char)(x+y) + (char)(random())  % 255 ;
        case G:return (char)(x-y) + (char)(random())  % 255 ;
        case B:return (char)(x-x) + (char)(random())  % 255 ;
        case A:return (char)(y+y) + (char)(random())  % 255 ;
        default: return 0;
    }
    return 0;
}

unsigned char gen2(int type,int x,int y,int w ,int h)
{

    srandom(x);

    x =x+ random()%w;
    y =y- random()%h;
    // if(xx == x)
    {

    switch (type) {
        case R:return (char)(x+y) + (char)(random()) *x  % 255 ;
        case G:return (char)(y+x) + (char)(random())  % 255 ;
        case B:return (char)(x+x) + (char)(random())  % 255 ;
        case A:return (char)(y+y) + (char)(random())  % 255 ;
        default: return 0;
    }
    }
    return 0;
}


unsigned char gen3(int type,int x,int y,int w ,int h)
{

    srandom(x);

    if(x << y  ){

    switch (type) {
        case R:return x-y & y ;
        case G:return y+x & x ;
        case B:return w-y & x ;
        case A:return h+x & y ;
        default: return 0;
    }
    }
    return 0;
}

unsigned char gen4(int type,int x,int y,int w ,int h)
{
    static int pp = 0;
     int r = 100;
    int px = 100-pp++;
    int py = 100-pp++;


    if((x < px+r && x > px-r) && ( y < py+r && y > py-r) )
    {
        return 255;
    }

    return 0;
}

int main(int argc, char *argv[])
{

    generate_tga(800,600,"img-out0.tga",gen0,gen0,gen0,gen0);

    generate_tga(800,600,"img-out1.tga",gen1,gen1,gen1,gen1);

    generate_tga(800,600,"img-out2.tga",gen2,gen2,gen2,gen2);

    generate_tga(800,600,"img-out3.tga",gen3,gen3,gen3,gen3);



    return 0;
}
LINUX-ORG-RU ★★★★★
()

И ты туда же (ну с @AntonI всё понятно).

Внутренний цикл делай по оси X, а внешний по оси Y

На порядки быстрее будет. Я в тебя верю!

HIS
()
Ответ на: комментарий от LINUX-ORG-RU

Блин же…

Цикл по оси X внутри. Y наружный. Что вы все как дети малые.

HIS
()
Ответ на: комментарий от HIS

С какого перепугу быстрее станет? Во-первых, там x и y строго говоря не должны быть константами, а должны в идеале задаваться пользователями, во-вторых, что так, что эдак ему надо 1440000 пикселя покрасить. А если уж и разгонять, то на numpy массивах, создаваемых с заданным значением фона и переписью пикселей только в нужных местах, а то putpixel медленная функция по факту. Или ты про код на сишке?

peregrine ★★★★★
() автор топика
Последнее исправление: peregrine (всего исправлений: 1)
Ответ на: комментарий от peregrine

объяснить могу в деталях. Я на графике динозавров съел.

Хотя ту дело не в графике, а в понимании организации памяти.

HIS
()
Последнее исправление: HIS (всего исправлений: 1)
Ответ на: комментарий от peregrine

С какого перепугу быстрее станет?

Последовательное чтение всей памяти 1 раз vs прыгание по памяти 800 раз через 600 значений при 800x600

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 1)
Ответ на: комментарий от LINUX-ORG-RU

Такое ощущение что перегрин ещё не отошёл от эффекта :)

Я этим пользуюсь уже лет 25 в своих программах.

HIS
()
Ответ на: комментарий от HIS

В курсе, но если картинко полностью лежит в l1/l2/l3 то разница может быть призрачно малоуловимой. Но если больше разница будет на порядки. Короче чем больше данных тем виднее разницу. А в идеале вообще просто image[i++]=bla() делать и всё =)

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 1)
Ответ на: комментарий от LINUX-ORG-RU

есть нюансы.

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

при обработке один раз всегда на порядки эффективнее.

HIS
()
Последнее исправление: HIS (всего исправлений: 1)
Ответ на: комментарий от LINUX-ORG-RU

Это я так понял ты сказал спасибо :)

А перегрин ушёл в забух от позора наверное, хотя мог бы сказать спасибо :)

HIS
()
Ответ на: комментарий от HIS

Я спал. Чекнул, проверяй, чёт ничего не изменилось у меня по скорости, какие-то доли секунды. А я даже сделал размер 3840x2160, результат в случае изменения цикла и без:

0:00:24.901781
0:00:25.444802
Ух, прямо в разы. Ух оптимизация. В 100 раз размер увеличивать чтобы точно ни в какой кеш не влезло, мне лень, один фиг таких мониторов нету. Ну или я не правильно понял и ты предлагаешь и алгоритм генерации поменять (расположение пикселей), давай сюда правильный цикл. На всякий случай дам тебе код изменённой версии, а то вдруг ты изменять сам результат предлагаешь (по вертикали там картинку развернуть или отзеркалить как-то):
from PIL import Image
import sympy
import random
from datetime import datetime

start_time = datetime.now()
x = 3840  # разрешение по оси x
y = 2160  # разрешение по оси y
background_color = (0, 0, 0, 255)  # цвет фона RGBA
front_color = (109, 167, 65, 255)  # цвет рисунка RGBA
shift_x = random.randint(0, 10000)  # сдвиг по оси x
shift_y = random.randint(0, 10000)  # сдвиг по оси y
im = Image.new('RGBA', (x, y))  # создание "пустой" картинки в RGBA формате
for i in range(0, y):
    for j in range(0, x):
        if sympy.isprime((j + shift_x) ^ (i + shift_y)):
            im.putpixel((j, i), front_color)
        else:
            im.putpixel((j, i), background_color)
im.save(f'img_x{shift_x}_y{shift_y}.png')  # сохранение картинки
print(datetime.now() - start_time)
А всё потому, что putpixel пипец какая медленная функция и то как pillow в недрах хранит картинку я, да и ты не смотрели. И да, у нас Python, а не сишка, как Python памятью управляет вообще не очевидно. Но вдруг я ничего не понимаю и размер надо ещё больше? Кеш моего процессора 6 MB, размер сырого пикселя в RGBA (а тут она используется) 4*8=32 бита. В таком случае, размер картинки, чтобы она не влезла в него должен превышать 50331648 бит, т.е. должно быть не менее 1 572 864 пикселей. Картинка 3840x2160 содержит в себе 8 249 400 пикселей, что явно больше. Может это надо по одной оси, чтобы он строчку кешировать не мог, тогда, извините, время на работу увеличится в 167 770 раз при сохранении пропорций, что составит каких-то жалких 48.5 дней. Ух как много смысла оптимизировать, это же типичный юзкейс алгоритма на поиграться — генерировать картинки по 38 терапикселей (и вообще преждевременные оптимизации — зло)! Где ошибка?

Ну а вот оптимизация с добавлением капельки ума:

from PIL import Image
import sympy
import random
from datetime import datetime
import numpy as np

start_time = datetime.now()
x = 3840  # разрешение по оси x
y = 2160  # разрешение по оси y
background_color = np.array([0, 0, 0, 255], dtype='uint8')  # цвет фона RGBA
front_color = np.array([109, 167, 65, 255], dtype='uint8')  # цвет рисунка RGBA
shift_x = random.randint(0, 10000)  # сдвиг по оси x
shift_y = random.randint(0, 10000)  # сдвиг по оси y
image_pixels = np.tile(background_color, (y, x, 1))
for i in range(0, x):
    for j in range(0, y):
        if sympy.isprime((i + shift_x) ^ (j + shift_y)):
            image_pixels[j, i] = front_color
im = Image.fromarray(image_pixels)
im.save(f'img_x{shift_x}_y{shift_y}.png')  # сохранение картинки
print(datetime.now() - start_time)
Что характерно время стало:
0:00:17.416809
Я не знаю, что у вас там за калькуляторы с магнитной лентой вместо оперативки или перфолентами, чтобы доступ был последовательным, единственное что на ум приходит, так это свап на HDD и оптимизация для него, но моему ноуту уже лет 6, а проц в нём вообще 2013 года выпуска.

peregrine ★★★★★
() автор топика
Последнее исправление: peregrine (всего исправлений: 3)
Ответ на: комментарий от peregrine

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

peregrine ★★★★★
() автор топика
Последнее исправление: peregrine (всего исправлений: 2)
from PIL import Image
import sympy
import math

x = 1600
y = 900
scale = 1e-2
count = 100000
background_color = (0, 0, 0, 255)
front_color = (109, 167, 65, 255)
im = Image.new('RGBA', (x, y), background_color)

for i in range(0, count):
    ix = int(i * math.cos(i) * scale + x / 2)  # Magic.
    iy = int(i * math.sin(i) * scale + y / 2)  # More magic.
    if 0 <= ix and ix < x and 0 <= iy and iy < y and sympy.isprime(i):
        im.putpixel((ix, iy), front_color)

im.save('img.png')
i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

Вот это уже серьёзная артиллерия в ход пошла.

peregrine ★★★★★
() автор топика
Ответ на: комментарий от peregrine

оптимизация

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

--- img.py	2020-05-20 15:54:20.351282954 +0300
+++ img.py	2020-05-20 15:54:05.911254583 +0300
@@ -12,9 +12,10 @@
 shift_x = random.randint(0, 10000)  # сдвиг по оси x
 shift_y = random.randint(0, 10000)  # сдвиг по оси y
 image_pixels = np.tile(background_color, (y, x, 1))
+prime = [sympy.isprime(i) for i in range(0, 2 * max(x + shift_x, y + shift_y) + 1)]
 for i in range(0, x):
     for j in range(0, y):
-        if sympy.isprime((i + shift_x) ^ (j + shift_y)):
+        if prime[(i + shift_x) ^ (j + shift_y)]:
             image_pixels[j, i] = front_color
 im = Image.fromarray(image_pixels)
 im.save(f'img_x{shift_x}_y{shift_y}.png')  # сохранение картинки
i-rinat ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.