varccv={pre:function(image){if(image.tagName.toLowerCase()=="img"){varcanvas=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);varctx=canvas.getContext("2d");ctx.drawImage(image,0,0);returncanvas;}returnimage;},grayscale:function(canvas){varctx=canvas.getContext("2d");varimageData=ctx.getImageData(0,0,canvas.width,canvas.height);vardata=imageData.data;varpix1,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);returncanvas;},__get_named_arguments:function(params,names){if(params.length>1){varnew_params={};for(vari=0;i<names.length;i++)new_params[names[i]]=params[i];returnnew_params;}returnparams[0];},__worker_scripts:{},spawn:function(pre,script,params,post,complete,worker_num){varparams=ccv.__get_named_arguments(arguments,["pre","script","params","post","complete","worker_num"]);varworker=newWorker("ccv.js");worker.onmessage=function(event){params.complete(params.post((typeofevent.data=="string")?JSON.parse(event.data):event.data));};varmsg={"data":params.pre(),"script":params.script,"params":params.params,"id":0,"worker_num":params.worker_num};try{worker.postMessage(msg);}catch(e){worker.postMessage(JSON.stringify(msg));}returnworker;},array_group:function(seq,gfunc){vari,j;varnode=newArray(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;varroot=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)){varroot2=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: */vartemp,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;}}}}}varidx=newArray(seq.length);varclass_idx=0;for(i=0;i<seq.length;i++){j=-1;varnode1=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:function(canvas,cascade,interval,min_neighbors,complete,worker_num,setup){varparams=ccv.__get_named_arguments(arguments,["canvas","cascade","interval","min_neighbors","complete","worker_num","setup"]);if(!params.setup){varcascade=params.cascade;varscale=Math.pow(2,1/(params.interval+1));varnext=params.interval+1;varscale_upto=Math.floor(Math.log(Math.min(params.canvas.width/cascade.width,params.canvas.height/cascade.height))/Math.log(scale));}varpre=function(){varpyr=newArray((scale_upto+next*2)*4);varret=newArray((scale_upto+next*2)*4);pyr[0]=params.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};vari;for(i=1;i<=params.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};}for(i=0;i<cascade.stage_classifier.length;i++)cascade.stage_classifier[i].orig_feature=cascade.stage_classifier[i].feature;returnret;};varwork=function(pyr,params,id,worker_num){varcascade=params.cascade;varscale=Math.pow(2,1/(params.interval+1));varnext=params.interval+1;varscale_upto=Math.floor(Math.log(Math.min(pyr[0].width/cascade.width,pyr[0].height/cascade.height))/Math.log(scale));vari,j,k,x,y,q;varscale_x=1,scale_y=1;vardx=[0,1,0,1];vardy=[0,0,1,1];varseq=[];for(i=0;i<scale_upto;i++){varqw=pyr[i*4+next*8].width-Math.floor(cascade.width/4);varqh=pyr[i*4+next*8].height-Math.floor(cascade.height/4);varstep=[pyr[i*4].width*4,pyr[i*4+next*4].width*4,pyr[i*4+next*8].width*4];varpaddings=[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++){varorig_feature=cascade.stage_classifier[j].orig_feature;varfeature=cascade.stage_classifier[j].feature=newArray(cascade.stage_classifier[j].count);for(k=0;k<cascade.stage_classifier[j].count;k++){feature[k]={"size":orig_feature[k].size,"px":newArray(orig_feature[k].size),"pz":newArray(orig_feature[k].size),"nx":newArray(orig_feature[k].size),"nz":newArray(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++){varu8=[pyr[i*4].data,pyr[i*4+next*4].data,pyr[i*4+next*8+q].data];varu8o=[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++){varsum=0;varflag=true;for(j=0;j<cascade.stage_classifier.length;j++){sum=0;varalpha=cascade.stage_classifier[j].alpha;varfeature=cascade.stage_classifier[j].feature;for(k=0;k<cascade.stage_classifier[j].count;k++){varfeature_k=feature[k];varp,pmin=u8[feature_k.pz[0]][u8o[feature_k.pz[0]]+feature_k.px[0]];varn,nmax=u8[feature_k.nz[0]][u8o[feature_k.nz[0]]+feature_k.nx[0]];if(pmin<=nmax){sum+=alpha[k*2];}else{varf,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;}returnseq;};varpost=function(seq){vari,j;for(i=0;i<cascade.stage_classifier.length;i++)cascade.stage_classifier[i].feature=cascade.stage_classifier[i].orig_feature;if(!(params.min_neighbors>0))returnseq;else{varresult=ccv.array_group(seq,function(r1,r2){vardistance=Math.floor(r1.width*0.25+0.5);returnr2.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;});varncomp=result.cat;varidx_seq=result.index;varcomps=newArray(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 neighborsfor(i=0;i<seq.length;i++){varr1=seq[i];varidx=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);}varseq2=[];// calculate average bounding boxfor(i=0;i<ncomp;i++){varn=comps[i].neighbors;if(n>=params.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});}varresult_seq=[];// filter out small face rectangles inside large face rectanglesfor(i=0;i<seq2.length;i++){varr1=seq2[i];varflag=true;for(j=0;j<seq2.length;j++){varr2=seq2[j];vardistance=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);}returnresult_seq;}};if(params.setup){ccv.__worker_scripts.detect_objects=work;}else{if(params.complete===undefined){returnpost(work(pre(),params,0,1));}else{ccv.spawn(pre,"detect_objects",{"cascade":params.cascade,"interval":params.interval,"min_neighbors":params.min_neighbors},post,params.complete,params.worker_num);}}}}onmessage=function(event){vardata=(typeofevent.data=="string")?JSON.parse(event.data):event.data;ccv[data.script]({"setup":true});varresult=ccv.__worker_scripts[data.script](data.data,data.params,data.id,data.worker_num);try{postMessage(result);}catch(e){postMessage(JSON.stringify(result));}}