Как преобразовать изображение RGB в CMYK с python? - PullRequest
3 голосов
/ 23 марта 2020

Я хочу конвертировать изображение RGB в CMYK. Это мой код, первая проблема в том, что когда я делю каждый пиксель на 255, значение закрывается до нуля, поэтому результирующее изображение становится примерно черным! Вторая проблема заключается в том, что я не знаю, как преобразовать полученное изображение с 1 каналом в 4 канала. Конечно, я не уверен, что созданный CMYK в следующем коде верен. Спасибо за внимание


CMYK formula Dr.Trump!

import cv2
import numpy as np
import time

img = cv2.imread('image/dr_trump.jpg')

B = img[:, :, 0]
G = img[:, :, 1]
R = img[:, :, 2]

B_ = np.copy(B) 
G_ = np.copy(G)
R_ = np.copy(R)

K = np.zeros_like(B) 
C = np.zeros_like(B) 
M = np.zeros_like(B) 
Y = np.zeros_like(B) 

ts = time.time()

for i in range(B.shape[0]):
    for j in range(B.shape[1]):
        B_[i, j] = B[i, j]/255
        G_[i, j] = G[i, j]/255
        R_[i, j] = R[i, j]/255

        K[i, j] = 1 - max(B_[i, j], G_[i, j], R_[i, j])
        if (B_[i, j] == 0) and (G_[i, j] == 0) and (R_[i, j] == 0):
        # black
              C[i, j] = 0
              M[i, j] = 0  
              Y[i, j] = 0
        else:

            C[i, j] = (1 - R_[i, j] - K[i, j])/float((1 - K[i, j]))
            M[i, j] = (1 - G_[i, j] - K[i, j])/float((1 - K[i, j]))
            Y[i, j] = (1 - B_[i, j] - K[i, j])/float((1 - K[i, j]))


CMYK = C + M + Y + K 

t = (time.time() -ts)
print("Loop: {:} ms".format(t*1000))


cv2.imshow('CMYK by loop',CMYK)
cv2.waitKey(0)
cv2.destroyAllWindows()

Ответы [ 2 ]

3 голосов
/ 23 марта 2020

Вы можете позволить PIL / Pillow сделать это для вас следующим образом:

from PIL import Image

# Open image, convert to CMYK and save as TIF
Image.open('drtrump.jpg').convert('CMYK').save('result.tif')

Если я использую IPython, я могу загружать, конвертировать и сохранять время в 13мс всего вот так:

%timeit Image.open('drtrump.jpg').convert('CMYK').save('PIL.tif')
13.6 ms ± 627 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Если вы хотите сделать это самостоятельно, внедрив формулу, вам лучше использовать векторизация Numpy, а не for циклы , Это занимает 35 мс.

#!/usr/bin/env python3

import cv2
import numpy as np

# Load image
bgr = cv2.imread('drtrump.jpg')

# Make float and divide by 255 to give BGRdash
bgrdash = bgr.astype(np.float)/255.

# Calculate K as (1 - whatever is biggest out of Rdash, Gdash, Bdash)
K = 1 - np.max(bgrdash, axis=2)

# Calculate C
C = (1-bgrdash[...,2] - K)/(1-K)

# Calculate M
M = (1-bgrdash[...,1] - K)/(1-K)

# Calculate Y
Y = (1-bgrdash[...,0] - K)/(1-K)

# Combine 4 channels into single image and re-scale back up to uint8
CMYK = (np.dstack((C,M,Y,K)) * 255).astype(np.uint8)

Если вы хотите проверить свои результаты, вам нужно знать о нескольких вещах. Не все форматы изображений могут сохранять CMYK, поэтому я сохранил как TIFF. Во-вторых, ваша формула оставляет все ваши значения в виде значений с плавающей запятой в диапазоне 0..1, так что вы, вероятно, захотите уменьшить масштаб путем умножения на 255 и преобразования в uint8.

Наконец, вы можете быть уверены в том, что правильно В результате просто используйте ImageMagick в Терминале:

magick drtrump.jpg -colorspace CMYK result.tif
2 голосов
/ 23 марта 2020

Вам не нужно делать CMYK = C + M + Y + K.

Я не знаю, как преобразовать 1-канальное изображение в 4-канальное.

Для ndim массивы, которые вы можете использовать numpy.dstack. Документация ссылка .

Редактировать

Неправильные результаты вызваны разделением int. Вам нужно выполнить деление поплавка. Одним из способов достижения этого является преобразование массива B, G и R в float

B = img[:, :, 0].astype(float) # float conversion, maybe we can do better. But this results in correct answer
G = img[:, :, 1].astype(float) #
R = img[:, :, 2].astype(float) #
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...