├── CollectShapeData └── CollectShapeData.pde ├── LICENSE ├── README.md └── shapeclassifier_ml5 ├── index.html ├── model ├── model.json ├── model.weights.bin └── model_meta.json └── sketch.js /CollectShapeData/CollectShapeData.pde: -------------------------------------------------------------------------------- 1 | void setup() { 2 | size(256, 256); 3 | } 4 | 5 | void draw() { 6 | 7 | for (int i = 0; i < 3; i++) { 8 | background(255); 9 | noFill(); 10 | strokeWeight(8); 11 | color c = color(random(128), random(128), random(128)); 12 | stroke(c); 13 | translate(width/2, height/2); 14 | float x = random(-32, 32); 15 | float y = random(-32, 32); 16 | float r = random(24, 72); 17 | if (i == 0) { 18 | circle(x, y, r*2); 19 | saveFrame("data/circle####.png"); 20 | } else if (i == 1) { 21 | rectMode(CENTER); 22 | square(x, y, r*2); 23 | saveFrame("data/square####.png"); 24 | } else if (i == 2) { 25 | triangle(x-r, y+r, x, y-r, x+r, y+r); 26 | saveFrame("data/triangle####.png"); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Daniel Shiffman 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ShapeClassifierCNN 2 | test code for new tutorial 3 | -------------------------------------------------------------------------------- /shapeclassifier_ml5/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Neural Network 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |

Convolutional Neural Network

13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /shapeclassifier_ml5/model/model.json: -------------------------------------------------------------------------------- 1 | {"modelTopology":{"class_name":"Sequential","config":{"name":"sequential_1","layers":[{"class_name":"Conv2D","config":{"filters":8,"kernel_initializer":{"class_name":"VarianceScaling","config":{"scale":1,"mode":"fan_in","distribution":"normal","seed":null}},"kernel_regularizer":null,"kernel_constraint":null,"kernel_size":[5,5],"strides":[1,1],"padding":"valid","data_format":"channels_last","dilation_rate":[1,1],"activation":"relu","use_bias":true,"bias_initializer":{"class_name":"Zeros","config":{}},"bias_regularizer":null,"activity_regularizer":null,"bias_constraint":null,"name":"conv2d_Conv2D1","trainable":true,"batch_input_shape":[null,128,128,4],"dtype":"float32"}},{"class_name":"MaxPooling2D","config":{"pool_size":[2,2],"padding":"valid","strides":[2,2],"data_format":"channels_last","name":"max_pooling2d_MaxPooling2D1","trainable":true}},{"class_name":"Conv2D","config":{"filters":16,"kernel_initializer":{"class_name":"VarianceScaling","config":{"scale":1,"mode":"fan_in","distribution":"normal","seed":null}},"kernel_regularizer":null,"kernel_constraint":null,"kernel_size":[5,5],"strides":[1,1],"padding":"valid","data_format":"channels_last","dilation_rate":[1,1],"activation":"relu","use_bias":true,"bias_initializer":{"class_name":"Zeros","config":{}},"bias_regularizer":null,"activity_regularizer":null,"bias_constraint":null,"name":"conv2d_Conv2D2","trainable":true}},{"class_name":"MaxPooling2D","config":{"pool_size":[2,2],"padding":"valid","strides":[2,2],"data_format":"channels_last","name":"max_pooling2d_MaxPooling2D2","trainable":true}},{"class_name":"Flatten","config":{"name":"flatten_Flatten1","trainable":true}},{"class_name":"Dense","config":{"units":3,"activation":"softmax","use_bias":true,"kernel_initializer":{"class_name":"VarianceScaling","config":{"scale":1,"mode":"fan_in","distribution":"normal","seed":null}},"bias_initializer":{"class_name":"Zeros","config":{}},"kernel_regularizer":null,"bias_regularizer":null,"activity_regularizer":null,"kernel_constraint":null,"bias_constraint":null,"name":"dense_Dense1","trainable":true}}]},"keras_version":"tfjs-layers 1.7.2","backend":"tensor_flow.js"},"weightsManifest":[{"paths":["./model.weights.bin"],"weights":[{"name":"conv2d_Conv2D1/kernel","shape":[5,5,4,8],"dtype":"float32"},{"name":"conv2d_Conv2D1/bias","shape":[8],"dtype":"float32"},{"name":"conv2d_Conv2D2/kernel","shape":[5,5,8,16],"dtype":"float32"},{"name":"conv2d_Conv2D2/bias","shape":[16],"dtype":"float32"},{"name":"dense_Dense1/kernel","shape":[13456,3],"dtype":"float32"},{"name":"dense_Dense1/bias","shape":[3],"dtype":"float32"}]}]} -------------------------------------------------------------------------------- /shapeclassifier_ml5/model/model.weights.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shiffman/ShapeClassifierCNN/d2e839ec9c360a6255ca11689c492f65eb941c2b/shapeclassifier_ml5/model/model.weights.bin -------------------------------------------------------------------------------- /shapeclassifier_ml5/model/model_meta.json: -------------------------------------------------------------------------------- 1 | {"inputUnits":[128,128,4],"outputUnits":3,"inputs":{"image":{"dtype":"array","min":0,"max":255}},"outputs":{"label":{"dtype":"string","min":0,"max":1,"uniqueValues":["circle","square","triangle"],"legend":{"circle":[1,0,0],"square":[0,1,0],"triangle":[0,0,1]}}},"isNormalized":true} -------------------------------------------------------------------------------- /shapeclassifier_ml5/sketch.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019 ml5 2 | // 3 | // This software is released under the MIT License. 4 | // https://opensource.org/licenses/MIT 5 | 6 | /* === 7 | ml5 Example 8 | Image classification using Convolutional Neural Network 9 | This example uses a callback pattern to create the classifier 10 | === */ 11 | 12 | const circles = []; 13 | const squares = []; 14 | const triangles = []; 15 | 16 | let resultsP; 17 | let shapeClassifier; 18 | let video; 19 | 20 | // function preload() { 21 | // for (let i = 0; i < 100; i++) { 22 | // circles[i] = loadImage(`data/circle${nf(i+1,4,0)}.png`) 23 | // squares[i] = loadImage(`data/square${nf(i+1,4,0)}.png`) 24 | // triangles[i] = loadImage(`data/triangle${nf(i+1,4,0)}.png`) 25 | // console.log(`data/circle${nf(i+1,4,0)}.png`); 26 | // } 27 | 28 | // } 29 | 30 | let canvas; 31 | let graphics; 32 | 33 | function setup() { 34 | canvas = createCanvas(128, 128); 35 | video = createCapture(VIDEO); 36 | video.size(128, 128); 37 | video.hide(); 38 | //graphics = createGraphics(128, 128); 39 | //pixelDensity(1); 40 | const options = { 41 | inputs: [128, 128, 4], 42 | task: 'imageClassification', 43 | debug: true, 44 | }; 45 | resultsP = createP(''); 46 | 47 | // construct the neural network 48 | shapeClassifier = ml5.neuralNetwork(options); 49 | shapeClassifier.load({ 50 | model: 'model/model.json', 51 | metadata: 'model/model_meta.json', 52 | weights: 'model/model.weights.bin' 53 | }, modelLoaded); 54 | 55 | // add data 56 | // for (let i = 0; i < circles.length; i += 1) { 57 | // shapeClassifier.addData({ image: circles[i] }, { label: "circle"}); 58 | // shapeClassifier.addData({ image: squares[i] }, { label: "square"}); 59 | // shapeClassifier.addData({ image: triangles[i] }, { label: "triangle"}); 60 | // } 61 | 62 | // normalize data 63 | // shapeClassifier.normalizeData(); 64 | 65 | // shapeClassifier.train({ epochs: 50 }, finishedTraining); 66 | } 67 | 68 | function draw() { 69 | image(video, 0,0,width,height); 70 | } 71 | 72 | function modelLoaded() { 73 | shapeClassifier.classify({ image: video }, gotResults); 74 | 75 | // graphics.translate(width/2,height/2); 76 | // noLoop(); 77 | // graphics.background(255); 78 | // graphics.noFill(); 79 | // graphics.strokeWeight(8); 80 | // const c = color(random(128), random(128), random(128)); 81 | // graphics.stroke(c); 82 | // const x = random(-16, 16); 83 | // const y = random(-16, 16); 84 | // const r = random(12, 48); 85 | // graphics.rectMode(CENTER); 86 | // graphics.square(x, y, r*2); 87 | 88 | // graphics.loadPixels(); 89 | // shapeClassifier.classify({ image: video }, gotResults); 90 | 91 | // image(graphics, 0, 0); 92 | } 93 | 94 | 95 | 96 | // function finishedTraining() { 97 | // console.log('finished training'); 98 | // // method 1: you can pass in an object with a matching key and the p5 image 99 | // } 100 | 101 | function gotResults(err, results) { 102 | if (err) { 103 | console.log(err); 104 | return; 105 | } 106 | console.log(results); 107 | const percent = 100 * results[0].confidence; 108 | resultsP.html(`${results[0].label} ${nf(percent, 2, 1)}%`); 109 | shapeClassifier.classify({ image: video }, gotResults); 110 | 111 | } 112 | --------------------------------------------------------------------------------