Что нужно сделать, чтобы разбить изображение на сетку квадратных ячеек, раскрасить каждую ячейку содержащимся в ней усредненным цветом и экспортировать полученные средние значения в виде CSV-файла?
Поскольку ppm — это простые форматы изображений, преобразование в формат ppm может быть хорошим началом, но что дальше?
Мотивация: я делаю карту игрового мира и хочу преобразовать карту с цветовой кодировкой (цвета указывают тип биома) в файл данных (например, csv), который может быть прочитан другими файлами исходного кода.
Поскольку игровая карта будет обновляться по мере разработки игры, я надеюсь автоматизировать этот процесс, поэтому я считаю, что решение на основе кода было бы оптимальным; он написан на С#.
Отредактировано, чтобы устранить проблему эффективности. Но чтобы уточнить, я просто хотел бы избежать длительного ручного процесса создания csv каждый раз, когда карта обновляется.
Простой поиск в Google выдал хорошее место для начала.
Было бы полезно, если бы вы объяснили, какие значения вы на самом деле хотите записать в файл CSV. Если rgb(r,g,b) и вам действительно нужен CSV-файл, то разделители-запятые будут сбивать с толку из-за тех, что в значениях rgb. Также вы хотите rgb или hex? Вы хотите, чтобы это было как rgb (r, g, b) или просто значения r, g, b.





Вы можете использовать ImageMagick, который установлен в большинстве дистрибутивов Linux и доступен для macOS и Windows.
Просто в терминале (или в командной строке Windows), начиная с этого изображения 500x256:
magick start.png -resize 3x2\! -depth 8 -compress none ppm:
P3
3 2
255
189 0 66 189 0 66 189 0 66
66 0 189 66 0 189 66 0 189
Это изменило размер изображения и усреднило цвета в изображение 3x2 (выберите другой размер, если хотите) и распечатало вывод в виде текстового файла PPM.
Размер 3x2, и первая строка составляет 3 пикселя с rgb (189,0,66), который в основном красный, а вторая строка — 3 пикселя с rgb (66,0,189), который в основном синий.
Я оставлю вас в формате CSV :-)
Здесь вы можете уменьшить его размер и снова увеличить, чтобы увидеть эффект усреднения по блокам 8x3:
magick start.png -resize 8x3\! -depth 8 -scale 400x result.png
В зависимости от того, что вам нравится анализировать, вы можете получить одну и ту же информацию в немного другом формате:
magick start.png -resize 8x3\! -depth 8 txt:
# ImageMagick pixel enumeration: 8,3,65535,srgb
0,0: (54998,0,10537) #D60029 srgb(214,0,41)
1,0: (54998,0,10537) #D60029 srgb(214,0,41)
2,0: (54998,0,10537) #D60029 srgb(214,0,41)
3,0: (54998,0,10537) #D60029 srgb(214,0,41)
4,0: (54998,0,10537) #D60029 srgb(214,0,41)
5,0: (54998,0,10537) #D60029 srgb(214,0,41)
...
...
3,1: (32896,0,32896) #800080 purple
4,1: (32896,0,32896) #800080 purple
5,1: (32896,0,32896) #800080 purple
6,1: (32896,0,32896) #800080 purple
7,1: (32896,0,32896) #800080 purple
0,2: (10537,0,54998) #2900D6 srgb(41,0,214)
5,2: (10537,0,54998) #2900D6 srgb(41,0,214)
6,2: (10537,0,54998) #2900D6 srgb(41,0,214)
7,2: (10537,0,54998) #2900D6 srgb(41,0,214)
Вот небольшой цикл сценария bash с использованием Imagemagick для получения средних цветов блоков изображения и записи в файл csv.
Вход (256x256):
Чтобы получить правильное среднее значение для блоков изображения, следует использовать -scale, а не -resize. Итак, здесь я получаю набор 4x4 средних блоков 64x64 цветов из изображения (256/4=64). Затем я перебираю каждый блок в строках, затем в столбцах и получаю цвета. Я сохраняю цвета для каждой строки в строке rowlist с запятыми между ними. Собрав каждый ряд цветов, я записываю его в текстовый файл. Повтор для следующего ряда.
convert image.png -scale 4x4! image2.png
for ((j=0; j<4; j++)); do
for ((i=0; i<4; i++)); do
rowcolor=`convert image2.png -crop 1x1+$i+$j +repage -format "rgb(%[fx:round(255*u.r)]_%[fx:round(255*u.g)]_%[fx:round(255*u.b)])" info:`
if [ $i -eq 0 ]; then
rowlist = "$rowcolor"
else
rowlist = "$rowlist,$rowcolor"
fi
done
echo "$rowlist" >> image_colors.txt
done
Данные в полученном текстовом файле выглядят следующим образом:
rgb(8_0_247),rgb(50_0_205),rgb(50_0_205),rgb(8_0_247)
rgb(50_0_205),rgb(157_0_98),rgb(157_0_98),rgb(50_0_205)
rgb(50_0_205),rgb(157_0_98),rgb(157_0_98),rgb(50_0_205)
rgb(8_0_247),rgb(50_0_205),rgb(50_0_205),rgb(8_0_247)
Вы можете удалить rgb(), если хотите, и просто сохранить значения цвета. Я использовал _ для разделения значений, чтобы запятые использовались только между цветами rgb(...). Однако вы можете предпочесть использовать табуляции или пробелы для разделителей файлов, чтобы значения цвета были r, g, b, а не r_g_b.
Возможно, во избежание путаницы с запятыми было бы лучше записывать цвета как шестнадцатеричные значения. Итак, для этого используйте:
convert image.png -scale 4x4! image2.png
for ((j=0; j<4; j++)); do
for ((i=0; i<4; i++)); do
rowcolor=`convert image2.png -depth 8 -crop 1x1+$i+$j +repage -format "#%[hex:u.p]" info:`
if [ $i -eq 0 ]; then
rowlist = "$rowcolor"
else
rowlist = "$rowlist,$rowcolor"
fi
done
echo "$rowlist" >> image_colors.txt
done
который создает следующие значения в текстовом файле.
#0800F7,#3200CD,#3200CD,#0800F7
#3200CD,#9D0062,#9D0062,#3200CD
#3200CD,#9D0062,#9D0062,#3200CD
#0800F7,#3200CD,#3200CD,#0800F7
Использование %[hex:] является новым для Imagemagick в версиях Imagemagick 6 и 7 от 01.06.2017.
Почему масштабирование, а не изменение размера, пожалуйста?
Масштаб усредняет блоки пикселей. Изменение размера интерполирует пиксели и поэтому не является правильным средним значением, если вы не укажете -filter box. Другие фильтры выполняют взвешивание в локальной окрестности и поэтому не учитывают каждый пиксель одинаково при усреднении для изменения размера. См. imagemagick.org/script/command-line-options.php#scale в сравнении с imagemagick.org/script/command-line-options.php#resize и imagemagick.org/Использование/фильтр/#interpolated.
«как эффективно действовать дальше» - почему вы беспокоитесь об эффективности, если на данный момент у вас нет эффективности? Просто идите вперед, внедрите его, а затем измерьте, является ли эффективность проблемой или нет.