Заставьте Подушку генерировать изображение с типом TrueColor, в то время как я использую только черный и белый

Я генерирую изображения, используя Python 3.6.6 и Pillow == 5.3.0. Все изображения имеют формат JPEG и цветовой режим RGB.

Когда я сделаю изображение с цветами, оно выйдет с Type: TrueColor (и с глубиной канала: красный: 8-битный зеленый: 8-битный синий: 8-битный)

Когда я использую только черно-белое изображение, Type: Grayscale (и с глубиной канала: серый: 8 бит)

Поскольку я пытаюсь использовать службу печати, которая принимает только мои цветные изображения, я хочу сделать черно-белые изображения TrueColor изображение, даже если у них не будет других цветов (RGB).
Могу я просто сделать это?
Или делает TrueColor изображение означает, что значения RGB не могут быть все 0?

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

Альтернативой может быть преобразование изображения с помощью инструмента (я работаю в Ubuntu 18.04 и использую ImageMagick и ffmpeg). Я попробовал следующее, но ничего не помогло. Выходной файл имеет те же метаданные, что и исходный.

convert -type TrueColor original_file.jpeg converted_file.jpeg
convert -type TrueColor -depth 8 original_file.jpeg converted_file.jpeg

РЕДАКТИРОВАТЬ & Пример

Вот код Python для создания двух изображений в одинаковом режиме (RGB).

from PIL import Image, ImageDraw

white = (255, 255, 255)
black = (0, 0, 0)
red = (230, 25, 75)

def draw_line(file_name, line_color):
    """
    Draw a 400x400 image with a white background and one 
    diagonal line of the given 'line_color'
    """
    image = Image.new(mode='RGB', size=(400, 400), color=white)
    draw = ImageDraw.Draw(image)
    draw.line(xy=((100, 100), (300, 300)), fill=line_color, width=5)
    image.save(fp=file_name, format='JPEG')

draw_line(file_name='black_line.jpeg', line_color=black
draw_line(file_name='red_line.jpeg', line_color=red)

Изображение с черной линией будет иметь Type: Grayscaleи тот, с красной линией Type: TrueColor, Обратите внимание, что ColorSpace является sRGB в обоих случаях, а глубина 8-битная.

identify black_line.jpeg
black_line.jpeg JPEG 400x400 400x400+0+0 8-bit sRGB 5.12KB 0.000u 0:00.000

identify -verbose black_line.jpeg
  Type: Grayscale
  Colorspace: sRGB
  Depth: 8-bit
  Channel depth:
    gray: 8-bit


identify red_line.jpeg
red_line.jpeg JPEG 400x400 400x400+0+0 8-bit sRGB 5.26KB 0.000u 0:00.000

identify -verbose red_line.jpeg
  Type: TrueColor
  Colorspace: sRGB
  Depth: 8-bit
  Channel depth:
    red: 8-bit
    green: 8-bit
    blue: 8-bit

Поэтому мой вопрос: могу ли я создавать изображения с помощью подушки, чтобы независимо от того, какие цвета я использовал, они всегда выглядели одинаково type: TrueColor с 3 каналами? Так что даже в том случае, когда я рисую черную линию на белом фоне.

(ПРИМЕЧАНИЕ: когда я нарисую красную линию с шириной по умолчанию 1, он будет иметь Type: Palette вместо TrueColor)

Попытка конвертировать в TrueColor

convert black_line.jpeg -type truecolor black_line_tc.jpeg
identify -verbose black_line_tc.jpeg |grep Type
  Type: Grayscale

Таким образом, он не будет преобразовывать тип в TrueColor. Я сделал различия в идентифицирующих выходных данных, но нет никакой существенной разницы в отношении channel_depth / colorspace / type и т. Д., Поэтому я не буду публиковать выходные данные.

identify -verbose black_line.jpeg > identity_black.txt
identify -verbose black_line_tc.jpeg > identity_black_tc.txt
diff identity_black.txt identity_black_tc.txt

3 ответа

Работает для меня. В тестах ниже:

  • BW-RGB.jpg изображение плазмы в оттенках серого (с каналами RGB), экспортированное из Gimp
  • BW-Grey.jpg такое же изображение в чистом оттенках серого (один канал), экспортированное из Gimp

И.М. identify говорит:

BW-Grey.jpg JPEG 400x400 400x400+0+0 8-bit Gray 256c 48.2KB 0.010u 0:00.000
BW-RGB.jpg JPEG 400x400 400x400+0+0 8-bit sRGB 49.1KB 0.010u 0:00.019

И если я использую:

convert BW-Grey.jpg -type TrueColor  BW-Converted.jpg

И.М. identify говорит:

BW-Converted.jpg JPEG 400x400 400x400+0+0 8-bit sRGB 54.1KB 0.000u 0:00.000

Так что результат действительно RGB. Обратите внимание, что размер файлов RGB и оттенков серого не очень отличается, что ожидается. Цветное изображение сохраняется в виде трех кадров, черно-белого и двухцветного, но для изображения в оттенках серого (R=G=B) эти два цветовых изображения имеют одно единое однородное значение и поэтому сжимаются очень хорошо.

PS: на Linux вы можете подтвердить IM identify сообщить с использованием file Команда: она сообщает один кадр в полутоновых изображениях и три в цветных.

Обновленный ответ

Я экспериментировал с этим, и это кажется очень неуправляемым - по крайней мере, мной!

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

Затем я попытался добавить и вычесть крошечное количество случайного шума для всех пикселей и добился некоторого прогресса, но изображение становится "ощутимо несчастным" до того, как ImageMagick признает, что это TrueColour. Подавление подвыборки в кодировщике JPEG и повышение качества помогают немного - но не сильно.

Я обнаружил, что должен был увеличить N (количество шума) до 9, прежде чем ImageMagick согласился, что изображение было TrueColour. Вы можете поэкспериментировать, поэтому вот код:

#!/usr/bin/env python3

from PIL import Image, ImageDraw
import numpy as np

def makeTrueColour(image):
   """
   Force image to TrueColour by 'slightly distorting' greys.
   Distortion means adding a tiny random amount of noise (0-N) to pixels that will not
   "burn out" (i.e. exceed 255) as a result, and also subtracting a similar tiny 
   random amount of noise from pixels  from pixels that will not underflow as a result.
   If N=1, this means less than 0.4% error - hopefully imperceptible.
   """

   N = 1
   w, h = image.size
   ni = np.array(image)

   # Mask of pixels that will not exceed 255 by adding N
   okpix = (ni <= (255 - N))
   # Make additive noise in those pixels
   noise = np.random.randint(0,N+1,size=(h,w,3),dtype=np.uint8) * okpix
   ni += noise

   # Mask of pixels big enough to subtract N
   okpix = (ni >= N)
   # Make subtractive noise in those pixels
   noise = np.random.randint(0,N+1,size=(h,w,3),dtype=np.uint8) * okpix
   ni -= noise

   return(Image.fromarray(ni))


image = Image.new(mode='RGB', size=(400, 400), color=(255,255,255))
draw = ImageDraw.Draw(image)
draw.line(xy=((100, 100), (300, 300)), fill=(0,0,0), width=5)

tc = makeTrueColour(image)
tc.save('result.jpg',subsample=0,quality=95)  

# This just counts the unique colours in "tc" - you don't need it
T = np.array(tc)   
print(len(np.unique(T.reshape(-1, T.shape[2]), axis=0)) )

Оригинальный ответ

Я не уверен, что понимаю. Вот что я получаю, когда делаю RGB-изображение:

from PIL import Image
import numpy as np

# Make a fully black image
im = np.zeros([480,640,3], dtype=np.uint8) 

# Save as RGB
Image.fromarray(im).save('resultRGB.jpg')

# Save as greyscale
Image.fromarray(grey).convert('L').save('resultGRAY.jpg')

Теперь я смотрю на них с помощью ImageMagick и получаю именно то, что ожидаю:

identify result*jpg

resultGRAY.jpg JPEG 640x480 640x480+0+0 8-bit Gray 256c 3932B 0.000u 0:00.000
resultRGB.jpg JPEG 640x480 640x480+0+0 8-bit sRGB 5427B 0.000u 0:00.000

На что ты надеялся? Пожалуйста, нажмите edit под свой оригинальный вопрос и приведите контрпример.

Вот пример принудительного преобразования одноканального изображения JPG в градациях серого в 3-канальное изображение sRGB с цветовым пространством с использованием ImageMagick.

Здесь я создаю градиент серого. Затем используйте Imagemagick identifier -verbose, и оно будет отображаться как цветное пространство Grey. Exiftool подтверждает это как 1 канал (компонент цвета) с 8 битами.

convert -size 256x256 gradient: grad.jpg

identify -verbose grad.jpg
Image: grad.jpg
  Format: JPEG (Joint Photographic Experts Group JFIF format)
  Mime type: image/jpeg
  Class: PseudoClass
  Geometry: 256x256+0+0
  Units: Undefined
  Colorspace: Gray
  Type: Grayscale
  Base type: Undefined
  Endianess: Undefined
  Depth: 8-bit
  Channel depth:
    gray: 8-bit
...

exiftool -s -ee -g1 -u -n -D grad.jpg
...
    - BitsPerSample                   : 8
    - ColorComponents                 : 1
...


Теперь я использую truetype -type для преобразования изображения в градациях серого в цветовое пространство RGB. ImageMagick говорит, что цветовое пространство RGB и exiftool показывают, что это 3 канала (цветовые компоненты) каждый из 8 бит.

convert grad.jpg -type truecolor grad_tc.jpg

Fredericks-Mac-mini:desktop fred$ identify -verbose grad_tc.jpg
Image: grad_tc.jpg
  Format: JPEG (Joint Photographic Experts Group JFIF format)
  Mime type: image/jpeg
  Class: DirectClass
  Geometry: 256x256+0+0
  Units: Undefined
  Colorspace: sRGB
  Type: Grayscale
  Base type: Undefined
  Endianess: Undefined
  Depth: 8-bit
  Channel depth:
    red: 8-bit
    green: 8-bit
    blue: 8-bit
...

exiftool -s -ee -g1 -u -n -D grad_tc.jpg
...
    - BitsPerSample                   : 8
    - ColorComponents                 : 3
...

Я подозреваю, что PIL определяет цветовое пространство тем, сколько каналов вы используете при чтении или создании изображения. Извините, я не очень знаком с PIL. Но если этого не произойдет, то вы можете передать его в numpy, чтобы сделать его 3 канала. Затем верните его в ПИЛ.

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