Estou criando uma demonstração de 20 bolas quicando umas nas outras, com um fundo preenchido com uma cor sólida. A cor de cada bola é escolhida aleatoriamente com randint(0, 255)
cada componente de tupla R, G, B.
O problema é que algumas bolas acabam com uma cor muito semelhante ao fundo, dificultando a visualização. Gostaria de evitar isso, rolando outra cor se a escolhida for muito semelhante (dentro de um determinado limite) ou afastando-a da cor de fundo.
Como calcular um índice de similaridade para usar como limite? Ou como transformar uma cor para torná-la, digamos, menos azulada ?
Isenção de responsabilidade óbvia: não sei nada sobre teoria das cores, portanto não sei se os conceitos acima existem!
Estou codificando em python, mas estou procurando conceitos e estratégias, então o pseudo-código é bom (ou apenas a teoria).
EDITAR:
Para esclarecer alguns pontos:
Cada bola tem sua própria cor aleatória. Gostaria que eles permanecessem o mais aleatórios possível e que explorassem o máximo possível do espaço de cores (seja RGB ou HSV,
pygame
aceita os dois formatos para definir cores)Eu gostaria de evitar que cada cor fique "muito perto" do plano de fundo. O problema não é apenas a tonalidade: eu estou perfeitamente bem com uma bola azul claro contra um fundo azul escuro (ou um "azul completo" contra um azul "branco-ish", etc)
Por enquanto, não me importo se uma bola acaba com uma cor semelhante (ou mesmo idêntica) a outra bola. Evitar isso é um bônus, mas é uma questão menor.
A cor de fundo é uma constante, única cor RGB. Por enquanto estou usando o azul "básico"
(0, 0, 255)
, mas não estou de acordo com isso. Portanto, considere o plano de fundo de uma cor arbitrária (com matiz arbitrário, brilho, saturação etc.).
EDIT2:
Versão TL, DR: Apenas crie uma forma aleatória de cores X para que nenhuma "desbote muito" em um fundo de cores arbitrárias (mas únicas e constantes)
Respostas:
Você pode usar o fato de que as cores compõem um espaço de cores (tridimensional) e calculam uma distância nesse espaço de cores. Você precisa definir uma métrica nesse espaço de cores para encontrar a distância entre duas cores.
Por exemplo, a distância em um espaço euclidiano entre dois pontos x = (x1, x2, x3) e y = (y1, y2, y3) é dada por d (x, y) = sqrt ((y1-x1) * (y1- x1) + (y2-x2) * (y2-x2) + (y3-x3) * (y3-x3)).
Agora você pode calcular a distância entre a cor de uma bola e a cor de fundo e, se ela for muito pequena, crie uma nova cor aleatória e teste novamente.
Você descobrirá que nem RGB nem HSV são bons espaços de cores para esta tarefa. O artigo da Wikipedia sobre diferença de cores emprega o espaço de cores L a b e fornece várias métricas possíveis.
Há também uma discussão sobre o stackoverflow no tópico.
fonte
A página das normas de acessibilidade da Web das Nações Unidas ( http://www.un.org/webaccessibility/1_visual/13_colourcontrast.shtml ) indica um padrão para garantir a devida contraste de texto nos sites, lembrando que alguns usuários são daltônicos. Isso pode ser particularmente importante para você, já que alguns de seus usuários também podem ser daltônicos (seria difícil distinguir uma bola vermelha de fundo verde se tiverem a mesma luminância).
A página da ONU aponta para o analisador de taxa de contraste de cores de luminosidade do Juicy Studios em ( http://juicystudio.com/services/luminositycontrastratio.php#specify ), que afirma que o texto em segundo plano deve ter uma taxa de contraste de 4,5: 1, exceto pelo que acredite ser semelhante ao seu caso:
Agora, o que é uma taxa de contraste? Seguindo os hiperlinks (isso é divertido!), Chegamos a uma página W3 que define a taxa de contraste como:
Onde L1 e L2 são as luminências relativas das cores. L1 é a cor mais luminosa, L2 é a cor menos luminosa. Novamente, seguimos o link para a mesma página W3 que especifica:
NOTA : O símbolo de sinal de intercalação ^ acima refere-se à exponenciação (x²)
E nós temos uma estrutura muito boa para um algoritmo de contraste (que é daltônico!)
fonte
^
, eu nunca pensaria em um XOR pouco a pouco nesse contexto. . (ou em quaisquer phreaks realmente C'mon C,^
é o simbol de facto para exponenciação em pseudo-códigos (embora muito poucas línguas realmente usá-lo ... em python é**
)O uso de valores RGB gerando um
0-255
valor aleatório para cada componente pode não apenas criar cores semelhantes ao plano de fundo, mas também acabar com cores muito semelhantes para as bolas.Eu provavelmente escolheria uma abordagem menos aleatória e criaria cores que, com certeza, serão diferentes. Você pode criar uma cor para cada ~ 32 graus na faixa de matiz e alternar o brilho ou a saturação (use o modelo de cores HSV em vez de RGB).
Então, algo como isto:
que criará 20 cores, bem distribuídas. Isso pressupõe que você está usando matemática inteiro, por isso
i = 0
ei = 1
vai criar o mesmo valor de tonalidade.É claro que isso não é muito bom. Se você tiver 100 valores de cores para criar, o espaçamento de matiz poderá não ser suficiente e você terá cores semelhantes novamente. Nesse caso, você também pode variar o
V
valor (brilho).Não sei como é a cor de fundo, mas o HSV também facilita a comparação de cores (basta comparar os 3 componentes e não se esqueça que o HUE é circular (0 == 360)).
ATUALIZAR:
Como eu realmente não respondi sua pergunta, mas forneci outra abordagem, eis como um algoritmo para um fundo arbitrário e bolas coloridas completamente aleatórias pode parecer (essa é uma abordagem de força bruta, mas deve funcionar bem para o seu caso de uso):
fonte
V
(porque o algoritmo atual não altera isso).Como você mencionou que tem um fundo estacionário, a cor das bolas ainda pode ser aleatória, mas elas precisam cair em determinados intervalos que ainda complementam o fundo.
Noções básicas. Antes de fazermos isso, você precisa conhecer o básico. Considere as seguintes cores:
Mistura de cores RGB [(0..255), (0..255), (0..255)] cria novas cores como acima.
Computação para cores negativas A computação para cores negativas é como transformar vermelho em ciano, verde em roxo, azul em amarelo.
Cor Complementar
Conforme referência em Computação de cores complementares: http://serennu.com/colour/rgbtohsl.php
Sobre HSL
HSL expressa cores em termos de matiz, saturação e luminosidade, fornecendo um número para cada um desses três atributos da cor.
The Hue é a posição da cor na roda de cores, expressa em graus de 0 ° a 359 °, representando os 360 ° da roda; 0 ° sendo vermelho, 180 ° sendo o vermelho oposto à cor ciano e assim por diante.
A saturação é a intensidade da cor, quão opaca ou brilhante é. Quanto menor a saturação, mais opaca (mais cinza) a cor fica. Isso é expresso como uma porcentagem, sendo 100% de saturação total, o mais brilhante e 0% sem saturação, cinza.
Leveza é o quão clara é a cor. Um pouco diferente da saturação. Quanto mais branco na cor, maior o valor da luminosidade, mais preto, menor a luminosidade. Portanto, 100% de luminosidade torna a cor branca, 0% de luminosidade torna a cor preta e a cor "pura" seria 50% de luminosidade.
É mais fácil ver a diferença entre Saturação e Luminosidade do que explicá-la. Se você deseja esclarecer, tente visualizar as variações de Luminosidade e Saturação na página da calculadora de cores, escolhendo uma cor bastante brilhante como sua cor inicial.
Portanto, a notação HSL se parece com isso, fornecendo os valores Matiz, Saturação e Luminosidade nessa ordem: t
Vermelho: 0 ° 100% 50% Rosa pálido: 0 ° 100% 90% Ciano: 180 ° 100% 50% Aqui estão as etapas:
Converta sua cor para HSL.
Altere o valor da Matiz para o oposto da Matiz (por exemplo, se o seu Matiz for 50 °, o oposto estará em 230 ° na roda - 180 ° mais à frente).
Deixe os valores de Saturação e Luminosidade como estavam.
Converta esse novo valor HSL de volta à sua notação de cores original (RGB ou qualquer outra coisa).
Sites como EasyRGB.com podem fazer uma conversão genérica para você de RGB para HSL ou vice-versa.
Exemplo de programação feito em PHP conforme referência
Conversão RGB para HSL
O valor acima do azul # 0000FF rgb (0,0,255) pode ser apresentado como vermelho hexadecimal 00 + verde hexadecimal 00 + azul hexadecimal FF
Também pode ser apresentado como Vermelho Decimal 0 + Verde Decimal 0 + Azul Decimal 255
Agora, conecte esses valores à rotina rgb2hsl. Abaixo está minha versão PHP do código genérico do EasyRGB.com para essa conversão:
A entrada é $ var_r, $ var_g e $ var_b acima A saída é equivalente a HSL como $ h, $ se $ l - eles são novamente expressos como frações de 1, como os valores de entrada
Então agora temos a cor como um valor HSL, nas variáveis $ h, $ se $ l. Essas três variáveis de saída são novamente mantidas como frações de 1 neste estágio, e não como graus e porcentagens. Assim, por exemplo, ciano (180 ° 100% 50%) sairia como $ h = 0,5, $ s = 1 e $ l = 0,5.
Em seguida, encontre o valor do matiz oposto, ou seja, aquele que está a 180 ° ou 0,5, de distância (tenho certeza que os matemáticos têm uma maneira mais elegante de mostrar isso, mas):
Calcular a matiz oposta, $ h2
O valor HSL da cor complementar está agora em $ h2, $ s, $ l. Então, estamos prontos para convertê-lo novamente em RGB (novamente, minha versão PHP da fórmula EasyRGB.com). Observe que os formatos de entrada e saída são diferentes desta vez, veja meus comentários na parte superior do código:
A entrada é o valor HSL da cor complementar, mantida em $ h2, $ s, $ l como frações de 1 A saída é RGB no formato normal 255 255 255, mantida em $ r, $ g, $ b A matiz é convertida usando a função hue_2_rgb, mostrada no final deste código
E depois dessa rotina, finalmente temos $ r, $ ge $ b no formato 255 255 255 (RGB), que podemos converter em seis dígitos hexadecimais:
$ rgbhex é a nossa resposta - a cor complementar em hexadecimal.
Como o fundo colorido é azul ou 0,0.255, o HSL é
Matiz (H): 240 graus / Saturação (S): 100% / Luminosidade (L): 4,9%
oposto de 240 é 60 em um círculo, em seguida, converter de volta para RGB dá um valor de # 181800
fonte
Gostaria de expandir a idéia de @ ashes999 de criar um esboço.
Meu código será o mais parecido com um python do que eu consigo (nunca escrevi uma linha de python na minha vida, mas olhei sobre um livro uma ou duas vezes).
Pode não parecer particularmente bonito e não é realmente ideal para código de produção, mas deve ser suficiente como uma solução rápida. Não testei o código, pois não tenho exatamente o programa "bolas saltando pela tela" que posso mutilar para testá-lo.
Editar:
Ao ver o código real em uso, a situação virou de cabeça para baixo, então, em vez disso, ofereço esta solução.
Substitua as linhas 276-284 pelo seguinte:
Nesta nova versão simplificada, um método de fábrica cospe as bolas e um método especializado gera as cores. O gerador de cores testa a cor gerada aleatoriamente para verificar se ela está dentro de um certo intervalo de proximidade da cor de fundo. Uma cor é considerada muito próxima da cor BG se todos os três canais de cores estiverem dentro de
leeway
cada lado da BG. Portanto, se a margem de manobra for 0, apenas as cores que correspondem exatamente ao BG serão recusadas. Eu escolhi 5 como padrão, que recusa a cor BG e as 5 cores em ambos os lados. Como a cor BG é branca, não tenho certeza se recusará o preto porque os dígitos são redondos. Isso pode ser evitado com o uso das funções min e max, mas eu as deixei de fora por uma questão de brevidade.fonte
pygame
como uma biblioteca. Não Lerp, apenas conversões básicas de RGB-HSV-CYMK: pygame.org/docs/ref/color.htmllerp
função na minha resposta é tudo o que existe. (Lerp significa 'interpolação linear').print
é diferente porque está usando o Python 3 e eu ainda estou no Python 2. E ainda não tenho certeza sepygame
foi portado para o Py3. Bottomline: não se preocupe :) A pergunta é sobre cores, você não precisa de bolas reais pulando :)Para um formato RGB, isso parece funcionar bem o suficiente e é trivial:
diversity_score = (abs (r1 - r2) + abs (g1 - g2) + abs (b1 - b2)) / 765,0
Isso lhe dará uma pontuação entre 0,0 e 1,0. Quanto menor, mais difícil é distinguir duas cores.
Deve ser óbvio, mas por uma questão de completude: os valores de r, g, b devem ser convertidos primeiro em um número de ponto flutuante e supõe-se que seu valor máximo seja 255.
fonte