source

사람과 구별할 수 있는 랜덤 컬러 생성

manysource 2023. 10. 17. 20:23

사람과 구별할 수 있는 랜덤 컬러 생성

javascript에서 hex로 색상을 무작위로 생성하려고 합니다.

하지만 생성된 색들은 거의 서로 구분이 되지 않습니다.
개선할 방법이 있습니까?


제가 사용하고 있는 코드는 다음과 같습니다.

function randomColor(){
   var allowed = "ABCDEF0123456789", S = "#";
    
   while(S.length < 7){
       S += allowed.charAt(Math.floor((Math.random()*16)+1));
   }
   return S;
}

HSLHSV 컬러 모델에 대해 들은 것이 있는데 제 코드로 작동이 안 됩니다.

최대로 다른 색을 선택하는 가장 쉬운 방법은 RGB 대신 HSL 값을 사용한 다음 Hue를 조작하는 것입니다. Hue는 0에서 360까지의 값을 가지고 있고 (0은 빨간색이고 360도 마찬가지입니다.)

10개의 구별 가능한 색이 필요하다면 360을 10으로 나눈 후 지수(제로 기준)에 값을 곱하여 개별 색을 선택할 수 있습니다.다음은 색상을 선택할 수 있는 기능의 예입니다.

function selectColor(colorNum, colors){
    if (colors < 1) colors = 1; // defaults to one color - avoid divide by zero
    return "hsl(" + (colorNum * (360 / colors) % 360) + ",100%,50%)";
}

이렇게 하면 색인을 랜덤화하여 색상 선택을 랜덤화할 수 있지만 색상은 항상 동일한 팔레트에 있습니다.

이렇게 하면 10개의 팔레트에서 랜덤 색상을 선택할 수 있습니다.

var color = selectColor(Math.floor(Math.random() * 10), 10);

이것도 마찬가지입니다.

var color = selectColor(Math.floor(Math.random() * 999), 10);

또는 팔레트에서 특정 색상을 선택할 수 있습니다(예: 13개의 팔레트 중 9번째 색상(인덱스 8):

var color = selectColor(8, 13);

여기 가지고 놀 수 있는 피들이 있습니다. http://jsfiddle.net/2UE2B/

2020-02-23 업데이트:

그래서 오늘 저는 이와 같은 문제에 대한 해결책이 필요했습니다.여기서 이 답변을 구글링하면서 (알아, SO에서 물건을 찾는 매우 이상한 방법) 골든 앵글 개념을 우연히 발견했습니다.이는 위의 예를 더욱 사소하게 만들 것이며, 미리 결정된 수의 색상을 제공할 필요가 없을 것입니다.

function selectColor(number) {
  const hue = number * 137.508; // use golden angle approximation
  return `hsl(${hue},50%,75%)`;
}

이것은 @netoperator-wibby의 질문에 대답합니다.

Example

제가 이 파티에 많이 늦었다는 것을 알지만, 다른 프로젝트에 대비되는 랜덤 색상 세트를 생성하기 위해 좀 더 정교한 함수를 작성했습니다.그것들은 (적어도 어느 정도) 매력적이고 (미리 정의된 색상에 기초하지 않음) 정말 무작위적이지만, 제 코드는 다른 응답들보다 조금 더 복잡합니다 (따라서 그것은 단지 기본을 얻기 위한 것이 아닙니다).

페이지에 두 가지 이상의 임의 색상이 있고 두 가지 색상이 너무 유사하지 않은지 확인하려는 사용자를 위한 것입니다.

피들

var generateRandomColors=function(number){
/*
This generates colors using the following algorithm:
Each time you create a color:
    Create a random, but attractive, color{
        Red, Green, and Blue are set to random luminosity.
        One random value is reduced significantly to prevent grayscale.
        Another is increased by a random amount up to 100%.
        They are mapped to a random total luminosity in a medium-high range (bright but not white).
    }
    Check for similarity to other colors{
        Check if the colors are very close together in value.
        Check if the colors are of similar hue and saturation.
        Check if the colors are of similar luminosity.
        If the random color is too similar to another,
        and there is still a good opportunity to change it:
            Change the hue of the random color and try again.
    }
    Output array of all colors generated
*/
    //if we've passed preloaded colors and they're in hex format
    if(typeof(arguments[1])!='undefined'&&arguments[1].constructor==Array&&arguments[1][0]&&arguments[1][0].constructor!=Array){
        for(var i=0;i<arguments[1].length;i++){ //for all the passed colors
            var vals = /^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(arguments[1][i]); //get RGB values
            arguments[1][i]=[parseInt(vals[1], 16),parseInt(vals[2], 16),parseInt(vals[3], 16)]; //and convert them to base 10
        }
    }
    var loadedColors=typeof(arguments[1])=='undefined'?[]:arguments[1],//predefine colors in the set
        number=number+loadedColors.length,//reset number to include the colors already passed
        lastLoadedReduction=Math.floor(Math.random()*3),//set a random value to be the first to decrease
        rgbToHSL=function(rgb){//converts [r,g,b] into [h,s,l]
            var r=rgb[0],g=rgb[1],b=rgb[2],cMax=Math.max(r,g,b),cMin=Math.min(r,g,b),delta=cMax-cMin,l=(cMax+cMin)/2,h=0,s=0;if(delta==0)h=0;else if(cMax==r)h=60*((g-b)/delta%6);else if(cMax==g)h=60*((b-r)/delta+2);else h=60*((r-g)/delta+4);if(delta==0)s=0;else s=delta/(1-Math.abs(2*l-1));return[h,s,l]
        },hslToRGB=function(hsl){//converts [h,s,l] into [r,g,b]
            var h=hsl[0],s=hsl[1],l=hsl[2],c=(1-Math.abs(2*l-1))*s,x=c*(1-Math.abs(h/60%2-1)),m=l-c/2,r,g,b;if(h<60){r=c;g=x;b=0}else if(h<120){r=x;g=c;b=0}else if(h<180){r=0;g=c;b=x}else if(h<240){r=0;g=x;b=c}else if(h<300){r=x;g=0;b=c}else{r=c;g=0;b=x}return[r,g,b]
        },shiftHue=function(rgb,degree){//shifts [r,g,b] by a number of degrees
            var hsl=rgbToHSL(rgb); //convert to hue/saturation/luminosity to modify hue
            hsl[0]+=degree; //increment the hue
            if(hsl[0]>360){ //if it's too high
                hsl[0]-=360 //decrease it mod 360
            }else if(hsl[0]<0){ //if it's too low
                hsl[0]+=360 //increase it mod 360
            }
            return hslToRGB(hsl); //convert back to rgb
        },differenceRecursions={//stores recursion data, so if all else fails we can use one of the hues already generated
            differences:[],//used to calculate the most distant hue
            values:[]//used to store the actual colors
        },fixDifference=function(color){//recursively asserts that the current color is distinctive
            if(differenceRecursions.values.length>23){//first, check if this is the 25th recursion or higher. (can we try any more unique hues?)
                //if so, get the biggest value in differences that we have and its corresponding value
                var ret=differenceRecursions.values[differenceRecursions.differences.indexOf(Math.max.apply(null,differenceRecursions.differences))];
                differenceRecursions={differences:[],values:[]}; //then reset the recursions array, because we're done now
                return ret; //and then return up the recursion chain
            } //okay, so we still have some hues to try.
            var differences=[]; //an array of the "difference" numbers we're going to generate.
            for(var i=0;i<loadedColors.length;i++){ //for all the colors we've generated so far
                var difference=loadedColors[i].map(function(value,index){ //for each value (red,green,blue)
                    return Math.abs(value-color[index]) //replace it with the difference in that value between the two colors
                }),sumFunction=function(sum,value){ //function for adding up arrays
                    return sum+value
                },sumDifference=difference.reduce(sumFunction), //add up the difference array
                loadedColorLuminosity=loadedColors[i].reduce(sumFunction), //get the total luminosity of the already generated color
                currentColorLuminosity=color.reduce(sumFunction), //get the total luminosity of the current color
                lumDifference=Math.abs(loadedColorLuminosity-currentColorLuminosity), //get the difference in luminosity between the two
                //how close are these two colors to being the same luminosity and saturation?
                differenceRange=Math.max.apply(null,difference)-Math.min.apply(null,difference),
                luminosityFactor=50, //how much difference in luminosity the human eye should be able to detect easily
                rangeFactor=75; //how much difference in luminosity and saturation the human eye should be able to dect easily
                if(luminosityFactor/(lumDifference+1)*rangeFactor/(differenceRange+1)>1){ //if there's a problem with range or luminosity
                    //set the biggest difference for these colors to be whatever is most significant
                    differences.push(Math.min(differenceRange+lumDifference,sumDifference));
                }
                differences.push(sumDifference); //otherwise output the raw difference in RGB values
            }
            var breakdownAt=64, //if you're generating this many colors or more, don't try so hard to make unique hues, because you might fail.
            breakdownFactor=25, //how much should additional colors decrease the acceptable difference
            shiftByDegrees=15, //how many degrees of hue should we iterate through if this fails
            acceptableDifference=250, //how much difference is unacceptable between colors
            breakVal=loadedColors.length/number*(number-breakdownAt), //break down progressively (if it's the second color, you can still make it a unique hue)
            totalDifference=Math.min.apply(null,differences); //get the color closest to the current color
            if(totalDifference>acceptableDifference-(breakVal<0?0:breakVal)*breakdownFactor){ //if the current color is acceptable
                differenceRecursions={differences:[],values:[]} //reset the recursions object, because we're done
                return color; //and return that color
            } //otherwise the current color is too much like another
            //start by adding this recursion's data into the recursions object
            differenceRecursions.differences.push(totalDifference);
            differenceRecursions.values.push(color);
            color=shiftHue(color,shiftByDegrees); //then increment the color's hue
            return fixDifference(color); //and try again
        },color=function(){ //generate a random color
            var scale=function(x){ //maps [0,1] to [300,510]
                return x*210+300 //(no brighter than #ff0 or #0ff or #f0f, but still pretty bright)
            },randVal=function(){ //random value between 300 and 510
                return Math.floor(scale(Math.random()))
            },luminosity=randVal(), //random luminosity
                red=randVal(), //random color values
                green=randVal(), //these could be any random integer but we'll use the same function as for luminosity
                blue=randVal(),
                rescale, //we'll define this later
                thisColor=[red,green,blue], //an array of the random values
                /*
                #ff0 and #9e0 are not the same colors, but they are on the same range of the spectrum, namely without blue.
                Try to choose colors such that consecutive colors are on different ranges of the spectrum.
                This shouldn't always happen, but it should happen more often then not.
                Using a factor of 2.3, we'll only get the same range of spectrum 15% of the time.
                */
                valueToReduce=Math.floor(lastLoadedReduction+1+Math.random()*2.3)%3, //which value to reduce
                /*
                Because 300 and 510 are fairly close in reference to zero,
                increase one of the remaining values by some arbitrary percent betweeen 0% and 100%,
                so that our remaining two values can be somewhat different.
                */
                valueToIncrease=Math.floor(valueToIncrease+1+Math.random()*2)%3, //which value to increase (not the one we reduced)
                increaseBy=Math.random()+1; //how much to increase it by
            lastLoadedReduction=valueToReduce; //next time we make a color, try not to reduce the same one
            thisColor[valueToReduce]=Math.floor(thisColor[valueToReduce]/16); //reduce one of the values
            thisColor[valueToIncrease]=Math.ceil(thisColor[valueToIncrease]*increaseBy) //increase one of the values
            rescale=function(x){ //now, rescale the random numbers so that our output color has the luminosity we want
                return x*luminosity/thisColor.reduce(function(a,b){return a+b}) //sum red, green, and blue to get the total luminosity
            };
            thisColor=fixDifference(thisColor.map(function(a){return rescale(a)})); //fix the hue so that our color is recognizable
            if(Math.max.apply(null,thisColor)>255){ //if any values are too large
                rescale=function(x){ //rescale the numbers to legitimate hex values
                    return x*255/Math.max.apply(null,thisColor)
                }
                thisColor=thisColor.map(function(a){return rescale(a)});
            }
            return thisColor;
        };
    for(var i=loadedColors.length;i<number;i++){ //Start with our predefined colors or 0, and generate the correct number of colors.
        loadedColors.push(color().map(function(value){ //for each new color
            return Math.round(value) //round RGB values to integers
        }));
    }
    //then, after you've made all your colors, convert them to hex codes and return them.
    return loadedColors.map(function(color){
        var hx=function(c){ //for each value
            var h=c.toString(16);//then convert it to a hex code
            return h.length<2?'0'+h:h//and assert that it's two digits
        }
        return "#"+hx(color[0])+hx(color[1])+hx(color[2]); //then return the hex code
    });
}

예를 들어, 제가 그렇게 하지는 않지만, 이것은 또한 한 세트에 새로운 구별되고 임의적인 색을 추가하는 데 사용될 수 있습니다.

generateRandomColors(1,generateRandomColors(10))

jquery.color.js 플러그인에 나열된 것과 같은 고정된 색상 집합을 사용할 수 있습니다.

jquery.color.js 플러그인의 색상 목록:

Colors = {};
Colors.names = {
    aqua: "#00ffff",
    azure: "#f0ffff",
    beige: "#f5f5dc",
    black: "#000000",
    blue: "#0000ff",
    brown: "#a52a2a",
    cyan: "#00ffff",
    darkblue: "#00008b",
    darkcyan: "#008b8b",
    darkgrey: "#a9a9a9",
    darkgreen: "#006400",
    darkkhaki: "#bdb76b",
    darkmagenta: "#8b008b",
    darkolivegreen: "#556b2f",
    darkorange: "#ff8c00",
    darkorchid: "#9932cc",
    darkred: "#8b0000",
    darksalmon: "#e9967a",
    darkviolet: "#9400d3",
    fuchsia: "#ff00ff",
    gold: "#ffd700",
    green: "#008000",
    indigo: "#4b0082",
    khaki: "#f0e68c",
    lightblue: "#add8e6",
    lightcyan: "#e0ffff",
    lightgreen: "#90ee90",
    lightgrey: "#d3d3d3",
    lightpink: "#ffb6c1",
    lightyellow: "#ffffe0",
    lime: "#00ff00",
    magenta: "#ff00ff",
    maroon: "#800000",
    navy: "#000080",
    olive: "#808000",
    orange: "#ffa500",
    pink: "#ffc0cb",
    purple: "#800080",
    violet: "#800080",
    red: "#ff0000",
    silver: "#c0c0c0",
    white: "#ffffff",
    yellow: "#ffff00"
};

나머지는 단순히 자바스크립트 객체에서 랜덤 속성을 선택하는 것입니다.

Colors.random = function() {
    var result;
    var count = 0;
    for (var prop in this.names)
        if (Math.random() < 1/++count)
           result = prop;
    return result;
};

으로.Colors.random()인간 readable 색깔을 보여줄 수도 있을 겁니다저는 심지어 아래의 예시를 실행시켰습니다.

(function(){
    Colors = {};
    Colors.names = {
        aqua: "#00ffff",
        azure: "#f0ffff",
        beige: "#f5f5dc",
        black: "#000000",
        blue: "#0000ff",
        brown: "#a52a2a",
        cyan: "#00ffff",
        darkblue: "#00008b",
        darkcyan: "#008b8b",
        darkgrey: "#a9a9a9",
        darkgreen: "#006400",
        darkkhaki: "#bdb76b",
        darkmagenta: "#8b008b",
        darkolivegreen: "#556b2f",
        darkorange: "#ff8c00",
        darkorchid: "#9932cc",
        darkred: "#8b0000",
        darksalmon: "#e9967a",
        darkviolet: "#9400d3",
        fuchsia: "#ff00ff",
        gold: "#ffd700",
        green: "#008000",
        indigo: "#4b0082",
        khaki: "#f0e68c",
        lightblue: "#add8e6",
        lightcyan: "#e0ffff",
        lightgreen: "#90ee90",
        lightgrey: "#d3d3d3",
        lightpink: "#ffb6c1",
        lightyellow: "#ffffe0",
        lime: "#00ff00",
        magenta: "#ff00ff",
        maroon: "#800000",
        navy: "#000080",
        olive: "#808000",
        orange: "#ffa500",
        pink: "#ffc0cb",
        purple: "#800080",
        violet: "#800080",
        red: "#ff0000",
        silver: "#c0c0c0",
        white: "#ffffff",
        yellow: "#ffff00"
    };
    Colors.random = function() {
        var result;
        var count = 0;
        for (var prop in this.names)
            if (Math.random() < 1/++count)
               result = prop;
        return { name: result, rgb: this.names[result]};
    };
    var $placeholder = $(".placeholder");
    $placeholder.click(function(){
        var color = Colors.random();
        $placeholder.css({'background-color': color.rgb});
        $("#color").html("It's " + color.name);
    });
})();
.placeholder {
    width: 150px;
    height: 150px;
    border: 1px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="placeholder"></div>
<span id="color">Click the square above.</span>

시도해 보기:

function getRandomColor() {
    var letters = '0123456789ABCDEF'.split('');
    var color = '#';
    for (var i = 0; i < 6; i++ ) {
        color += letters[Math.round(Math.random() * 15)];
    }
    return color;
}

실제로 보기: http://jsfiddle.net/3wjgG/1/

당신이 말하는 것은 임의의 색을 생성하고 싶지 않다는 것이고, 다른 색을 생성하고 싶다는 것입니다.
어떻게 하는지에 대한 좋은 자습서는 여기 http://krazydad.com/tutorials/makecolors.php 에서 찾을 수 있습니다.

사용자가 비반복 색상을 생성하는 방법을 설명하는 자습서의 관련 코드를 사용하여 이 작업을 수행했습니다.

http://jsfiddle.net/rGL52/

튜토리얼 코드와 다른 점은 makegradient() 함수가 나중에 페이지에 마음대로 적용할 수 있는 색상 배열을 반환한다는 것입니다.

무작위로 색을 생성하는 경우, 저는 다음과 같은 간단한 것을 선택하는 경향이 있습니다.

​function randomColor () {
    var max = 0xffffff;
    return '#' + Math.round( Math.random() * max ).toString( 16 );
}
​

형체를 알아볼 수 없다는 게 무슨 뜻인지 잘 모르겠어요.이 방법은 사용자 지정을 많이 제공하지는 않지만, 적어도 숫자가 너무 가볍거나 너무 어둡지 않도록 쉽게 해줍니다.

생성된 색 사이에 간격을 크게 만들고 싶다면 허용되는 문자 수를 줄이는 방법을 시도해 볼 수 있습니다.저는 예전에 그런 방법을 사용한 적이 있습니다.0369cf캐릭터의 풀로서 말입니다.이것을 중복 체크와 결합하면 더 구별 가능한 색상을 제공할 수 있을 뿐만 아니라,#fff3글자 구문입니다.

이 메서드를 사용하도록 수정된 원래 기능은 다음과 같습니다.

function randomColor(){
    var allowed = "0369cf".split( '' ), s = "#";
    while ( s.length < 4 ) {
       s += allowed.splice( Math.floor( ( Math.random() * allowed.length ) ), 1 );
    }
    return s;
}

Unique color swatches

제가 작성하는 새로운 강의를 위해 오늘 이 문제를 해결해야 했기 때문에, 제 해결책은 다음과 같습니다.

function getUniqueColor(n) {
    const rgb = [0, 0, 0];
  
  for (let i = 0; i < 24; i++) {
    rgb[i%3] <<= 1;
    rgb[i%3] |= n & 0x01;
    n >>= 1;
  }
  
  return '#' + rgb.reduce((a, c) => (c > 0x0f ? c.toString(16) : '0' + c.toString(16)) + a, '')
}

입력된 숫자의 비트를 RGB 값을 통해 거꾸로 "퍼뜨립니다.완벽하지는 않지만 코드가 콤팩트하고 인접한 색상을 구분할 수 있습니다.음정은 여기 있습니다.

모든 대답에 동의해요 여기서 뭘 기대하는지는 잘 모르겠어요

이것은 css 요소에 대한 rgb(r, g, b) 출력과 hex 출력 중에서 선택할 수 있는 가능성입니다.

간단한 예로, 이 초안을 수정하기만 하면 되지만 Firefox에서는 그대로 작동합니다.

<script type="text/javascript">
    //<![CDATA[
        function RndColor(){
        var maximum = 255;
        var minimum = 100;
        var range = maximum - minimum;
        var red = Math.floor(Math.random()*range)+minimum;
        var green = Math.floor(Math.random()*range)+minimum;
        var blue = Math.floor(Math.random()*range)+minimum;
        var redToHex = red.toString(16);
        var greenToHex = green.toString(16);
        var blueToHex = blue.toString(16);
        this.rgbValue = "rgb(" + red + "," + green + "," + blue + ")";
        this.hexValue = "#" + redToHex + "" + greenToHex + "" + blueToHex;
    }
    RndColor.prototype.getRGB = function(){
        return this.rgbValue;
    }
    RndColor.prototype.getHex = function(){
        return this.hexValue;
    }
    //]]>
</script>

그런 다음 아래와 같은 값을 검색할 수 있습니다.

<script type="text/javascript">
//<![CDATA[
    rndCol = new RndColor();
    document.write("<div style = width:150px;height:100px;background-color:" + rndCol.getHex() + ">" + rndCol.getHex() + "</div><br /><br />");
    document.write("<div style = width:150px;height:100px;background-color:" + rndCol.getRGB() + ">" + rndCol.getRGB() + "</div>");
//]]>
</script>

이것이 당신에게 도움이 되기를 바랍니다.안부 전합니다.

HSL의 주요 아이디어를 제공해 주고 골든 앵글을 사용해 준 고란에게 감사드립니다.저는 그의 jfiddle을 복사해서 색깔이 비슷한 부분을 짜내는 새로운 아이디어를 넣었습니다.각도 배열의 점들 사이에 선형 보간을 했습니다.또한, 모든 것이 똑같이 가벼워 보이게 하기 위해, 가벼움을 위해서도 똑같이 했습니다.

generated 20 colors

function makeColor(colorNum, lightness){
    let hues = [0, 20, 30, 40, 50, 60, 80, 120, 160, 190, 210, 230, 260, 290, 330, 360];
    //hues = [...Array(37).keys()].map(x=>x*10);
    let lights = [60, 50, 50, 50, 50, 50, 50, 55, 50, 55, 67, 77, 73, 67, 60, 60];
    let goldenFrac = 0.5 * (3 - Math.sqrt(5));
    let x = (colorNum * goldenFrac % 1.0) * (hues.length - 1);
    //x=colorNum%(hues.length-1); // for point visualisation
    let i = Math.floor(x);
    let f = x % 1.0;
    let hue = (1.0 - f) * hues[i] + f * hues[i + 1];
    let light = (1.0 - f) * lights[i] + f * lights[i + 1];
    return "hsl( " + Math.round(hue * 100) / 100 + ", 100%, "+Math.round(light * 100) / 100+"% )";
}

// TEST CODE
var totalDIVs = 20;
var totalColors = totalDIVs;
for (var i = 0; i < totalDIVs; i++){
    var element = document.createElement('div');
    document.body.appendChild(element);
    var color = makeColor(i);
    element.style.backgroundColor = color;
    element.innerHTML = color + " = " + element.style.backgroundColor;
}

우선 문자열에서 16진수 값을 만드는 이유는 무엇입니까?값에 숫자를 사용한 다음 다음 다음과 같은 것으로 출력합니다.yourNumber.toString(16).

그런 다음, 색상을 더 명확하게 하기 위해 각 색상 구성 요소에 0에서 255 사이의 전체 범위를 사용하지 말고, 10이나 20, 또는 충분히 큰 차이를 만들기 위해 필요한 모든 것을 점프하여 사용하십시오.

저는 SwitchColors.js라는 작은 스크립트를 작성했는데, 여기에서 확인할 수 있습니다: https://github.com/akulmehta/SwitchColors.js

이 스크립트는 더 많은 포화색을 생성하고 밝기를 조절할 수 있습니다.시각적으로 구분 가능한 색상을 생성하지는 않지만, 높은 채도와 밝은 색상을 생성하여 매력적일 수 있습니다.

언급URL : https://stackoverflow.com/questions/10014271/generate-random-color-distinguishable-to-humans