색상환 생성 기능 [닫기]
-
08-06-2019 - |
문제
이것은 제가 여러 번 의사 해결을 해봤지만 아직 해결책을 찾지 못한 문제입니다.
문제는 생성 방법을 찾는 것입니다. N
가능한 한 구별할 수 있는 색상 N
매개변수입니다.
해결책
이에 대한 나의 첫 번째 생각은 "서로의 거리를 최대화하는 공간에서 N개의 벡터를 생성하는 방법"이었습니다.
RGB(또는 색상 공간의 기초를 형성하는 데 사용하는 다른 스케일)가 단지 벡터라는 것을 알 수 있습니다.보세요 무작위 포인트 따기.서로 최대화되는 벡터 세트가 있으면 나중에 해시 테이블이나 다른 곳에 저장할 수 있으며 무작위 회전을 수행하여 서로 최대한 떨어져 있는 원하는 모든 색상을 얻을 수 있습니다!
이 문제를 좀 더 생각해 보면 색상을 (0,0,0) → (255,255,255) 사전순으로 선형 방식으로 매핑한 다음 고르게 분포시키는 것이 더 나을 것입니다.
이것이 얼마나 잘 작동할지는 모르겠지만, 이후에는 다음과 같이 말해야 합니다.
n = 10
우리는 16777216개의 색상(256^3)을 가지고 있다는 것을 알고 있습니다.
우리는 사용할 수 있습니다 버클 알고리즘 515 사전순으로 색인된 색상을 찾으려면.오버플로를 방지하고 약간의 속도 향상을 추가하기 위해 알고리즘을 편집해야 할 수도 있습니다.
다른 팁
"지각적으로 균일한" 색상 공간에서 최대한 멀리 있는 색상을 찾는 것이 가장 좋습니다.CIELAB(L*, a*, b* 좌표 사이의 유클리드 거리를 거리 측정법으로 사용) 그런 다음 선택한 색상 공간으로 변환합니다.지각적 균일성은 인간 시각 시스템의 비선형성에 근접하도록 색 공간을 조정함으로써 달성됩니다.
일부 관련 리소스:
컬러브루어 - 지도에서 사용하기 위해 최대한 구별할 수 있도록 설계된 색상 세트입니다.
RGB랜드 탈출:통계 그래픽의 색상 선택 - 상품 생성을 위한 일련의 알고리즘을 설명하는 기술 보고서(예:최대로 구별 가능) 색상은 hcl 색상 공간으로 설정됩니다.
다음은 지정된 광도의 HSL 색상환 주위에 RGB 색상을 균등하게 할당하는 코드입니다.
class cColorPicker
{
public:
void Pick( vector<DWORD>&v_picked_cols, int count, int bright = 50 );
private:
DWORD HSL2RGB( int h, int s, int v );
unsigned char ToRGB1(float rm1, float rm2, float rh);
};
/**
Evenly allocate RGB colors around HSL color wheel
@param[out] v_picked_cols a vector of colors in RGB format
@param[in] count number of colors required
@param[in] bright 0 is all black, 100 is all white, defaults to 50
based on Fig 3 of http://epub.wu-wien.ac.at/dyn/virlib/wp/eng/mediate/epub-wu-01_c87.pdf?ID=epub-wu-01_c87
*/
void cColorPicker::Pick( vector<DWORD>&v_picked_cols, int count, int bright )
{
v_picked_cols.clear();
for( int k_hue = 0; k_hue < 360; k_hue += 360/count )
v_picked_cols.push_back( HSL2RGB( k_hue, 100, bright ) );
}
/**
Convert HSL to RGB
based on http://www.codeguru.com/code/legacy/gdi/colorapp_src.zip
*/
DWORD cColorPicker::HSL2RGB( int h, int s, int l )
{
DWORD ret = 0;
unsigned char r,g,b;
float saturation = s / 100.0f;
float luminance = l / 100.f;
float hue = (float)h;
if (saturation == 0.0)
{
r = g = b = unsigned char(luminance * 255.0);
}
else
{
float rm1, rm2;
if (luminance <= 0.5f) rm2 = luminance + luminance * saturation;
else rm2 = luminance + saturation - luminance * saturation;
rm1 = 2.0f * luminance - rm2;
r = ToRGB1(rm1, rm2, hue + 120.0f);
g = ToRGB1(rm1, rm2, hue);
b = ToRGB1(rm1, rm2, hue - 120.0f);
}
ret = ((DWORD)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16)));
return ret;
}
unsigned char cColorPicker::ToRGB1(float rm1, float rm2, float rh)
{
if (rh > 360.0f) rh -= 360.0f;
else if (rh < 0.0f) rh += 360.0f;
if (rh < 60.0f) rm1 = rm1 + (rm2 - rm1) * rh / 60.0f;
else if (rh < 180.0f) rm1 = rm2;
else if (rh < 240.0f) rm1 = rm1 + (rm2 - rm1) * (240.0f - rh) / 60.0f;
return static_cast<unsigned char>(rm1 * 255);
}
int _tmain(int argc, _TCHAR* argv[])
{
vector<DWORD> myCols;
cColorPicker colpick;
colpick.Pick( myCols, 20 );
for( int k = 0; k < (int)myCols.size(); k++ )
printf("%d: %d %d %d\n", k+1,
( myCols[k] & 0xFF0000 ) >>16,
( myCols[k] & 0xFF00 ) >>8,
( myCols[k] & 0xFF ) );
return 0;
}
색상을 설정하는 순서도 중요한 요소가 아닐까요?
Dillie-Os 아이디어를 사용하는 것처럼 색상을 최대한 혼합해야 합니다.0 64 128 256은 하나부터 다음까지입니다.그러나 바퀴의 0 256 64 128은 더 "떨어져" 있습니다.
이게 말이 돼?
나는 인간의 눈이 4개 미만의 값 차이를 구별할 수 없는 곳을 읽은 적이 있습니다.그래서 이것은 명심해야 할 것입니다.다음 알고리즘은 이를 보상하지 않습니다.
이것이 정확히 원하는 것인지는 모르겠지만 반복되지 않는 색상 값을 무작위로 생성하는 한 가지 방법입니다.
(앞으로 일관되지 않은 의사 코드를 조심하세요)
//colors entered as 0-255 [R, G, B]
colors = []; //holds final colors to be used
rand = new Random();
//assumes n is less than 16,777,216
randomGen(int n){
while (len(colors) < n){
//generate a random number between 0,255 for each color
newRed = rand.next(256);
newGreen = rand.next(256);
newBlue = rand.next(256);
temp = [newRed, newGreen, newBlue];
//only adds new colors to the array
if temp not in colors {
colors.append(temp);
}
}
}
더 나은 가시성을 위해 이를 최적화할 수 있는 한 가지 방법은 각각의 새로운 색상과 배열의 모든 색상 사이의 거리를 비교하는 것입니다.
for item in color{
itemSq = (item[0]^2 + item[1]^2 + item[2]^2])^(.5);
tempSq = (temp[0]^2 + temp[1]^2 + temp[2]^2])^(.5);
dist = itemSq - tempSq;
dist = abs(dist);
}
//NUMBER can be your chosen distance apart.
if dist < NUMBER and temp not in colors {
colors.append(temp);
}
그러나 이 접근 방식은 알고리즘 속도를 크게 저하시킵니다.
또 다른 방법은 무작위성을 폐기하고 체계적으로 4개의 값을 모두 검토하고 위 예에서 배열에 색상을 추가하는 것입니다.
나는 이것이 오래된 게시물이라는 것을 알고 있지만 주제에 대한 PHP 솔루션을 찾는 동안 그것을 발견했고 마침내 간단한 솔루션을 얻었습니다.
function random_color($i = null, $n = 10, $sat = .5, $br = .7) {
$i = is_null($i) ? mt_rand(0,$n) : $i;
$rgb = hsv2rgb(array($i*(360/$n), $sat, $br));
for ($i=0 ; $i<=2 ; $i++)
$rgb[$i] = dechex(ceil($rgb[$i]));
return implode('', $rgb);
}
function hsv2rgb($c) {
list($h,$s,$v)=$c;
if ($s==0)
return array($v,$v,$v);
else {
$h=($h%=360)/60;
$i=floor($h);
$f=$h-$i;
$q[0]=$q[1]=$v*(1-$s);
$q[2]=$v*(1-$s*(1-$f));
$q[3]=$q[4]=$v;
$q[5]=$v*(1-$s*$f);
return(array($q[($i+4)%6]*255,$q[($i+2)%6]*255,$q[$i%6]*255)); //[1]
}
}
따라서 $i가 색상을 식별하고, $n이 가능한 색상 수, $sat가 채도, $br이 밝기를 식별하는 Random_color() 함수를 호출하면 됩니다.
"가장 구별 가능한" 결과를 얻으려면 RGB가 아닌 Lab(또는 다른 지각 선형 색상 공간)과 같은 지각 색상 공간을 사용해야 합니다.또한, 이 공간을 양자화하여 공간의 크기를 줄일 수 있습니다.
가능한 모든 양자화된 항목으로 전체 3D 공간을 생성하고 다음을 사용하여 K-평균 알고리즘을 실행합니다. k=N
.결과 중심/"수단"은 대략적으로 서로 가장 구별 가능해야 합니다.