Permalink
Browse files

First step in converting from HSV range color-matching algorithm to R…

…GB-distance-to-centers algorithm for determining sticker colors.
  • Loading branch information...
1 parent bb68142 commit a89cd714f9ede29ac063a664bd3f92e43988d680 @marcn committed Dec 28, 2011
Showing with 110 additions and 44 deletions.
  1. +81 −22 js/color_match.js
  2. +4 −0 js/cube.js
  3. +2 −5 js/main.js
  4. +7 −2 js/test.js
  5. +16 −15 test.html
View
@@ -1,6 +1,3 @@
-var LEFT_EDGE_X = 55;
-var TOP_EDGE_Y = 15;
-var CUBIE_SIZE = 70;
var FACE_TO_HEX = {
"F": "#fe9722", // orange
@@ -12,17 +9,79 @@ var FACE_TO_HEX = {
" ": "#acb5bc" // empty
};
+/**
+ * Calculate the distance between two RGB values. If the RGB for the test color is deemed to be
+ * washed out, additional distance is added to the result because it will not provide reliable results.
+ * @param test array of [r, g, b]
+ * @param base array of [r, g, b]
+ */
+function distanceBetween(test, base) {
+ var dist = Math.sqrt(
+ (test[0]-base[0]) * (test[0]-base[0]) +
+ (test[1]-base[1]) * (test[1]-base[1]) +
+ (test[2]-base[2]) * (test[2]-base[2]));
+ if (test[0] > 245 && test[1] > 245 && test[2] > 245) {
+ dist += 300;
+ }
+ return dist
+}
+
+/**
+ * Return array of RGB values for each blob as sampled from it's center region
+ */
+function getBlobColors(blobs, snapShotSelector, sampleSelector, graphSelector) {
+ var graphContext = null;
+ if (graphSelector) {
+ graphContext = $(graphSelector).get(0).getContext("2d");
+ }
-function colorScan(size, log, snapShotSelector, sampleSelector, matchSelector, graphSelector) {
- var blobs = [];
- for (var y = 0; y < 3; y++) {
- for (var x = 0; x < 3; x++) {
- var xpos = CUBIE_SIZE * x + LEFT_EDGE_X + (CUBIE_SIZE / 2) - (size / 2);
- var ypos = CUBIE_SIZE * y + TOP_EDGE_Y + (CUBIE_SIZE / 2) - (size / 2);
- blobs.push(new Blob(xpos, ypos, CUBIE_SIZE, CUBIE_SIZE));
+ var results = [];
+ var svh = [];
+ var maxSat = 0;
+ var context = $(snapShotSelector).get(0).getContext("2d");
+ var i = 0;
+ blobs.sort(Blob.sortFunction);
+ _.each(blobs, function(blob) {
+ var size = blob.width / 2; // sample size is half of blob size
+ var xpos = blob.x - (size / 2);
+ var ypos = blob.y - (size / 2);
+ var rgb = computeRGB(xpos, ypos, size, context);
+ results.push(rgb);
+ var hsv = RGB2HSV(rgb);
+ var cssColor = rgbToCss(rgb);
+ // Update sampled color in sample selector div
+ if (sampleSelector) {
+ $("div", sampleSelector).eq(i).removeClass("color_grey").css("background-color", cssColor);
+ }
+ // Mark solid squares in sample area of snapshot canvas
+ context.fillStyle = cssColor;
+ context.fillRect(xpos, ypos, size, size);
+ context.fillStyle = "black";
+ context.strokeRect(xpos, ypos, size, size);
+
+ svh.push([hsv[1], hsv[0], cssColor]);
+ maxSat = Math.max(maxSat, hsv[1]);
+ i++;
+ });
+
+ // saturation vs. hue graph
+ if (graphContext) {
+ if ($("#cleargraph").is(":checked")) {
+ graphContext.fillStyle = "#cccccc";
+ graphContext.fillRect(0, 0, 220, 370);
+ }
+ while (svh.length > 0) {
+ var sv = svh.pop();
+ graphContext.beginPath();
+ graphContext.fillStyle = sv[2];
+ graphContext.arc(((sv[0] / maxSat * 200)) + 5, 360 - sv[1] + 5, 5, 0, Math.PI + (Math.PI * 3) / 2, false);
+ graphContext.fill();
+ graphContext.fillStyle = "black";
+ graphContext.stroke();
}
}
- return colorScanBlobs(blobs, log, snapShotSelector, sampleSelector, matchSelector, graphSelector);
+
+ return results;
}
function colorScanBlobs(blobs, log, snapShotSelector, sampleSelector, matchSelector, graphSelector) {
@@ -41,11 +100,12 @@ function colorScanBlobs(blobs, log, snapShotSelector, sampleSelector, matchSelec
var size = blob.width / 2; // sample size is half of blob size
var xpos = blob.x - (size / 2);
var ypos = blob.y - (size / 2);
- var hsv = computeHsv(xpos, ypos, size, context);
+ var rgb = computeRGB(xpos, ypos, size, context);
+ var hsv = RGB2HSV(rgb);
var hue = hsv[0];
var sat = hsv[1];
var val = hsv[2];
- var cssColor = hsvToCss(hsv);
+ var cssColor = rgbToCss(rgb);
if (log) {
console.log(hsv, cssColor);
}
@@ -106,13 +166,13 @@ function colorScanBlobs(blobs, log, snapShotSelector, sampleSelector, matchSelec
}
/**
- * Compute the average HSV value for a square centered at the given coordinates
+ * Compute the average RGB value for a square centered at the given coordinates
* @param x
* @param y
* @param size
* @param context
*/
-function computeHsv(x, y, size, context) {
+function computeRGB(x, y, size, context) {
var image = context.getImageData(0, 0, 320, 240);
var xmin = Math.floor(x) - Math.floor(size / 2);
var xmax = Math.floor(x) + Math.floor(size / 2);
@@ -127,19 +187,18 @@ function computeHsv(x, y, size, context) {
bsum += image.data[((yy * (image.width * 4)) + (xx * 4)) + 2];
}
}
- return RGB2HSV(rsum / total, gsum / total, bsum / total);
+ return [rsum / total, gsum / total, bsum / total];
}
-function hsvToCss(hsv) {
- var rgb = HSV2RGB(hsv[0], hsv[1], hsv[2]);
+function rgbToCss(rgb) {
return "rgb(" + Math.round(rgb[0]) + "," + Math.round(rgb[1]) + "," + Math.round(rgb[2]) + ")";
}
-function RGB2HSV(r, g, b) {
- r = r / 255;
- g = g / 255;
- b = b / 255;
+function RGB2HSV(rgb) {
+ r = rgb[0] / 255;
+ g = rgb[1] / 255;
+ b = rgb[2] / 255;
var minVal = Math.min(r, g, b);
var maxVal = Math.max(r, g, b);
var delta = maxVal - minVal;
View
@@ -30,6 +30,10 @@ function print_message(str) {
}
function solve() {
+ if (cube == solvedCube) {
+ onSolutionFound("");
+ return;
+ }
function solFcn(set_sol) {
solution = set_sol;
print_solution(set_sol);
View
@@ -289,7 +289,8 @@ function showSolvingUI() {
}
function onSolutionFound(str) {
- solutionSteps = str.trim().split(" ");
+ str = str.trim();
+ solutionSteps = str.length > 0 ? str.split(" ") : [];
step = 0;
var now = new Date().getTime();
console.log("now - solveStartTime = ", now - solveStartTime);
@@ -319,10 +320,6 @@ function showCurrentSolutionStep() {
audio.currentTime = 0;
audio.play();
}
- setTimeout(function() {
- // hack because we don't get an onload event from the audio tag
- $("audio").get(0).play();
- }, 500);
return;
}
var s = solutionSteps[step];
View
@@ -53,7 +53,12 @@ function onCaptureComplete() {
if (logging) console.timeEnd("blobDetect");
if (blobs.length == 9) {
- colorScanBlobs(blobs, logging, "#snapshot", "#sampleCube", "#calcCube", "#satvshue");
+ var colors = getBlobColors(blobs, "#snapshot", "#sampleCube", "#satvshue");
+ var cubies = $("#sampleCube .cubie");
+ for (var i=0; i < 9; i++) {
+ var dist = distanceBetween(colors[i], colors[4]);
+ cubies.eq(i).text(Math.round(dist));
+ }
}
if (cont) {
var now = new Date().getTime();
@@ -94,7 +99,7 @@ $(window).load(function() {
resetCanvas();
var graphContext = document.getElementById("satvshue").getContext("2d");
graphContext.fillStyle = "#cccccc";
- graphContext.fillRect(0, 0, 110, 370);
+ graphContext.fillRect(0, 0, 220, 370);
swfobject.embedSWF("webcam/webcam.swf", "webcam", "320", "240", "10", "swfobject/expressInstall.swf", null,
{ allowScriptAccess: "always", wmode: "transparent" });
});
View
@@ -12,8 +12,20 @@
<script type="text/javascript" src="js/test.js"></script>
<link rel="stylesheet" href="style.css">
<style>
+ span, div {
+ font-family: arial,sans-serif;
+ font-size: 14px;
+ }
.cubie {
- width:48px;height:48px;float:left;border:1px solid white;
+ font-size: 12px;
+ color: white;
+ text-shadow: black 1px 1px;
+ width: 48px;
+ height: 33px;
+ float: left;
+ border: 1px solid white;
+ text-align: center;
+ padding-top: 15px;
}
</style>
</head>
@@ -31,22 +43,11 @@
<div class="cubie color_grey"></div>
<div class="cubie color_grey"></div>
</div>
- <span>Estimated Face Color</span>
- <div id="calcCube" style="width:150px; height:150px;">
- <div class="cubie color_grey"></div>
- <div class="cubie color_grey"></div>
- <div class="cubie color_grey"></div>
- <div class="cubie color_grey"></div>
- <div class="cubie color_grey"></div>
- <div class="cubie color_grey"></div>
- <div class="cubie color_grey"></div>
- <div class="cubie color_grey"></div>
- <div class="cubie color_grey"></div>
- </div>
+ <span>(dist. from center color)</span>
</div>
- <div style="float:right; width:130px; padding-right: 20px; color:#ffffff;">
+ <div style="float:right; width:230px; padding-right: 20px; color:#ffffff;">
<span style="color:#ffffff">Saturation vs. Hue</span>
- <canvas id="satvshue" width="110" height="370"></canvas>
+ <canvas id="satvshue" width="220" height="370"></canvas>
<br>
<input type="checkbox" id="cleargraph" name="cleargraph" checked> Clear before sample
</div>

0 comments on commit a89cd71

Please sign in to comment.