Максимальное количество цветов и масштабирование

Я пытаюсь преобразовать 80x80 изображений в 56x56 изображений в оттенках серого в 2bpp.

Изображения 80x80 цветные и, возможно, содержат до 16 цветов. У них также есть прозрачный фон.

Мне нужно, чтобы они были серого цвета с четырьмя цветами: белый - самый светлый, а черный - самый темный.

Каждое изображение содержит несколько цветов, но каждый цвет имеет палитру из 3 цветов: темного, среднего и светлого.

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

Я могу успешно преобразовать изображение в оттенки серого, обрезать холст и заполнить фон этой командой

convert input.png +dither -flatten -trim -set colorspace Gray -
separate -average output.png

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

-авто-уровни не делают то, что я хочу, либо.

Есть ли способ установить цвета в среднем диапазоне, чтобы они автоматически выравнивались в соответствии с моими требованиями? Извините, если я не объясняю это достаточно.

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

convert "$f" +dither -flatten -trim -set colorspace Gray -separate -
average -gamma 1.37 -level 25%,75% -colors 4 -adaptive-resize 56x56\> 
-background white -gravity center -extent 56x56 -remap nido.png 
"${f%.png}".png2

Я не могу предоставить ожидаемое изображение, но изображение, похожее на ожидаемое. Вот оригинальное изображение https://img.pokemondb.net/sprites/black-white/normal/charizard.png а вот изображение желаемого формата вывода https://img.pokemondb.net/sprites/red-blue/normal/charizard.png

Вот то, что я до сих пор получил https://www.pokecommunity.com/showthread.php?p=9692599

convert "$f" +dither -background white -flatten -trim -adaptive-resize 
56x56\> "${f%.png}".png2
convert "${f%.png}".png2 +dither -colorspace gray -separate -average 
"${f%.png}".png2
convert "${f%.png}".png2 +dither -gamma 3.0 -black-threshold 70% 
"${f%.png}".png2
convert "${f%.png}".png2 +dither -gamma 0.45 -white-threshold 90% 
"${f%.png}".png2
convert "${f%.png}".png2 +dither -remap nidoking.png -background white 
-gravity center -extent 56x56 "${f%.png}".png2

Кстати, ^ находится в цикле for, отсюда и переменные. Изменение значений гаммы и черного / белого приближает меня, но это очень утомительно, и когда я получаю одно изображение, чтобы правильно преобразовать другое, разрывы. nidoking.png - мой файл переотображения. Переназначение работает отлично, перед переназначением цвета разделяются или фильтруются должным образом.

Решено, благодаря Марку Сетчеллу

Это то, что я в итоге делал

#!/bin/bash
rm x*
rm colors*
cd images
rm *.png2
rm *.txt
for f in *.png
do

#Fitting canvas to image, setting background color, and removing transparency

    convert "$f" +dither -background white -flatten -trim "${f%.png}".png2

#Converting image to greyscale

    convert "${f%.png}".png2 +dither -colorspace gray -separate -average "${f%.png}".png2

#Resizing without blurring/adding pixels

    convert "${f%.png}.png2" +dither -interpolate Nearest -interpolative-resize 56x56\> "${f%.png}".png2

#Grabbing every color used in image and putting it in a text file

    convert "${f%.png}.png2" txt: | sed '1d' | cut -f 4 -d " " | sort -u > "${f%.png}".txt
done

#Putting all colors into one file

cat *.txt >> ../colors
cd ../

#One last clean up of file/sorting

cat colors | tr " " "\n" | sort -u > colors.txt
rm colors

#Splitting the hex codes into four files for each desired color

file=colors.txt
lines=$(wc -l <${file})
((lpp = (lines + 4 - 1) / 4))
split --lines=${lpp} ${file}

#Going back to images directory

cd images

for f in *.png
do

#Each while loop reads everyone line of the specified file and puts it in variable $i, then I use $i to convert to one of the desired 4 colors.

    cat ../xaa | while read i
    do
    convert "${f%.png}".png2 +dither -fuzz 0% -fill "#000000" -opaque "${i}" "${f%.png}".png2
    done

    cat ../xab | while read i
    do
    convert "${f%.png}".png2 +dither -fuzz 0% -fill "#555555" -opaque "${i}" "${f%.png}".png2
    done

    cat ../xac | while read i
    do
    convert "${f%.png}".png2 +dither -fuzz 0% -fill "#AAAAAA" -opaque "${i}" "${f%.png}".png2
    done

    cat ../xad | while read i
    do
    convert "${f%.png}".png2 +dither -fuzz 0% -fill "#FFFFFF" -opaque "${i}" "${f%.png}".png2
    done

    mv "${f%.png}".png2 ../finished/"${f}"

done

Этот сценарий превратил это Исходное изображение

В это Отфильтрованное изображение

2 ответа

Решение

По сути, идея состоит в том, чтобы уменьшить до 4 цветов в цветовом пространстве RGB (а не в цветовом пространстве серого), чтобы получить лучшие четыре цвета. Затем возьмите яркость каждого из них и сопоставьте самый темный с черным, следующий светлее с темно-серым, следующий светлее с серым и самый светлый с белым.

Здесь он сопоставлен с 4 лучшими цветами в цветовом пространстве RGB:

введите описание изображения здесь

Код без особой проверки ошибок или обработки угловых случаев выглядит следующим образом:

#!/bin/bash -x

# Do a colour reduction to get best 4 colours in RGB colourspace rather than in grey colourspace
magick pokething.png -alpha off +dither -colors 5 -unique-colors unique.png

# Get hex colours into array "hexcolours[]"
hexcolours=( $(convert unique.png txt: | awk 'NR>1{print $3}') )
echo DEBUG: hexcolours=${hexcolours[@]}

# Get lightness of each colour into array "lightness[]", i.e. H of HSL
# Note ggrep is just GNU grep
lightness=( $(convert unique.png -colorspace HSL -separate -delete 0,1 txt: | ggrep -Po "\d+(?=\)$)") )
echo DEBUG: lightness=${lightness[@]}

# Sort the colours by their lightness
fourshades=( $(for ((i=0;i<4;i++)) ;do
   echo ${lightness[i]} ${hexcolours[i]}
done | sort -n | awk '{print $2}') )
echo DEBUG: fourshades=${fourshades[@]}

# Now change those colours in original image
magick pokething.png -alpha off +dither -colors 5 -fuzz 10%   \
   -fill black  -opaque "${fourshades[0]}"                    \
   -fill gray25 -opaque "${fourshades[1]}"                    \
   -fill gray75 -opaque "${fourshades[2]}"                    \
   -fill white  -opaque "${fourshades[3]}"                    \
   result.png

Вывод следующий:

DEBUG: hexcolours=#000000 #094152 #A95244 #EF9E3C
DEBUG: lightness=0 46 119 150
DEBUG: fourshades=#000000 #094152 #A95244 #EF9E3C

Это приводит к тому, что это выполняется:

magick pokething.png -alpha off +dither -colors 5 -fuzz 10% \
   -fill black  -opaque '#000000'                           \
   -fill gray25 -opaque '#094152'                           \
   -fill gray75 -opaque '#A95244'                           \
   -fill white  -opaque '#EF9E3C' result.png

введите описание изображения здесь

Итак, в основном я заменяю #094152 на темно-серый, потому что 46 является вторым самым темным присутствующим цветом. Затем я заменяю #A95244 на светло-серый, потому что 119 - следующий более светлый цвет, затем заменяю #EF9E3C на белый, потому что это самый светлый цвет.

Вы можете получить желаемый результат, используя только "-remap". В этом примере будет построена четырехцветная карта из белого, 65% серого, 35% серого и черного и запись этой карты во временную память. Затем он читает ваше входное изображение, устанавливает белый фон и выравнивает изображение. Затем он отключает сглаживание, переназначает входное изображение на созданную вами карту и возвращает результат.

convert xc:white xc:gray65 xc:gray35 xc:black -append -write mpr:map +delete \
   input.png -background white -flatten +dither -remap mpr:map output.png

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

Другие вопросы по тегам