|
|
|
<!DOCTYPE html> |
|
|
|
<html lang="en"> |
|
<head> |
|
<meta charset="utf-8" /> |
|
<title>Image Hulling</title> |
|
<style> |
|
canvas { |
|
position: absolute; |
|
} |
|
|
|
svg { |
|
position: absolute; |
|
} |
|
|
|
#cv-new { |
|
top: 500px; |
|
} |
|
|
|
#cv { |
|
opacity: 0; |
|
} |
|
img { |
|
position: fixed; |
|
top: 0; |
|
left: 600px; |
|
max-width: 500px; |
|
z-index: 99; |
|
} |
|
</style> |
|
</head> |
|
<body> |
|
<img></img> |
|
<canvas id="cv" width="1000" height="500" ></canvas> |
|
<svg width="1000" height="500" ></svg> |
|
|
|
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8" type="text/javascript"></script> |
|
<script src="colornames.js" charset="utf-8" type="text/javascript"></script> |
|
<script src="d3.geom.concaveHull.js" charset="utf-8" type="text/javascript"></script> |
|
|
|
<script type="text/javascript"> |
|
|
|
var gridSize = 3; |
|
var lessDominant = true; |
|
var localColorization = true; |
|
|
|
var canvas = document.getElementById('cv'); |
|
context = canvas.getContext('2d'); |
|
|
|
var img = new Image(); |
|
var rando = 'source' + (parseInt(Math.random() * 6) + 1) + '.jpg'; |
|
|
|
img.src = rando; |
|
|
|
d3.select("img").attr("src", rando) |
|
|
|
img.onload = function () { |
|
d3.select("canvas").attr("width", img.width).attr("height", img.height) |
|
d3.select("svg").attr("width", img.width).attr("height", img.height) |
|
process(img.width, img.height); |
|
}; |
|
|
|
|
|
function process(imageWidth, imageHeight) { |
|
|
|
context.drawImage(img, 0, 0); |
|
var imageData = context.getImageData(0, 0, imageWidth, imageHeight); |
|
|
|
var hslArray = []; |
|
var hslGrid = [[]]; |
|
|
|
var cx = 0; |
|
var cy = 0; |
|
|
|
for (var x = 0; x<imageData.data.length;x = x + 4) { |
|
var r = x; |
|
var g = x + 1; |
|
var b = x + 2; |
|
|
|
var hsl = d3.hsl(d3.rgb(imageData.data[r],imageData.data[g],imageData.data[b],255)); |
|
|
|
var group = "Red"; |
|
var hue = hsl.h; |
|
|
|
if (hsl.l <= .1) { |
|
group = "black" |
|
hsl.h = 360; |
|
} else if (hsl.l >= .9) { |
|
group = "white" |
|
hsl.h = 0; |
|
} else if (hue < 10) { |
|
group = "Red"; |
|
} else if (hue < 20) { |
|
group = "Orange Red"; |
|
} else if (hue < 30) { |
|
group = "Safety Orange"; |
|
} else if (hue < 40) { |
|
group = "Dark Orange"; |
|
} else if (hue < 50) { |
|
group = "Amber"; |
|
} else if (hue < 60) { |
|
group = "Golden Yellow"; |
|
} else if (hue < 70) { |
|
group = "Chartreuse Yellow"; |
|
} else if (hue < 80) { |
|
group = "Electric Lime"; |
|
} else if (hue < 90) { |
|
group = "Spring Bud"; |
|
} else if (hue < 100) { |
|
group = "Bright Green"; |
|
} else if (hue < 110) { |
|
group = "Harlequin"; |
|
} else if (hue < 130) { |
|
group = "Lime"; |
|
} else if (hue < 140) { |
|
group = "Free Speech Green"; |
|
} else if (hue < 160) { |
|
group = "Spring Green"; |
|
} else if (hue < 170) { |
|
group = "Medium Spring Green"; |
|
} else if (hue < 190) { |
|
group = "Aqua"; |
|
} else if (hue < 200) { |
|
group = "Deep Sky Blue"; |
|
} else if (hue < 220) { |
|
group = "Dodger Blue"; |
|
} else if (hue < 250) { |
|
group = "Blue"; |
|
} else if (hue < 260) { |
|
group = "Han Purple"; |
|
} else if (hue < 270) { |
|
group = "Electric Indigo"; |
|
} else if (hue < 290) { |
|
group = "Electric Purple"; |
|
} else if (hue < 300) { |
|
group = "Psychedelic Purple"; |
|
} else if (hue < 310) { |
|
group = "Magenta"; |
|
} else if (hue < 320) { |
|
group = "Hot Magenta"; |
|
} else if (hue < 330) { |
|
group = "Hollywood Cerise"; |
|
} else if (hue < 340) { |
|
group = "Deep Pink"; |
|
} else if (hue < 350) { |
|
group = "Torch Red"; |
|
} |
|
|
|
var hsl = {x: cx, y: cy, hsl: hsl, group: group}; |
|
|
|
hslArray.push(hsl); |
|
hslGrid[cy].push(hsl); |
|
cx = cx + 1; |
|
if (cx === imageWidth) { |
|
cx = 0; |
|
cy = cy + 1; |
|
hslGrid[cy] = []; |
|
} |
|
} |
|
|
|
var data = hslArray.map(d => [d.x, d.y]); |
|
|
|
var canvasWidth = imageWidth; |
|
var canvasHeight = imageHeight; |
|
|
|
var gridX = 0; |
|
|
|
var gridY = 0; |
|
|
|
var compactGrid = []; |
|
|
|
while (gridY < canvasHeight) { |
|
while (gridX < canvasWidth) { |
|
|
|
var stepY = 0; |
|
var stepX = 0; |
|
|
|
var region = []; |
|
|
|
for (x = 0; x<gridSize; x++) { |
|
for (y = 0; y<gridSize; y++) { |
|
if(hslGrid[y + gridY] && hslGrid[y + gridY][x + gridX]) { |
|
region.push(hslGrid[y + gridY][x + gridX]); |
|
} |
|
} |
|
} |
|
|
|
var hue = dominantColor(region.map(d => d.group)); |
|
var color = d3.hsl(hue, d3.mean(region.map(d => d.hsl.s)), d3.mean(region.map(d => d.hsl.l))) |
|
if (hue === undefined) { |
|
css = "none"; |
|
} |
|
else { |
|
css = color.toString(); |
|
} |
|
|
|
cArray = []; |
|
cArray.push(color.h); |
|
cArray.push(color.s); |
|
cArray.push(color.l); |
|
cArray.push(255); |
|
var compactCell = {color: cArray, css: css, x: gridX, y: gridY}; |
|
|
|
compactGrid.push(compactCell); |
|
|
|
gridX = gridX + gridSize; |
|
} |
|
gridX = 0; |
|
gridY = gridY + gridSize; |
|
} |
|
hull = d3.geom.concaveHull().distance(gridSize * 3); |
|
|
|
for (x in colorHash) { |
|
onlyThisColor = compactGrid.filter(d => d.color[0] === colorHash[x]); |
|
var averageSaturation = d3.mean(onlyThisColor.map(d => d.color[1])) |
|
var averageLuminosity = d3.mean(onlyThisColor.map(d => d.color[2])) |
|
|
|
console.log("******************") |
|
console.log(x) |
|
console.log(x === "black" || x === "white" ? x : d3.hsl(colorHash[x], averageSaturation, averageLuminosity).toString()) |
|
console.log(onlyThisColor) |
|
|
|
if (onlyThisColor.length > 3) { |
|
d3.select("svg").append("g") |
|
.attr("transform", "translate(0,0)") |
|
.selectAll("path") |
|
.data(hull(onlyThisColor.map(d => [d.x + (Math.random()), d.y + (Math.random())]))) |
|
.enter().append("path") |
|
.attr("d", function(d) { return "M" + d.join("L") + "Z"; }) |
|
.style("fill-opacity", .9) |
|
.style("fill", x === "black" || x === "white" ? x : d3.hsl(colorHash[x], averageSaturation, averageLuminosity).toString()) |
|
|
|
} |
|
|
|
} |
|
|
|
function dominantColor(colorArray) { |
|
var colorCensus = {}; |
|
var colorLength = colorArray.length; |
|
colorArray.forEach(color => { |
|
colorCensus[color] ? colorCensus[color]++ : colorCensus[color] = 1; |
|
}); |
|
for (x in colorCensus) { |
|
if (colorCensus[x] * 2 >= colorLength) { |
|
return colorHash[x]; |
|
} |
|
} |
|
if (lessDominant) { |
|
var max = 0; |
|
var value = "none"; |
|
for (x in colorCensus) { |
|
if (colorCensus[x] > max) { |
|
value = colorHash[x]; |
|
} |
|
} |
|
} |
|
return value; |
|
} |
|
|
|
|
|
|
|
} |
|
|
|
</script> |
|
</body> |
|
</html> |