Convertendo uma Imagem para Usar Cores Seguras

Um sistema de representação de cores em imagens — RGB, HSI, CMY, CMYK — pode conter diversos valores, permitindo gerar escalas com tonalidades mais ou menos variadas, dependendo da quantidade de informação utilizada na representação (8, 16, 32 ou 24 bits). Todavia, existem 216 cores padronizadas utilizadas para algumas aplicações.

Estas 216 cores seguras tem como principal utilização a Web e são usadas pelos navegadores, independentemente a plataforma. O navegador alterará todas as cores da imagem para essas cores seguras para a Web ao visualizar uma cor a imagem na tela de 8 bits. As 216 cores formam um subconjunto das paletas de cores de 8 bits do MacOS. Ao trabalhar apenas com essas cores, é possível ter certeza de que a arte preparada para a Web não ficará pontilhada em um sistema definido com exibição em 256 cores.

Cada uma das 216 cores seguras é formada pelos três valores RGB da paleta de 256, mas estes valores são re-escalonados apenas para os valores 0, 51, 102, 153 ou 255. Assim, a tripla é formada pela combinação desses seis valores — \((6)^3 = 216\) possíveis valores. Portanto, a conversão consiste apenas em transformar os valores intermediários da maior escala \((0-255) \) nos valores da menor escala para cada pixel (note que no espaço RGB cada pixel possui 3 componentes). A função abaixo ilustra este processo:

def safecolors(Im):
    """
    Convert a RGB image to safe colors.
 
    Parameters
    ----------
    * im: unsafe RGB image (numpy matrix)
 
    Written by Pedro Garcia Freitas [sawp @sawp.com.br]
    Copyright 2010 by Pedro Garcia Freitas
 
    see: http://www.sawp.com.br
    """
    Im = ceil((6.0 / 255.0) * Im)
    R = Im[:,:,0]
    G = Im[:,:,1]
    B = Im[:,:,2]
 
    R = (R == 1).choose(R, 0x00)
    R = (R == 2).choose(R, 0x33)
    R = (R == 3).choose(R, 0x66)
    R = (R == 4).choose(R, 0x99)
    R = (R == 5).choose(R, 0xCC)
    R = (R == 6).choose(R, 0xFF)
 
    G = (G == 1).choose(G, 0x00)
    G = (G == 2).choose(G, 0x33)
    G = (G == 3).choose(G, 0x66)
    G = (G == 4).choose(G, 0x99)
    G = (G == 5).choose(G, 0xCC)
    G = (G == 6).choose(G, 0xFF)
 
    B = (B == 1).choose(B, 0x00)
    B = (B == 2).choose(B, 0x33)
    B = (B == 3).choose(B, 0x66)
    B = (B == 4).choose(B, 0x99)
    B = (B == 5).choose(B, 0xCC)
    B = (B == 6).choose(B, 0xFF)
 
    Om = zeros((Im.shape[0], Im.shape[1], 3))
    Om[:,:,0] = R
    Om[:,:,1] = G
    Om[:,:,2] = B
    return Om

Esta função pode ser utilizada da seguinte forma:

if __name__ == "__main__":
    inputim = imread('cube.bmp')
    outputim = safecolors(inputim)
    imsave('safe.bmp', outputim)

O resultado deste código é

Original
Cores seguras