• 纯js实现人脸识别眨眨眼张张嘴案例——ccv.js


    if (parallable === undefined) {
        var parallable = function (file, funct) {
            parallable.core[funct.toString()] = funct().core;
            return function () {
                var i;
                var async, worker_num, params;
                if (arguments.length > 1) {
                    async = arguments[arguments.length - 2];
                    worker_num = arguments[arguments.length - 1];
                    params = new Array(arguments.length - 2);
                    for (i = 0; i < arguments.length - 2; i++)
                        params[i] = arguments[i];
                } else {
                    async = arguments[0].async;
                    worker_num = arguments[0].worker;
                    params = arguments[0];
                    delete params["async"];
                    delete params["worker"];
                    params = [params];
                }
                var scope = { "shared" : {} };
                var ctrl = funct.apply(scope, params);
                if (async) {
                    return function (complete, error) {
                        var executed = 0;
                        var outputs = new Array(worker_num);
                        var inputs = ctrl.pre.apply(scope, [worker_num]);
                        /* sanitize scope shared because for Chrome/WebKit, worker only support JSONable data */
                        for (i in scope.shared)
                            /* delete function, if any */
                            if (typeof scope.shared[i] == "function")
                                delete scope.shared[i];
                            /* delete DOM object, if any */
                            else if (scope.shared[i].tagName !== undefined)
                                delete scope.shared[i];
                        for (i = 0; i < worker_num; i++) {
                            var worker = new Worker(file);
                            worker.onmessage = (function (i) {
                                return function (event) {
                                    outputs[i] = (typeof event.data == "string") ? JSON.parse(event.data) : event.data;
                                    executed++;
                                    if (executed == worker_num)
                                        complete(ctrl.post.apply(scope, [outputs]));
                                }
                            })(i);
                            var msg = { "input" : inputs[i],
                                        "name" : funct.toString(),
                                        "shared" : scope.shared,
                                        "id" : i,
                                        "worker" : params.worker_num };
                            try {
                                worker.postMessage(msg);
                            } catch (e) {
                                worker.postMessage(JSON.stringify(msg));
                            }
                        }
                    }
                } else {
                    return ctrl.post.apply(scope, [[ctrl.core.apply(scope, [ctrl.pre.apply(scope, [1])[0], 0, 1])]]);
                }
            }
        };
        parallable.core = {};
    }
    
    function get_named_arguments(params, names) {
        if (params.length > 1) {
            var new_params = {};
            for (var i = 0; i < names.length; i++)
                new_params[names[i]] = params[i];
            return new_params;
        } else if (params.length == 1) {
            return params[0];
        } else {
            return {};
        }
    }
    
    var ccv = {
        pre : function (image) {
            if (image.tagName.toLowerCase() == "img") {
                var canvas = document.createElement("canvas");
                document.body.appendChild(image);
                canvas.width = image.offsetWidth;
                canvas.style.width = image.offsetWidth.toString() + "px";
                canvas.height = image.offsetHeight;
                canvas.style.height = image.offsetHeight.toString() + "px";
                document.body.removeChild(image);
                var ctx = canvas.getContext("2d");
                ctx.drawImage(image, 0, 0);
                return canvas;
            }
            return image;
        },
    
        grayscale : function (canvas) {
            var ctx = canvas.getContext("2d");
            var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
            var data = imageData.data;
            var pix1, pix2, pix = canvas.width * canvas.height * 4;
            while (pix > 0)
                data[pix -= 4] = data[pix1 = pix + 1] = data[pix2 = pix + 2] = (data[pix] * 0.3 + data[pix1] * 0.59 + data[pix2] * 0.11);
            ctx.putImageData(imageData, 0, 0);
            return canvas;
        },
    
        array_group : function (seq, gfunc) {
            var i, j;
            var node = new Array(seq.length);
            for (i = 0; i < seq.length; i++)
                node[i] = {"parent" : -1,
                           "element" : seq[i],
                           "rank" : 0};
            for (i = 0; i < seq.length; i++) {
                if (!node[i].element)
                    continue;
                var root = i;
                while (node[root].parent != -1)
                    root = node[root].parent;
                for (j = 0; j < seq.length; j++) {
                    if( i != j && node[j].element && gfunc(node[i].element, node[j].element)) {
                        var root2 = j;
    
                        while (node[root2].parent != -1)
                            root2 = node[root2].parent;
    
                        if(root2 != root) {
                            if(node[root].rank > node[root2].rank)
                                node[root2].parent = root;
                            else {
                                node[root].parent = root2;
                                if (node[root].rank == node[root2].rank)
                                node[root2].rank++;
                                root = root2;
                            }
    
                            /* compress path from node2 to the root: */
                            var temp, node2 = j;
                            while (node[node2].parent != -1) {
                                temp = node2;
                                node2 = node[node2].parent;
                                node[temp].parent = root;
                            }
    
                            /* compress path from node to the root: */
                            node2 = i;
                            while (node[node2].parent != -1) {
                                temp = node2;
                                node2 = node[node2].parent;
                                node[temp].parent = root;
                            }
                        }
                    }
                }
            }
            var idx = new Array(seq.length);
            var class_idx = 0;
            for(i = 0; i < seq.length; i++) {
                j = -1;
                var node1 = i;
                if(node[node1].element) {
                    while (node[node1].parent != -1)
                        node1 = node[node1].parent;
                    if(node[node1].rank >= 0)
                        node[node1].rank = ~class_idx++;
                    j = ~node[node1].rank;
                }
                idx[i] = j;
            }
            return {"index" : idx, "cat" : class_idx};
        },
    
        detect_objects : parallable("ccv.js", function (canvas, cascade, interval, min_neighbors) {
            if (this.shared !== undefined) {
                var params = get_named_arguments(arguments, ["canvas", "cascade", "interval", "min_neighbors"]);
                this.shared.canvas = params.canvas;
                this.shared.interval = params.interval;
                this.shared.min_neighbors = params.min_neighbors;
                this.shared.cascade = params.cascade;
                this.shared.scale = Math.pow(2, 1 / (params.interval + 1));
                this.shared.next = params.interval + 1;
                this.shared.scale_upto = Math.floor(Math.log(Math.min(params.canvas.width / params.cascade.width, params.canvas.height / params.cascade.height)) / Math.log(this.shared.scale));
                var i;
                for (i = 0; i < this.shared.cascade.stage_classifier.length; i++)
                    this.shared.cascade.stage_classifier[i].orig_feature = this.shared.cascade.stage_classifier[i].feature;
            }
            function pre(worker_num) {
                var canvas = this.shared.canvas;
                var interval = this.shared.interval;
                var scale = this.shared.scale;
                var next = this.shared.next;
                var scale_upto = this.shared.scale_upto;
                var pyr = new Array((scale_upto + next * 2) * 4);
                var ret = new Array((scale_upto + next * 2) * 4);
                pyr[0] = canvas;
                ret[0] = { "width" : pyr[0].width,
                           "height" : pyr[0].height,
                           "data" : pyr[0].getContext("2d").getImageData(0, 0, pyr[0].width, pyr[0].height).data };
                var i;
                for (i = 1; i <= interval; i++) {
                    pyr[i * 4] = document.createElement("canvas");
                    pyr[i * 4].width = Math.floor(pyr[0].width / Math.pow(scale, i));
                    pyr[i * 4].height = Math.floor(pyr[0].height / Math.pow(scale, i));
                    pyr[i * 4].getContext("2d").drawImage(pyr[0], 0, 0, pyr[0].width, pyr[0].height, 0, 0, pyr[i * 4].width, pyr[i * 4].height);
                    ret[i * 4] = { "width" : pyr[i * 4].width,
                                   "height" : pyr[i * 4].height,
                                   "data" : pyr[i * 4].getContext("2d").getImageData(0, 0, pyr[i * 4].width, pyr[i * 4].height).data };
                }
                for (i = next; i < scale_upto + next * 2; i++) {
                    pyr[i * 4] = document.createElement("canvas");
                    pyr[i * 4].width = Math.floor(pyr[i * 4 - next * 4].width / 2);
                    pyr[i * 4].height = Math.floor(pyr[i * 4 - next * 4].height / 2);
                    pyr[i * 4].getContext("2d").drawImage(pyr[i * 4 - next * 4], 0, 0, pyr[i * 4 - next * 4].width, pyr[i * 4 - next * 4].height, 0, 0, pyr[i * 4].width, pyr[i * 4].height);
                    ret[i * 4] = { "width" : pyr[i * 4].width,
                                   "height" : pyr[i * 4].height,
                                   "data" : pyr[i * 4].getContext("2d").getImageData(0, 0, pyr[i * 4].width, pyr[i * 4].height).data };
                }
                for (i = next * 2; i < scale_upto + next * 2; i++) {
                    pyr[i * 4 + 1] = document.createElement("canvas");
                    pyr[i * 4 + 1].width = Math.floor(pyr[i * 4 - next * 4].width / 2);
                    pyr[i * 4 + 1].height = Math.floor(pyr[i * 4 - next * 4].height / 2);
                    pyr[i * 4 + 1].getContext("2d").drawImage(pyr[i * 4 - next * 4], 1, 0, pyr[i * 4 - next * 4].width - 1, pyr[i * 4 - next * 4].height, 0, 0, pyr[i * 4 + 1].width - 2, pyr[i * 4 + 1].height);
                    ret[i * 4 + 1] = { "width" : pyr[i * 4 + 1].width,
                                       "height" : pyr[i * 4 + 1].height,
                                       "data" : pyr[i * 4 + 1].getContext("2d").getImageData(0, 0, pyr[i * 4 + 1].width, pyr[i * 4 + 1].height).data };
                    pyr[i * 4 + 2] = document.createElement("canvas");
                    pyr[i * 4 + 2].width = Math.floor(pyr[i * 4 - next * 4].width / 2);
                    pyr[i * 4 + 2].height = Math.floor(pyr[i * 4 - next * 4].height / 2);
                    pyr[i * 4 + 2].getContext("2d").drawImage(pyr[i * 4 - next * 4], 0, 1, pyr[i * 4 - next * 4].width, pyr[i * 4 - next * 4].height - 1, 0, 0, pyr[i * 4 + 2].width, pyr[i * 4 + 2].height - 2);
                    ret[i * 4 + 2] = { "width" : pyr[i * 4 + 2].width,
                                       "height" : pyr[i * 4 + 2].height,
                                       "data" : pyr[i * 4 + 2].getContext("2d").getImageData(0, 0, pyr[i * 4 + 2].width, pyr[i * 4 + 2].height).data };
                    pyr[i * 4 + 3] = document.createElement("canvas");
                    pyr[i * 4 + 3].width = Math.floor(pyr[i * 4 - next * 4].width / 2);
                    pyr[i * 4 + 3].height = Math.floor(pyr[i * 4 - next * 4].height / 2);
                    pyr[i * 4 + 3].getContext("2d").drawImage(pyr[i * 4 - next * 4], 1, 1, pyr[i * 4 - next * 4].width - 1, pyr[i * 4 - next * 4].height - 1, 0, 0, pyr[i * 4 + 3].width - 2, pyr[i * 4 + 3].height - 2);
                    ret[i * 4 + 3] = { "width" : pyr[i * 4 + 3].width,
                                       "height" : pyr[i * 4 + 3].height,
                                       "data" : pyr[i * 4 + 3].getContext("2d").getImageData(0, 0, pyr[i * 4 + 3].width, pyr[i * 4 + 3].height).data };
                }
                return [ret];
            };
    
            function core(pyr, id, worker_num) {
                var cascade = this.shared.cascade;
                var interval = this.shared.interval;
                var scale = this.shared.scale;
                var next = this.shared.next;
                var scale_upto = this.shared.scale_upto;
                var i, j, k, x, y, q;
                var scale_x = 1, scale_y = 1;
                var dx = [0, 1, 0, 1];
                var dy = [0, 0, 1, 1];
                var seq = [];
                for (i = 0; i < scale_upto; i++) {
                    var qw = pyr[i * 4 + next * 8].width - Math.floor(cascade.width / 4);
                    var qh = pyr[i * 4 + next * 8].height - Math.floor(cascade.height / 4);
                    var step = [pyr[i * 4].width * 4, pyr[i * 4 + next * 4].width * 4, pyr[i * 4 + next * 8].width * 4];
                    var paddings = [pyr[i * 4].width * 16 - qw * 16,
                                    pyr[i * 4 + next * 4].width * 8 - qw * 8,
                                    pyr[i * 4 + next * 8].width * 4 - qw * 4];
                    for (j = 0; j < cascade.stage_classifier.length; j++) {
                        var orig_feature = cascade.stage_classifier[j].orig_feature;
                        var feature = cascade.stage_classifier[j].feature = new Array(cascade.stage_classifier[j].count);
                        for (k = 0; k < cascade.stage_classifier[j].count; k++) {
                            feature[k] = {"size" : orig_feature[k].size,
                                          "px" : new Array(orig_feature[k].size),
                                          "pz" : new Array(orig_feature[k].size),
                                          "nx" : new Array(orig_feature[k].size),
                                          "nz" : new Array(orig_feature[k].size)};
                            for (q = 0; q < orig_feature[k].size; q++) {
                                feature[k].px[q] = orig_feature[k].px[q] * 4 + orig_feature[k].py[q] * step[orig_feature[k].pz[q]];
                                feature[k].pz[q] = orig_feature[k].pz[q];
                                feature[k].nx[q] = orig_feature[k].nx[q] * 4 + orig_feature[k].ny[q] * step[orig_feature[k].nz[q]];
                                feature[k].nz[q] = orig_feature[k].nz[q];
                            }
                        }
                    }
                    for (q = 0; q < 4; q++) {
                        var u8 = [pyr[i * 4].data, pyr[i * 4 + next * 4].data, pyr[i * 4 + next * 8 + q].data];
                        var u8o = [dx[q] * 8 + dy[q] * pyr[i * 4].width * 8, dx[q] * 4 + dy[q] * pyr[i * 4 + next * 4].width * 4, 0];
                        for (y = 0; y < qh; y++) {
                            for (x = 0; x < qw; x++) {
                                var sum = 0;
                                var flag = true;
                                for (j = 0; j < cascade.stage_classifier.length; j++) {
                                    sum = 0;
                                    var alpha = cascade.stage_classifier[j].alpha;
                                    var feature = cascade.stage_classifier[j].feature;
                                    for (k = 0; k < cascade.stage_classifier[j].count; k++) {
                                        var feature_k = feature[k];
                                        var p, pmin = u8[feature_k.pz[0]][u8o[feature_k.pz[0]] + feature_k.px[0]];
                                        var n, nmax = u8[feature_k.nz[0]][u8o[feature_k.nz[0]] + feature_k.nx[0]];
                                        if (pmin <= nmax) {
                                            sum += alpha[k * 2];
                                        } else {
                                            var f, shortcut = true;
                                            for (f = 0; f < feature_k.size; f++) {
                                                if (feature_k.pz[f] >= 0) {
                                                    p = u8[feature_k.pz[f]][u8o[feature_k.pz[f]] + feature_k.px[f]];
                                                    if (p < pmin) {
                                                        if (p <= nmax) {
                                                            shortcut = false;
                                                            break;
                                                        }
                                                        pmin = p;
                                                    }
                                                }
                                                if (feature_k.nz[f] >= 0) {
                                                    n = u8[feature_k.nz[f]][u8o[feature_k.nz[f]] + feature_k.nx[f]];
                                                    if (n > nmax) {
                                                        if (pmin <= n) {
                                                            shortcut = false;
                                                            break;
                                                        }
                                                        nmax = n;
                                                    }
                                                }
                                            }
                                            sum += (shortcut) ? alpha[k * 2 + 1] : alpha[k * 2];
                                        }
                                    }
                                    if (sum < cascade.stage_classifier[j].threshold) {
                                        flag = false;
                                        break;
                                    }
                                }
                                if (flag) {
                                    seq.push({"x" : (x * 4 + dx[q] * 2) * scale_x,
                                              "y" : (y * 4 + dy[q] * 2) * scale_y,
                                              "width" : cascade.width * scale_x,
                                              "height" : cascade.height * scale_y,
                                              "neighbor" : 1,
                                              "confidence" : sum});
                                }
                                u8o[0] += 16;
                                u8o[1] += 8;
                                u8o[2] += 4;
                            }
                            u8o[0] += paddings[0];
                            u8o[1] += paddings[1];
                            u8o[2] += paddings[2];
                        }
                    }
                    scale_x *= scale;
                    scale_y *= scale;
                }
                return seq;
            };
    
            function post(seq) {
                var min_neighbors = this.shared.min_neighbors;
                var cascade = this.shared.cascade;
                var interval = this.shared.interval;
                var scale = this.shared.scale;
                var next = this.shared.next;
                var scale_upto = this.shared.scale_upto;
                var i, j;
                for (i = 0; i < cascade.stage_classifier.length; i++)
                    cascade.stage_classifier[i].feature = cascade.stage_classifier[i].orig_feature;
                seq = seq[0];
                if (!(min_neighbors > 0))
                    return seq;
                else {
                    var result = ccv.array_group(seq, function (r1, r2) {
                        var distance = Math.floor(r1.width * 0.25 + 0.5);
    
                        return r2.x <= r1.x + distance &&
                               r2.x >= r1.x - distance &&
                               r2.y <= r1.y + distance &&
                               r2.y >= r1.y - distance &&
                               r2.width <= Math.floor(r1.width * 1.5 + 0.5) &&
                               Math.floor(r2.width * 1.5 + 0.5) >= r1.width;
                    });
                    var ncomp = result.cat;
                    var idx_seq = result.index;
                    var comps = new Array(ncomp + 1);
                    for (i = 0; i < comps.length; i++)
                        comps[i] = {"neighbors" : 0,
                                    "x" : 0,
                                    "y" : 0,
                                    "width" : 0,
                                    "height" : 0,
                                    "confidence" : 0};
    
                    // count number of neighbors
                    for(i = 0; i < seq.length; i++)
                    {
                        var r1 = seq[i];
                        var idx = idx_seq[i];
    
                        if (comps[idx].neighbors == 0)
                            comps[idx].confidence = r1.confidence;
    
                        ++comps[idx].neighbors;
    
                        comps[idx].x += r1.x;
                        comps[idx].y += r1.y;
                        comps[idx].width += r1.width;
                        comps[idx].height += r1.height;
                        comps[idx].confidence = Math.max(comps[idx].confidence, r1.confidence);
                    }
    
                    var seq2 = [];
                    // calculate average bounding box
                    for(i = 0; i < ncomp; i++)
                    {
                        var n = comps[i].neighbors;
                        if (n >= min_neighbors)
                            seq2.push({"x" : (comps[i].x * 2 + n) / (2 * n),
                                       "y" : (comps[i].y * 2 + n) / (2 * n),
                                       "width" : (comps[i].width * 2 + n) / (2 * n),
                                       "height" : (comps[i].height * 2 + n) / (2 * n),
                                       "neighbors" : comps[i].neighbors,
                                       "confidence" : comps[i].confidence});
                    }
    
                    var result_seq = [];
                    // filter out small face rectangles inside large face rectangles
                    for(i = 0; i < seq2.length; i++)
                    {
                        var r1 = seq2[i];
                        var flag = true;
                        for(j = 0; j < seq2.length; j++)
                        {
                            var r2 = seq2[j];
                            var distance = Math.floor(r2.width * 0.25 + 0.5);
    
                            if(i != j &&
                               r1.x >= r2.x - distance &&
                               r1.y >= r2.y - distance &&
                               r1.x + r1.width <= r2.x + r2.width + distance &&
                               r1.y + r1.height <= r2.y + r2.height + distance &&
                               (r2.neighbors > Math.max(3, r1.neighbors) || r1.neighbors < 3))
                            {
                                flag = false;
                                break;
                            }
                        }
    
                        if(flag)
                            result_seq.push(r1);
                    }
                    return result_seq;
                }
            };
            return { "pre" : pre, "core" : core, "post" : post };
        })
    }
    
    onmessage = function (event) {
        var data = (typeof event.data == "string") ? JSON.parse(event.data) : event.data;
        var scope = { "shared" : data.shared };
        var result = parallable.core[data.name].apply(scope, [data.input, data.id, data.worker]);
        try {
            postMessage(result);
        } catch (e) {
            postMessage(JSON.stringify(result));
        }
    }
    
  • 相关阅读:
    SeaweedFS上手使用指南
    XyTalk企业即时通讯IM开始开源
    大数据项目相关技术栈(Hadoop周边技术)
    Hive SQL基础操作
    Applet Mode
    快速开始
    NetBeans启动Tomcat报“'127.0.0.1' 不是内部或外部命令”启动失败的解决办法
    运行带distance field的Hiero
    Game Loop的几种实现方式
    20150408
  • 原文地址:https://www.cnblogs.com/a1111/p/12816009.html
Copyright © 2020-2023  润新知