Permalink
Browse files

Added a 2D convolution matrix implementation and added some filters t…

…hat can

use it.
  • Loading branch information...
1 parent d3620e2 commit 0afab618109f2e1826c39f61ac16db821fe90e63 Adam Harvey committed Jan 16, 2010
View
@@ -12,7 +12,7 @@ lint: dist/cine.js
dist:
test -d dist || mkdir dist
-dist/cine.js: src/cinejs.js src/util.js src/Player.js src/filters/BrightnessContrast.js src/filters/ColourLevel.js src/filters/GaussianBlur.js src/filters/Greyscale.js src/filters/Invert.js src/filters/Posterise.js | dist
+dist/cine.js: src/cinejs.js src/util.js src/Player.js src/filters/BrightnessContrast.js src/filters/ColourLevel.js src/filters/EdgeDetect.js src/filters/Emboss.js src/filters/GaussianBlur.js src/filters/Greyscale.js src/filters/Invert.js src/filters/Posterise.js src/filters/Smooth.js | dist
cat $^ > $@
dist/cine.js.gz: dist/cine.js
View
@@ -0,0 +1,49 @@
+/* Copyright © 2009-2010 Adam Harvey
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+
+/**
+ * Constructs a quick and dirty edge detection filter.
+ *
+ * @class An edge detection filter.
+ */
+cinejs.filters.EdgeDetect = function () {
+ this.filter = [
+ [-1.0, 0.0, -1.0],
+ [0.0, 4.0, 0.0],
+ [-1.0, 0.0, -1.0]
+ ];
+};
+
+/**
+ * The processing function for the edge detection filter.
+ *
+ * This is based on gdImageEdgeDetectQuick() by Pierre Joye.
+ *
+ * @param {ImageData} frame
+ * @param {HTMLCanvasElement} canvas
+ */
+cinejs.filters.EdgeDetect.prototype.processFrame = function (frame, canvas) {
+ cinejs.util.applyConvolution(frame, canvas.width, canvas.height, this.filter, 1, 127);
+};
+
+
+// vim: set cin noet ts=8 sw=8:
View
@@ -0,0 +1,49 @@
+/* Copyright © 2009-2010 Adam Harvey
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+
+/**
+ * Constructs an embossing filter.
+ *
+ * @class An embossing filter.
+ */
+cinejs.filters.Emboss = function () {
+ this.filter = [
+ [1.5, 0.0, 0.0],
+ [0.0, 0.0, 0.0],
+ [0.0, 0.0, -1.5]
+ ];
+};
+
+/**
+ * The processing function for the embossing filter.
+ *
+ * This is based on gdImageEmboss() by Pierre Joye.
+ *
+ * @param {ImageData} frame
+ * @param {HTMLCanvasElement} canvas
+ */
+cinejs.filters.Emboss.prototype.processFrame = function (frame, canvas) {
+ cinejs.util.applyConvolution(frame, canvas.width, canvas.height, this.filter, 1, 127);
+};
+
+
+// vim: set cin noet ts=8 sw=8:
@@ -58,6 +58,11 @@ cinejs.filters.GaussianBlur.prototype.processFrame = function (frame, canvas) {
var row;
var col;
+ /* JFTR: This function predates the existence of
+ * cinejs.util.applyConvolution(), but I'm going to keep this
+ * implementation anyway, simply because we're not doing a generic 2D
+ * convolution; we're doing a pair of 1D convolutions instead. */
+
// Column-wise blurring.
for (row = 0; row < canvas.height; row++) {
for (col = 0; col < canvas.width; col++) {
View
@@ -0,0 +1,54 @@
+/* Copyright © 2009-2010 Adam Harvey
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+
+/**
+ * Constructs a smoothing filter.
+ *
+ * @param {number} weight The weight of the smoothing to apply. Lower values
+ * (toward 0) imply more smoothing.
+ *
+ * @class A smoothing filter.
+ */
+cinejs.filters.Smooth = function (weight) {
+ this.filter = [
+ [1.0, 1.0, 1.0],
+ [1.0, weight, 1.0],
+ [1.0, 1.0, 1.0]
+ ];
+
+ this.divisor = weight + 8;
+};
+
+/**
+ * The processing function for the embossing filter.
+ *
+ * This is based on gdImageSmooth() by Pierre Joye.
+ *
+ * @param {ImageData} frame
+ * @param {HTMLCanvasElement} canvas
+ */
+cinejs.filters.Smooth.prototype.processFrame = function (frame, canvas) {
+ cinejs.util.applyConvolution(frame, canvas.width, canvas.height, this.filter, this.divisor, 0);
+};
+
+
+// vim: set cin noet ts=8 sw=8:
View
@@ -27,6 +27,68 @@ cinejs.util = {internal: {}};
/**
+ * Apply an arbitrarily sized convolution filter.
+ *
+ * This is (a very loose) port of the libgd gdImageConvolution() function as
+ * written by Pierre Joye.
+ *
+ * @param {ImageData} frame The image data to filter.
+ * @param {number} width The width of the image data.
+ * @param {number} height The height of the image data.
+ * @param {array} filter A 2D array describing the filter. This is not checked
+ * at all for speed reasons, so make sure this is a
+ * square 2D array before passing it in; preferably upon
+ * initial calculation.
+ * @param {number} divisor The amount to divide the resultant pixel values by.
+ * This is typically the sum of the filter elements,
+ * and can (and should) be pre-calculated.
+ * @param {number} offset An offset to apply to the resulting subpixel values.
+ * @return void
+ */
+cinejs.util.applyConvolution = function (frame, width, height, filter, divisor, offset) {
+ var filterSize = Math.floor(filter.length / 2);
+
+ /* We have to keep the previous image data around for the entire
+ * convolution. */
+ var newImage = [];
+
+ for (var y = 0; y < height; y++) {
+ for (var x = 0; x < width; x++) {
+ var red = 0;
+ var green = 0;
+ var blue = 0;
+
+ for (var j = 0; j < filter.length; j++) {
+ var sourceRow = Math.min(Math.max(y + j - filterSize, 0), height - 1);
+ for (var i = 0; i < filter.length; i++) {
+ var sourceCol = Math.min(Math.max(x + i - filterSize, 0), width - 1);
+ var frameIndex = 4 * ((width * sourceRow) + sourceCol);
+
+ red += filter[j][i] * frame.data[frameIndex + 0];
+ green += filter[j][i] * frame.data[frameIndex + 1];
+ blue += filter[j][i] * frame.data[frameIndex + 2];
+ }
+ }
+
+ red /= divisor;
+ green /= divisor;
+ blue /= divisor;
+
+ newImage.push(Math.min(Math.max(0, red + offset), 255));
+ newImage.push(Math.min(Math.max(0, green + offset), 255));
+ newImage.push(Math.min(Math.max(0, blue + offset), 255));
+ newImage.push(255);
+ }
+ }
+
+ // Copy the new image into the ImageData array.
+ for (var i = 0; i < newImage.length; i++) {
+ frame.data[i] = newImage[i];
+ }
+};
+
+
+/**
* Converts a HSV colour value to RGB.
*
* @param {number} hue The hue in degrees. Expected to be in the range 0-360,
View
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Edge Detection filter test</title>
+ <link rel="stylesheet" type="text/css" href="test.css" />
+ <script type="text/javascript" src="../dist/cine.js"></script>
+ <script type="text/javascript" src="test.js"></script>
+ <script type="text/javascript" src="EdgeDetect.js"></script>
+ </head>
+ <body>
+ <h1>Edge Detection filter test</h1>
+
+ <div id="source-container">
+ <h2>Source</h2>
+
+ <video id="source" width="320" height="240">
+ <source src="test.ogv" type="video/ogg" />
+ <source src="test.mp4" type="video/mp4" />
+ </video>
+ </div>
+
+ <div id="intermediate-container">
+ <h2>Intermediate</h2>
+
+ <canvas id="intermediate" width="320" height="240" />
+ </div>
+
+ <div id="destination-container">
+ <h2>Destination</h2>
+
+ <canvas id="destination" width="320" height="240" />
+ </div>
+
+ <a id="play" href="#">Play!</a>
+
+ <span id="fps">?? FPS</span>
+ </body>
+</html>
View
@@ -0,0 +1,28 @@
+/* Copyright © 2009-2010 Adam Harvey
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+
+window.onload = function () {
+ cinejs.test(new cinejs.filters.EdgeDetect());
+};
+
+
+// vim: set cin noet ts=8 sw=8:
View
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Emboss filter test</title>
+ <link rel="stylesheet" type="text/css" href="test.css" />
+ <script type="text/javascript" src="../dist/cine.js"></script>
+ <script type="text/javascript" src="test.js"></script>
+ <script type="text/javascript" src="Emboss.js"></script>
+ </head>
+ <body>
+ <h1>Emboss filter test</h1>
+
+ <div id="source-container">
+ <h2>Source</h2>
+
+ <video id="source" width="320" height="240">
+ <source src="test.ogv" type="video/ogg" />
+ <source src="test.mp4" type="video/mp4" />
+ </video>
+ </div>
+
+ <div id="intermediate-container">
+ <h2>Intermediate</h2>
+
+ <canvas id="intermediate" width="320" height="240" />
+ </div>
+
+ <div id="destination-container">
+ <h2>Destination</h2>
+
+ <canvas id="destination" width="320" height="240" />
+ </div>
+
+ <a id="play" href="#">Play!</a>
+
+ <span id="fps">?? FPS</span>
+ </body>
+</html>
View
@@ -0,0 +1,28 @@
+/* Copyright © 2009-2010 Adam Harvey
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+
+window.onload = function () {
+ cinejs.test(new cinejs.filters.Emboss());
+};
+
+
+// vim: set cin noet ts=8 sw=8:
Oops, something went wrong.

0 comments on commit 0afab61

Please sign in to comment.