BVB Source Codes

jsfeat Show jsfeat_imgproc.js Source code

Return Download jsfeat: download jsfeat_imgproc.js Source code - Download jsfeat Source code - Type:.js
  1. /**
  2.  * @author Eugene Zatepyakin / http://inspirit.ru/
  3.  */
  4.  
  5. (function(global) {
  6.     "use strict";
  7.     //
  8.  
  9.     var imgproc = (function() {
  10.  
  11.         var _resample_u8 = function(src, dst, nw, nh) {
  12.             var xofs_count=0;
  13.             var ch=src.channel,w=src.cols,h=src.rows;
  14.             var src_d=src.data,dst_d=dst.data;
  15.             var scale_x = w / nw, scale_y = h / nh;
  16.             var inv_scale_256 = (scale_x * scale_y * 0x10000)|0;
  17.             var dx=0,dy=0,sx=0,sy=0,sx1=0,sx2=0,i=0,k=0,fsx1=0.0,fsx2=0.0;
  18.             var a=0,b=0,dxn=0,alpha=0,beta=0,beta1=0;
  19.  
  20.             var buf_node = jsfeat.cache.get_buffer((nw*ch)<<2);
  21.             var sum_node = jsfeat.cache.get_buffer((nw*ch)<<2);
  22.             var xofs_node = jsfeat.cache.get_buffer((w*2*3)<<2);
  23.  
  24.             var buf = buf_node.i32;
  25.             var sum = sum_node.i32;
  26.             var xofs = xofs_node.i32;
  27.  
  28.             for (; dx < nw; dx++) {
  29.                 fsx1 = dx * scale_x, fsx2 = fsx1 + scale_x;
  30.                 sx1 = (fsx1 + 1.0 - 1e-6)|0, sx2 = fsx2|0;
  31.                 sx1 = Math.min(sx1, w - 1);
  32.                 sx2 = Math.min(sx2, w - 1);
  33.  
  34.                 if(sx1 > fsx1) {
  35.                     xofs[k++] = (dx * ch)|0;
  36.                     xofs[k++] = ((sx1 - 1)*ch)|0;
  37.                     xofs[k++] = ((sx1 - fsx1) * 0x100)|0;
  38.                     xofs_count++;
  39.                 }
  40.                 for(sx = sx1; sx < sx2; sx++){
  41.                     xofs_count++;
  42.                     xofs[k++] = (dx * ch)|0;
  43.                     xofs[k++] = (sx * ch)|0;
  44.                     xofs[k++] = 256;
  45.                 }
  46.                 if(fsx2 - sx2 > 1e-3) {
  47.                     xofs_count++;
  48.                     xofs[k++] = (dx * ch)|0;
  49.                     xofs[k++] = (sx2 * ch)|0;
  50.                     xofs[k++] = ((fsx2 - sx2) * 256)|0;
  51.                 }
  52.             }
  53.  
  54.             for (dx = 0; dx < nw * ch; dx++) {
  55.                 buf[dx] = sum[dx] = 0;
  56.             }
  57.             dy = 0;
  58.             for (sy = 0; sy < h; sy++) {
  59.                 a = w * sy;
  60.                 for (k = 0; k < xofs_count; k++) {
  61.                     dxn = xofs[k*3];
  62.                     sx1 = xofs[k*3+1];
  63.                     alpha = xofs[k*3+2];
  64.                     for (i = 0; i < ch; i++) {
  65.                         buf[dxn + i] += src_d[a+sx1+i] * alpha;
  66.                     }
  67.                 }
  68.                 if ((dy + 1) * scale_y <= sy + 1 || sy == h - 1) {
  69.                     beta = (Math.max(sy + 1 - (dy + 1) * scale_y, 0.0) * 256)|0;
  70.                     beta1 = 256 - beta;
  71.                     b = nw * dy;
  72.                     if (beta <= 0) {
  73.                         for (dx = 0; dx < nw * ch; dx++) {
  74.                             dst_d[b+dx] = Math.min(Math.max((sum[dx] + buf[dx] * 256) / inv_scale_256, 0), 255);
  75.                             sum[dx] = buf[dx] = 0;
  76.                         }
  77.                     } else {
  78.                         for (dx = 0; dx < nw * ch; dx++) {
  79.                             dst_d[b+dx] = Math.min(Math.max((sum[dx] + buf[dx] * beta1) / inv_scale_256, 0), 255);
  80.                             sum[dx] = buf[dx] * beta;
  81.                             buf[dx] = 0;
  82.                         }
  83.                     }
  84.                     dy++;
  85.                 } else {
  86.                     for(dx = 0; dx < nw * ch; dx++) {
  87.                         sum[dx] += buf[dx] * 256;
  88.                         buf[dx] = 0;
  89.                     }
  90.                 }
  91.             }
  92.  
  93.             jsfeat.cache.put_buffer(sum_node);
  94.             jsfeat.cache.put_buffer(buf_node);
  95.             jsfeat.cache.put_buffer(xofs_node);
  96.         }
  97.  
  98.         var _resample = function(src, dst, nw, nh) {
  99.             var xofs_count=0;
  100.             var ch=src.channel,w=src.cols,h=src.rows;
  101.             var src_d=src.data,dst_d=dst.data;
  102.             var scale_x = w / nw, scale_y = h / nh;
  103.             var scale = 1.0 / (scale_x * scale_y);
  104.             var dx=0,dy=0,sx=0,sy=0,sx1=0,sx2=0,i=0,k=0,fsx1=0.0,fsx2=0.0;
  105.             var a=0,b=0,dxn=0,alpha=0.0,beta=0.0,beta1=0.0;
  106.  
  107.             var buf_node = jsfeat.cache.get_buffer((nw*ch)<<2);
  108.             var sum_node = jsfeat.cache.get_buffer((nw*ch)<<2);
  109.             var xofs_node = jsfeat.cache.get_buffer((w*2*3)<<2);
  110.  
  111.             var buf = buf_node.f32;
  112.             var sum = sum_node.f32;
  113.             var xofs = xofs_node.f32;
  114.  
  115.             for (; dx < nw; dx++) {
  116.                 fsx1 = dx * scale_x, fsx2 = fsx1 + scale_x;
  117.                 sx1 = (fsx1 + 1.0 - 1e-6)|0, sx2 = fsx2|0;
  118.                 sx1 = Math.min(sx1, w - 1);
  119.                 sx2 = Math.min(sx2, w - 1);
  120.  
  121.                 if(sx1 > fsx1) {
  122.                     xofs_count++;
  123.                     xofs[k++] = ((sx1 - 1)*ch)|0;
  124.                     xofs[k++] = (dx * ch)|0;
  125.                     xofs[k++] = (sx1 - fsx1) * scale;
  126.                 }
  127.                 for(sx = sx1; sx < sx2; sx++){
  128.                     xofs_count++;
  129.                     xofs[k++] = (sx * ch)|0;
  130.                     xofs[k++] = (dx * ch)|0;
  131.                     xofs[k++] = scale;
  132.                 }
  133.                 if(fsx2 - sx2 > 1e-3) {
  134.                     xofs_count++;
  135.                     xofs[k++] = (sx2 * ch)|0;
  136.                     xofs[k++] = (dx * ch)|0;
  137.                     xofs[k++] = (fsx2 - sx2) * scale;
  138.                 }
  139.             }
  140.  
  141.             for (dx = 0; dx < nw * ch; dx++) {
  142.                 buf[dx] = sum[dx] = 0;
  143.             }
  144.             dy = 0;
  145.             for (sy = 0; sy < h; sy++) {
  146.                 a = w * sy;
  147.                 for (k = 0; k < xofs_count; k++) {
  148.                     sx1 = xofs[k*3]|0;
  149.                     dxn = xofs[k*3+1]|0;
  150.                     alpha = xofs[k*3+2];
  151.                     for (i = 0; i < ch; i++) {
  152.                         buf[dxn + i] += src_d[a+sx1+i] * alpha;
  153.                     }
  154.                 }
  155.                 if ((dy + 1) * scale_y <= sy + 1 || sy == h - 1) {
  156.                     beta = Math.max(sy + 1 - (dy + 1) * scale_y, 0.0);
  157.                     beta1 = 1.0 - beta;
  158.                     b = nw * dy;
  159.                     if (Math.abs(beta) < 1e-3) {
  160.                         for (dx = 0; dx < nw * ch; dx++) {
  161.                             dst_d[b+dx] = sum[dx] + buf[dx];
  162.                             sum[dx] = buf[dx] = 0;
  163.                         }
  164.                     } else {
  165.                         for (dx = 0; dx < nw * ch; dx++) {
  166.                             dst_d[b+dx] = sum[dx] + buf[dx] * beta1;
  167.                             sum[dx] = buf[dx] * beta;
  168.                             buf[dx] = 0;
  169.                         }
  170.                     }
  171.                     dy++;
  172.                 } else {
  173.                     for(dx = 0; dx < nw * ch; dx++) {
  174.                         sum[dx] += buf[dx];
  175.                         buf[dx] = 0;
  176.                     }
  177.                 }
  178.             }
  179.             jsfeat.cache.put_buffer(sum_node);
  180.             jsfeat.cache.put_buffer(buf_node);
  181.             jsfeat.cache.put_buffer(xofs_node);
  182.         }
  183.  
  184.         var _convol_u8 = function(buf, src_d, dst_d, w, h, filter, kernel_size, half_kernel) {
  185.             var i=0,j=0,k=0,sp=0,dp=0,sum=0,sum1=0,sum2=0,sum3=0,f0=filter[0],fk=0;
  186.             var w2=w<<1,w3=w*3,w4=w<<2;
  187.             // hor pass
  188.             for (; i < h; ++i) {
  189.                 sum = src_d[sp];
  190.                 for (j = 0; j < half_kernel; ++j) {
  191.                     buf[j] = sum;
  192.                 }
  193.                 for (j = 0; j <= w-2; j+=2) {
  194.                     buf[j + half_kernel] = src_d[sp+j];
  195.                     buf[j + half_kernel+1] = src_d[sp+j+1];
  196.                 }
  197.                 for (; j < w; ++j) {
  198.                     buf[j + half_kernel] = src_d[sp+j];
  199.                 }
  200.                 sum = src_d[sp+w-1];
  201.                 for (j = w; j < half_kernel + w; ++j) {
  202.                     buf[j + half_kernel] = sum;
  203.                 }
  204.                 for (j = 0; j <= w-4; j+=4) {
  205.                     sum = buf[j] * f0,
  206.                     sum1 = buf[j+1] * f0,
  207.                     sum2 = buf[j+2] * f0,
  208.                     sum3 = buf[j+3] * f0;
  209.                     for (k = 1; k < kernel_size; ++k) {
  210.                         fk = filter[k];
  211.                         sum += buf[k + j] * fk;
  212.                         sum1 += buf[k + j+1] * fk;
  213.                         sum2 += buf[k + j+2] * fk;
  214.                         sum3 += buf[k + j+3] * fk;
  215.                     }
  216.                     dst_d[dp+j] = Math.min(sum >> 8, 255);
  217.                     dst_d[dp+j+1] = Math.min(sum1 >> 8, 255);
  218.                     dst_d[dp+j+2] = Math.min(sum2 >> 8, 255);
  219.                     dst_d[dp+j+3] = Math.min(sum3 >> 8, 255);
  220.                 }
  221.                 for (; j < w; ++j) {
  222.                     sum = buf[j] * f0;
  223.                     for (k = 1; k < kernel_size; ++k) {
  224.                         sum += buf[k + j] * filter[k];
  225.                     }
  226.                     dst_d[dp+j] = Math.min(sum >> 8, 255);
  227.                 }
  228.                 sp += w;
  229.                 dp += w;
  230.             }
  231.  
  232.             // vert pass
  233.             for (i = 0; i < w; ++i) {
  234.                 sum = dst_d[i];
  235.                 for (j = 0; j < half_kernel; ++j) {
  236.                     buf[j] = sum;
  237.                 }
  238.                 k = i;
  239.                 for (j = 0; j <= h-2; j+=2, k+=w2) {
  240.                     buf[j+half_kernel] = dst_d[k];
  241.                     buf[j+half_kernel+1] = dst_d[k+w];
  242.                 }
  243.                 for (; j < h; ++j, k+=w) {
  244.                     buf[j+half_kernel] = dst_d[k];
  245.                 }
  246.                 sum = dst_d[(h-1)*w + i];
  247.                 for (j = h; j < half_kernel + h; ++j) {
  248.                     buf[j + half_kernel] = sum;
  249.                 }
  250.                 dp = i;
  251.                 for (j = 0; j <= h-4; j+=4, dp+=w4) {
  252.                     sum = buf[j] * f0,
  253.                     sum1 = buf[j+1] * f0,
  254.                     sum2 = buf[j+2] * f0,
  255.                     sum3 = buf[j+3] * f0;
  256.                     for (k = 1; k < kernel_size; ++k) {
  257.                         fk = filter[k];
  258.                         sum += buf[k + j] * fk;
  259.                         sum1 += buf[k + j+1] * fk;
  260.                         sum2 += buf[k + j+2] * fk;
  261.                         sum3 += buf[k + j+3] * fk;
  262.                     }
  263.                     dst_d[dp] = Math.min(sum >> 8, 255);
  264.                     dst_d[dp+w] = Math.min(sum1 >> 8, 255);
  265.                     dst_d[dp+w2] = Math.min(sum2 >> 8, 255);
  266.                     dst_d[dp+w3] = Math.min(sum3 >> 8, 255);
  267.                 }
  268.                 for (; j < h; ++j, dp+=w) {
  269.                     sum = buf[j] * f0;
  270.                     for (k = 1; k < kernel_size; ++k) {
  271.                         sum += buf[k + j] * filter[k];
  272.                     }
  273.                     dst_d[dp] = Math.min(sum >> 8, 255);
  274.                 }
  275.             }
  276.         }
  277.  
  278.         var _convol = function(buf, src_d, dst_d, w, h, filter, kernel_size, half_kernel) {
  279.             var i=0,j=0,k=0,sp=0,dp=0,sum=0.0,sum1=0.0,sum2=0.0,sum3=0.0,f0=filter[0],fk=0.0;
  280.             var w2=w<<1,w3=w*3,w4=w<<2;
  281.             // hor pass
  282.             for (; i < h; ++i) {
  283.                 sum = src_d[sp];
  284.                 for (j = 0; j < half_kernel; ++j) {
  285.                     buf[j] = sum;
  286.                 }
  287.                 for (j = 0; j <= w-2; j+=2) {
  288.                     buf[j + half_kernel] = src_d[sp+j];
  289.                     buf[j + half_kernel+1] = src_d[sp+j+1];
  290.                 }
  291.                 for (; j < w; ++j) {
  292.                     buf[j + half_kernel] = src_d[sp+j];
  293.                 }
  294.                 sum = src_d[sp+w-1];
  295.                 for (j = w; j < half_kernel + w; ++j) {
  296.                     buf[j + half_kernel] = sum;
  297.                 }
  298.                 for (j = 0; j <= w-4; j+=4) {
  299.                     sum = buf[j] * f0,
  300.                     sum1 = buf[j+1] * f0,
  301.                     sum2 = buf[j+2] * f0,
  302.                     sum3 = buf[j+3] * f0;
  303.                     for (k = 1; k < kernel_size; ++k) {
  304.                         fk = filter[k];
  305.                         sum += buf[k + j] * fk;
  306.                         sum1 += buf[k + j+1] * fk;
  307.                         sum2 += buf[k + j+2] * fk;
  308.                         sum3 += buf[k + j+3] * fk;
  309.                     }
  310.                     dst_d[dp+j] = sum;
  311.                     dst_d[dp+j+1] = sum1;
  312.                     dst_d[dp+j+2] = sum2;
  313.                     dst_d[dp+j+3] = sum3;
  314.                 }
  315.                 for (; j < w; ++j) {
  316.                     sum = buf[j] * f0;
  317.                     for (k = 1; k < kernel_size; ++k) {
  318.                         sum += buf[k + j] * filter[k];
  319.                     }
  320.                     dst_d[dp+j] = sum;
  321.                 }
  322.                 sp += w;
  323.                 dp += w;
  324.             }
  325.  
  326.             // vert pass
  327.             for (i = 0; i < w; ++i) {
  328.                 sum = dst_d[i];
  329.                 for (j = 0; j < half_kernel; ++j) {
  330.                     buf[j] = sum;
  331.                 }
  332.                 k = i;
  333.                 for (j = 0; j <= h-2; j+=2, k+=w2) {
  334.                     buf[j+half_kernel] = dst_d[k];
  335.                     buf[j+half_kernel+1] = dst_d[k+w];
  336.                 }
  337.                 for (; j < h; ++j, k+=w) {
  338.                     buf[j+half_kernel] = dst_d[k];
  339.                 }
  340.                 sum = dst_d[(h-1)*w + i];
  341.                 for (j = h; j < half_kernel + h; ++j) {
  342.                     buf[j + half_kernel] = sum;
  343.                 }
  344.                 dp = i;
  345.                 for (j = 0; j <= h-4; j+=4, dp+=w4) {
  346.                     sum = buf[j] * f0,
  347.                     sum1 = buf[j+1] * f0,
  348.                     sum2 = buf[j+2] * f0,
  349.                     sum3 = buf[j+3] * f0;
  350.                     for (k = 1; k < kernel_size; ++k) {
  351.                         fk = filter[k];
  352.                         sum += buf[k + j] * fk;
  353.                         sum1 += buf[k + j+1] * fk;
  354.                         sum2 += buf[k + j+2] * fk;
  355.                         sum3 += buf[k + j+3] * fk;
  356.                     }
  357.                     dst_d[dp] = sum;
  358.                     dst_d[dp+w] = sum1;
  359.                     dst_d[dp+w2] = sum2;
  360.                     dst_d[dp+w3] = sum3;
  361.                 }
  362.                 for (; j < h; ++j, dp+=w) {
  363.                     sum = buf[j] * f0;
  364.                     for (k = 1; k < kernel_size; ++k) {
  365.                         sum += buf[k + j] * filter[k];
  366.                     }
  367.                     dst_d[dp] = sum;
  368.                 }
  369.             }
  370.         }
  371.  
  372.         return {
  373.             // TODO: add support for RGB/BGR order
  374.             // for raw arrays
  375.             grayscale: function(src, w, h, dst, code) {
  376.                 // this is default image data representation in browser
  377.                 if (typeof code === "undefined") { code = jsfeat.COLOR_RGBA2GRAY; }
  378.                 var x=0, y=0, i=0, j=0, ir=0,jr=0;
  379.                 var coeff_r = 4899, coeff_g = 9617, coeff_b = 1868, cn = 4;
  380.  
  381.                 if(code == jsfeat.COLOR_BGRA2GRAY || code == jsfeat.COLOR_BGR2GRAY) {
  382.                     coeff_r = 1868;
  383.                     coeff_b = 4899;
  384.                 }
  385.                 if(code == jsfeat.COLOR_RGB2GRAY || code == jsfeat.COLOR_BGR2GRAY) {
  386.                     cn = 3;
  387.                 }
  388.                 var cn2 = cn<<1, cn3 = (cn*3)|0;
  389.  
  390.                 dst.resize(w, h, 1);
  391.                 var dst_u8 = dst.data;
  392.  
  393.                 for(y = 0; y < h; ++y, j+=w, i+=w*cn) {
  394.                     for(x = 0, ir = i, jr = j; x <= w-4; x+=4, ir+=cn<<2, jr+=4) {
  395.                         dst_u8[jr]     = (src[ir] * coeff_r + src[ir+1] * coeff_g + src[ir+2] * coeff_b + 8192) >> 14;
  396.                         dst_u8[jr + 1] = (src[ir+cn] * coeff_r + src[ir+cn+1] * coeff_g + src[ir+cn+2] * coeff_b + 8192) >> 14;
  397.                         dst_u8[jr + 2] = (src[ir+cn2] * coeff_r + src[ir+cn2+1] * coeff_g + src[ir+cn2+2] * coeff_b + 8192) >> 14;
  398.                         dst_u8[jr + 3] = (src[ir+cn3] * coeff_r + src[ir+cn3+1] * coeff_g + src[ir+cn3+2] * coeff_b + 8192) >> 14;
  399.                     }
  400.                     for (; x < w; ++x, ++jr, ir+=cn) {
  401.                         dst_u8[jr] = (src[ir] * coeff_r + src[ir+1] * coeff_g + src[ir+2] * coeff_b + 8192) >> 14;
  402.                     }
  403.                 }
  404.             },
  405.             // derived from CCV library
  406.             resample: function(src, dst, nw, nh) {
  407.                 var h=src.rows,w=src.cols;
  408.                 if (h > nh && w > nw) {
  409.                     dst.resize(nw, nh, src.channel);
  410.                     // using the fast alternative (fix point scale, 0x100 to avoid overflow)
  411.                     if (src.type&jsfeat.U8_t && dst.type&jsfeat.U8_t && h * w / (nh * nw) < 0x100) {
  412.                         _resample_u8(src, dst, nw, nh);
  413.                     } else {
  414.                         _resample(src, dst, nw, nh);
  415.                     }
  416.                 }
  417.             },
  418.  
  419.             box_blur_gray: function(src, dst, radius, options) {
  420.                 if (typeof options === "undefined") { options = 0; }
  421.                 var w=src.cols, h=src.rows, h2=h<<1, w2=w<<1;
  422.                 var i=0,x=0,y=0,end=0;
  423.                 var windowSize = ((radius << 1) + 1)|0;
  424.                 var radiusPlusOne = (radius + 1)|0, radiusPlus2 = (radiusPlusOne+1)|0;
  425.                 var scale = options&jsfeat.BOX_BLUR_NOSCALE ? 1 : (1.0 / (windowSize*windowSize));
  426.  
  427.                 var tmp_buff = jsfeat.cache.get_buffer((w*h)<<2);
  428.  
  429.                 var sum=0, dstIndex=0, srcIndex = 0, nextPixelIndex=0, previousPixelIndex=0;
  430.                 var data_i32 = tmp_buff.i32; // to prevent overflow
  431.                 var data_u8 = src.data;
  432.                 var hold=0;
  433.  
  434.                 dst.resize(w, h, src.channel);
  435.  
  436.                 // first pass
  437.                 // no need to scale
  438.                 //data_u8 = src.data;
  439.                 //data_i32 = tmp;
  440.                 for (y = 0; y < h; ++y) {
  441.                     dstIndex = y;
  442.                     sum = radiusPlusOne * data_u8[srcIndex];
  443.  
  444.                     for(i = (srcIndex+1)|0, end=(srcIndex+radius)|0; i <= end; ++i) {
  445.                         sum += data_u8[i];
  446.                     }
  447.  
  448.                     nextPixelIndex = (srcIndex + radiusPlusOne)|0;
  449.                     previousPixelIndex = srcIndex;
  450.                     hold = data_u8[previousPixelIndex];
  451.                     for(x = 0; x < radius; ++x, dstIndex += h) {
  452.                         data_i32[dstIndex] = sum;
  453.                         sum += data_u8[nextPixelIndex]- hold;
  454.                         nextPixelIndex ++;
  455.                     }
  456.                     for(; x < w-radiusPlus2; x+=2, dstIndex += h2) {
  457.                         data_i32[dstIndex] = sum;
  458.                         sum += data_u8[nextPixelIndex]- data_u8[previousPixelIndex];
  459.  
  460.                         data_i32[dstIndex+h] = sum;
  461.                         sum += data_u8[nextPixelIndex+1]- data_u8[previousPixelIndex+1];
  462.  
  463.                         nextPixelIndex +=2;
  464.                         previousPixelIndex +=2;
  465.                     }
  466.                     for(; x < w-radiusPlusOne; ++x, dstIndex += h) {
  467.                         data_i32[dstIndex] = sum;
  468.                         sum += data_u8[nextPixelIndex]- data_u8[previousPixelIndex];
  469.  
  470.                         nextPixelIndex ++;
  471.                         previousPixelIndex ++;
  472.                     }
  473.                    
  474.                     hold = data_u8[nextPixelIndex-1];
  475.                     for(; x < w; ++x, dstIndex += h) {
  476.                         data_i32[dstIndex] = sum;
  477.  
  478.                         sum += hold- data_u8[previousPixelIndex];
  479.                         previousPixelIndex ++;
  480.                     }
  481.  
  482.                     srcIndex += w;
  483.                 }
  484.                 //
  485.                 // second pass
  486.                 srcIndex = 0;
  487.                 //data_i32 = tmp; // this is a transpose
  488.                 data_u8 = dst.data;
  489.  
  490.                 // dont scale result
  491.                 if(scale == 1) {
  492.                     for (y = 0; y < w; ++y) {
  493.                         dstIndex = y;
  494.                         sum = radiusPlusOne * data_i32[srcIndex];
  495.  
  496.                         for(i = (srcIndex+1)|0, end=(srcIndex+radius)|0; i <= end; ++i) {
  497.                             sum += data_i32[i];
  498.                         }
  499.  
  500.                         nextPixelIndex = srcIndex + radiusPlusOne;
  501.                         previousPixelIndex = srcIndex;
  502.                         hold = data_i32[previousPixelIndex];
  503.  
  504.                         for(x = 0; x < radius; ++x, dstIndex += w) {
  505.                             data_u8[dstIndex] = sum;
  506.                             sum += data_i32[nextPixelIndex]- hold;
  507.                             nextPixelIndex ++;
  508.                         }
  509.                         for(; x < h-radiusPlus2; x+=2, dstIndex += w2) {
  510.                             data_u8[dstIndex] = sum;
  511.                             sum += data_i32[nextPixelIndex]- data_i32[previousPixelIndex];
  512.  
  513.                             data_u8[dstIndex+w] = sum;
  514.                             sum += data_i32[nextPixelIndex+1]- data_i32[previousPixelIndex+1];
  515.  
  516.                             nextPixelIndex +=2;
  517.                             previousPixelIndex +=2;
  518.                         }
  519.                         for(; x < h-radiusPlusOne; ++x, dstIndex += w) {
  520.                             data_u8[dstIndex] = sum;
  521.  
  522.                             sum += data_i32[nextPixelIndex]- data_i32[previousPixelIndex];
  523.                             nextPixelIndex ++;
  524.                             previousPixelIndex ++;
  525.                         }
  526.                         hold = data_i32[nextPixelIndex-1];
  527.                         for(; x < h; ++x, dstIndex += w) {
  528.                             data_u8[dstIndex] = sum;
  529.  
  530.                             sum += hold- data_i32[previousPixelIndex];
  531.                             previousPixelIndex ++;
  532.                         }
  533.  
  534.                         srcIndex += h;
  535.                     }
  536.                 } else {
  537.                     for (y = 0; y < w; ++y) {
  538.                         dstIndex = y;
  539.                         sum = radiusPlusOne * data_i32[srcIndex];
  540.  
  541.                         for(i = (srcIndex+1)|0, end=(srcIndex+radius)|0; i <= end; ++i) {
  542.                             sum += data_i32[i];
  543.                         }
  544.  
  545.                         nextPixelIndex = srcIndex + radiusPlusOne;
  546.                         previousPixelIndex = srcIndex;
  547.                         hold = data_i32[previousPixelIndex];
  548.  
  549.                         for(x = 0; x < radius; ++x, dstIndex += w) {
  550.                             data_u8[dstIndex] = sum*scale;
  551.                             sum += data_i32[nextPixelIndex]- hold;
  552.                             nextPixelIndex ++;
  553.                         }
  554.                         for(; x < h-radiusPlus2; x+=2, dstIndex += w2) {
  555.                             data_u8[dstIndex] = sum*scale;
  556.                             sum += data_i32[nextPixelIndex]- data_i32[previousPixelIndex];
  557.  
  558.                             data_u8[dstIndex+w] = sum*scale;
  559.                             sum += data_i32[nextPixelIndex+1]- data_i32[previousPixelIndex+1];
  560.  
  561.                             nextPixelIndex +=2;
  562.                             previousPixelIndex +=2;
  563.                         }
  564.                         for(; x < h-radiusPlusOne; ++x, dstIndex += w) {
  565.                             data_u8[dstIndex] = sum*scale;
  566.  
  567.                             sum += data_i32[nextPixelIndex]- data_i32[previousPixelIndex];
  568.                             nextPixelIndex ++;
  569.                             previousPixelIndex ++;
  570.                         }
  571.                         hold = data_i32[nextPixelIndex-1];
  572.                         for(; x < h; ++x, dstIndex += w) {
  573.                             data_u8[dstIndex] = sum*scale;
  574.  
  575.                             sum += hold- data_i32[previousPixelIndex];
  576.                             previousPixelIndex ++;
  577.                         }
  578.  
  579.                         srcIndex += h;
  580.                     }
  581.                 }
  582.  
  583.                 jsfeat.cache.put_buffer(tmp_buff);
  584.             },
  585.  
  586.             gaussian_blur: function(src, dst, kernel_size, sigma) {
  587.                 if (typeof sigma === "undefined") { sigma = 0.0; }
  588.                 if (typeof kernel_size === "undefined") { kernel_size = 0; }
  589.                 kernel_size = kernel_size == 0 ? (Math.max(1, (4.0 * sigma + 1.0 - 1e-8)) * 2 + 1)|0 : kernel_size;
  590.                 var half_kernel = kernel_size >> 1;
  591.                 var w = src.cols, h = src.rows;
  592.                 var data_type = src.type, is_u8 = data_type&jsfeat.U8_t;
  593.  
  594.                 dst.resize(w, h, src.channel);
  595.  
  596.                 var src_d = src.data, dst_d = dst.data;
  597.                 var buf,filter,buf_sz=(kernel_size + Math.max(h, w))|0;
  598.  
  599.                 var buf_node = jsfeat.cache.get_buffer(buf_sz<<2);
  600.                 var filt_node = jsfeat.cache.get_buffer(kernel_size<<2);
  601.  
  602.                 if(is_u8) {
  603.                     buf = buf_node.i32;
  604.                     filter = filt_node.i32;
  605.                 } else if(data_type&jsfeat.S32_t) {
  606.                     buf = buf_node.i32;
  607.                     filter = filt_node.f32;
  608.                 } else {
  609.                     buf = buf_node.f32;
  610.                     filter = filt_node.f32;
  611.                 }
  612.  
  613.                 jsfeat.math.get_gaussian_kernel(kernel_size, sigma, filter, data_type);
  614.  
  615.                 if(is_u8) {
  616.                     _convol_u8(buf, src_d, dst_d, w, h, filter, kernel_size, half_kernel);
  617.                 } else {
  618.                     _convol(buf, src_d, dst_d, w, h, filter, kernel_size, half_kernel);
  619.                 }
  620.  
  621.                 jsfeat.cache.put_buffer(buf_node);
  622.                 jsfeat.cache.put_buffer(filt_node);
  623.             },
  624.             hough_transform: function( img, rho_res, theta_res, threshold ) {
  625.                 var image = img.data;
  626.  
  627.                 var width = img.cols;
  628.                 var height = img.rows;
  629.                 var step = width;
  630.  
  631.                 min_theta = 0.0;
  632.                 max_theta = Math.PI;
  633.  
  634.                 numangle = Math.round((max_theta - min_theta) / theta_res);
  635.                 numrho = Math.round(((width + height) * 2 + 1) / rho_res);
  636.                 irho = 1.0 / rho_res;
  637.  
  638.                 var accum = new Int32Array((numangle+2) * (numrho+2)); //typed arrays are initialized to 0
  639.                 var tabSin = new Float32Array(numangle);
  640.                 var tabCos = new Float32Array(numangle);
  641.  
  642.                 var n=0;
  643.                 var ang = min_theta;
  644.                 for(; n < numangle; n++ ) {
  645.                     tabSin[n] = Math.sin(ang) * irho;
  646.                     tabCos[n] = Math.cos(ang) * irho;
  647.                     ang += theta_res
  648.                 }
  649.  
  650.                 // stage 1. fill accumulator
  651.                 for( var i = 0; i < height; i++ ) {
  652.                     for( var j = 0; j < width; j++ ) {
  653.                         if( image[i * step + j] != 0 ) {
  654.                             //console.log(r, (n+1) * (numrho+2) + r+1, tabCos[n], tabSin[n]);
  655.                             for(var n = 0; n < numangle; n++ ) {
  656.                                 var r = Math.round( j * tabCos[n] + i * tabSin[n] );
  657.                                 r += (numrho - 1) / 2;
  658.                                 accum[(n+1) * (numrho+2) + r+1] += 1;
  659.                             }
  660.                         }
  661.                     }
  662.                 }
  663.  
  664.                 // stage 2. find local maximums
  665.                 //TODO: Consider making a vector class that uses typed arrays
  666.                 _sort_buf = new Array();
  667.                 for(var r = 0; r < numrho; r++ ) {
  668.                     for(var n = 0; n < numangle; n++ ) {
  669.                         var base = (n+1) * (numrho+2) + r+1;
  670.                         if( accum[base] > threshold &&
  671.                             accum[base] > accum[base - 1] && accum[base] >= accum[base + 1] &&
  672.                             accum[base] > accum[base - numrho - 2] && accum[base] >= accum[base + numrho + 2] ) {
  673.                             _sort_buf.push(base);
  674.                         }
  675.                     }
  676.                 }
  677.  
  678.                 // stage 3. sort the detected lines by accumulator value
  679.                 _sort_buf.sort(function(l1, l2) {
  680.                     return accum[l1] > accum[l2] || (accum[l1] == accum[l2] && l1 < l2);
  681.                 });
  682.  
  683.                 // stage 4. store the first min(total,linesMax) lines to the output buffer
  684.                 linesMax = Math.min(numangle*numrho, _sort_buf.length);
  685.                 scale = 1.0 / (numrho+2);
  686.                 lines = new Array();
  687.                 for( var i = 0; i < linesMax; i++ ) {
  688.                     var idx = _sort_buf[i];
  689.                     var n = Math.floor(idx*scale) - 1;
  690.                     var r = idx - (n+1)*(numrho+2) - 1;
  691.                     var lrho = (r - (numrho - 1)*0.5) * rho_res;
  692.                     var langle = n * theta_res;
  693.                     lines.push([lrho, langle]);
  694.                 }
  695.                 return lines;
  696.             },
  697.             // assume we always need it for u8 image
  698.             pyrdown: function(src, dst, sx, sy) {
  699.                 // this is needed for bbf
  700.                 if (typeof sx === "undefined") { sx = 0; }
  701.                 if (typeof sy === "undefined") { sy = 0; }
  702.  
  703.                 var w = src.cols, h = src.rows;
  704.                 var w2 = w >> 1, h2 = h >> 1;
  705.                 var _w2 = w2 - (sx << 1), _h2 = h2 - (sy << 1);
  706.                 var x=0,y=0,sptr=sx+sy*w,sline=0,dptr=0,dline=0;
  707.  
  708.                 dst.resize(w2, h2, src.channel);
  709.  
  710.                 var src_d = src.data, dst_d = dst.data;
  711.  
  712.                 for(y = 0; y < _h2; ++y) {
  713.                     sline = sptr;
  714.                     dline = dptr;
  715.                     for(x = 0; x <= _w2-2; x+=2, dline+=2, sline += 4) {
  716.                         dst_d[dline] = (src_d[sline] + src_d[sline+1] +
  717.                                             src_d[sline+w] + src_d[sline+w+1] + 2) >> 2;
  718.                         dst_d[dline+1] = (src_d[sline+2] + src_d[sline+3] +
  719.                                             src_d[sline+w+2] + src_d[sline+w+3] + 2) >> 2;
  720.                     }
  721.                     for(; x < _w2; ++x, ++dline, sline += 2) {
  722.                         dst_d[dline] = (src_d[sline] + src_d[sline+1] +
  723.                                             src_d[sline+w] + src_d[sline+w+1] + 2) >> 2;
  724.                     }
  725.                     sptr += w << 1;
  726.                     dptr += w2;
  727.                 }
  728.             },
  729.  
  730.             // dst: [gx,gy,...]
  731.             scharr_derivatives: function(src, dst) {
  732.                 var w = src.cols, h = src.rows;
  733.                 var dstep = w<<1,x=0,y=0,x1=0,a,b,c,d,e,f;
  734.                 var srow0=0,srow1=0,srow2=0,drow=0;
  735.                 var trow0,trow1;
  736.  
  737.                 dst.resize(w, h, 2); // 2 channel output gx, gy
  738.  
  739.                 var img = src.data, gxgy=dst.data;
  740.  
  741.                 var buf0_node = jsfeat.cache.get_buffer((w+2)<<2);
  742.                 var buf1_node = jsfeat.cache.get_buffer((w+2)<<2);
  743.  
  744.                 if(src.type&jsfeat.U8_t || src.type&jsfeat.S32_t) {
  745.                     trow0 = buf0_node.i32;
  746.                     trow1 = buf1_node.i32;
  747.                 } else {
  748.                     trow0 = buf0_node.f32;
  749.                     trow1 = buf1_node.f32;
  750.                 }
  751.  
  752.                 for(; y < h; ++y, srow1+=w) {
  753.                     srow0 = ((y > 0 ? y-1 : 1)*w)|0;
  754.                     srow2 = ((y < h-1 ? y+1 : h-2)*w)|0;
  755.                     drow = (y*dstep)|0;
  756.                     // do vertical convolution
  757.                     for(x = 0, x1 = 1; x <= w-2; x+=2, x1+=2) {
  758.                         a = img[srow0+x], b = img[srow2+x];
  759.                         trow0[x1] = ( (a + b)*3 + (img[srow1+x])*10 );
  760.                         trow1[x1] = ( b - a );
  761.                         //
  762.                         a = img[srow0+x+1], b = img[srow2+x+1];
  763.                         trow0[x1+1] = ( (a + b)*3 + (img[srow1+x+1])*10 );
  764.                         trow1[x1+1] = ( b - a );
  765.                     }
  766.                     for(; x < w; ++x, ++x1) {
  767.                         a = img[srow0+x], b = img[srow2+x];
  768.                         trow0[x1] = ( (a + b)*3 + (img[srow1+x])*10 );
  769.                         trow1[x1] = ( b - a );
  770.                     }
  771.                     // make border
  772.                     x = (w + 1)|0;
  773.                     trow0[0] = trow0[1]; trow0[x] = trow0[w];
  774.                     trow1[0] = trow1[1]; trow1[x] = trow1[w];
  775.                     // do horizontal convolution, interleave the results and store them
  776.                     for(x = 0; x <= w-4; x+=4) {
  777.                         a = trow1[x+2], b = trow1[x+1], c = trow1[x+3], d = trow1[x+4],
  778.                         e = trow0[x+2], f = trow0[x+3];
  779.                         gxgy[drow++] = ( e - trow0[x] );
  780.                         gxgy[drow++] = ( (a + trow1[x])*3 + b*10 );
  781.                         gxgy[drow++] = ( f - trow0[x+1] );
  782.                         gxgy[drow++] = ( (c + b)*3 + a*10 );
  783.  
  784.                         gxgy[drow++] = ( (trow0[x+4] - e) );
  785.                         gxgy[drow++] = ( ((d + a)*3 + c*10) );
  786.                         gxgy[drow++] = ( (trow0[x+5] - f) );
  787.                         gxgy[drow++] = ( ((trow1[x+5] + c)*3 + d*10) );
  788.                     }
  789.                     for(; x < w; ++x) {
  790.                         gxgy[drow++] = ( (trow0[x+2] - trow0[x]) );
  791.                         gxgy[drow++] = ( ((trow1[x+2] + trow1[x])*3 + trow1[x+1]*10) );
  792.                     }
  793.                 }
  794.                 jsfeat.cache.put_buffer(buf0_node);
  795.                 jsfeat.cache.put_buffer(buf1_node);
  796.             },
  797.  
  798.             // compute gradient using Sobel kernel [1 2 1] * [-1 0 1]^T
  799.             // dst: [gx,gy,...]
  800.             sobel_derivatives: function(src, dst) {
  801.                 var w = src.cols, h = src.rows;
  802.                 var dstep = w<<1,x=0,y=0,x1=0,a,b,c,d,e,f;
  803.                 var srow0=0,srow1=0,srow2=0,drow=0;
  804.                 var trow0,trow1;
  805.  
  806.                 dst.resize(w, h, 2); // 2 channel output gx, gy
  807.  
  808.                 var img = src.data, gxgy=dst.data;
  809.  
  810.                 var buf0_node = jsfeat.cache.get_buffer((w+2)<<2);
  811.                 var buf1_node = jsfeat.cache.get_buffer((w+2)<<2);
  812.  
  813.                 if(src.type&jsfeat.U8_t || src.type&jsfeat.S32_t) {
  814.                     trow0 = buf0_node.i32;
  815.                     trow1 = buf1_node.i32;
  816.                 } else {
  817.                     trow0 = buf0_node.f32;
  818.                     trow1 = buf1_node.f32;
  819.                 }
  820.  
  821.                 for(; y < h; ++y, srow1+=w) {
  822.                     srow0 = ((y > 0 ? y-1 : 1)*w)|0;
  823.                     srow2 = ((y < h-1 ? y+1 : h-2)*w)|0;
  824.                     drow = (y*dstep)|0;
  825.                     // do vertical convolution
  826.                     for(x = 0, x1 = 1; x <= w-2; x+=2, x1+=2) {
  827.                         a = img[srow0+x], b = img[srow2+x];
  828.                         trow0[x1] = ( (a + b) + (img[srow1+x]*2) );
  829.                         trow1[x1] = ( b - a );
  830.                         //
  831.                         a = img[srow0+x+1], b = img[srow2+x+1];
  832.                         trow0[x1+1] = ( (a + b) + (img[srow1+x+1]*2) );
  833.                         trow1[x1+1] = ( b - a );
  834.                     }
  835.                     for(; x < w; ++x, ++x1) {
  836.                         a = img[srow0+x], b = img[srow2+x];
  837.                         trow0[x1] = ( (a + b) + (img[srow1+x]*2) );
  838.                         trow1[x1] = ( b - a );
  839.                     }
  840.                     // make border
  841.                     x = (w + 1)|0;
  842.                     trow0[0] = trow0[1]; trow0[x] = trow0[w];
  843.                     trow1[0] = trow1[1]; trow1[x] = trow1[w];
  844.                     // do horizontal convolution, interleave the results and store them
  845.                     for(x = 0; x <= w-4; x+=4) {
  846.                         a = trow1[x+2], b = trow1[x+1], c = trow1[x+3], d = trow1[x+4],
  847.                         e = trow0[x+2], f = trow0[x+3];
  848.                         gxgy[drow++] = ( e - trow0[x] );
  849.                         gxgy[drow++] = ( a + trow1[x] + b*2 );
  850.                         gxgy[drow++] = ( f - trow0[x+1] );
  851.                         gxgy[drow++] = ( c + b + a*2 );
  852.  
  853.                         gxgy[drow++] = ( trow0[x+4] - e );
  854.                         gxgy[drow++] = ( d + a + c*2 );
  855.                         gxgy[drow++] = ( trow0[x+5] - f );
  856.                         gxgy[drow++] = ( trow1[x+5] + c + d*2 );
  857.                     }
  858.                     for(; x < w; ++x) {
  859.                         gxgy[drow++] = ( trow0[x+2] - trow0[x] );
  860.                         gxgy[drow++] = ( trow1[x+2] + trow1[x] + trow1[x+1]*2 );
  861.                     }
  862.                 }
  863.                 jsfeat.cache.put_buffer(buf0_node);
  864.                 jsfeat.cache.put_buffer(buf1_node);
  865.             },
  866.  
  867.             // please note:
  868.             // dst_(type) size should be cols = src.cols+1, rows = src.rows+1
  869.             compute_integral_image: function(src, dst_sum, dst_sqsum, dst_tilted) {
  870.                 var w0=src.cols|0,h0=src.rows|0,src_d=src.data;
  871.                 var w1=(w0+1)|0;
  872.                 var s=0,s2=0,p=0,pup=0,i=0,j=0,v=0,k=0;
  873.  
  874.                 if(dst_sum && dst_sqsum) {
  875.                     // fill first row with zeros
  876.                     for(; i < w1; ++i) {
  877.                         dst_sum[i] = 0, dst_sqsum[i] = 0;
  878.                     }
  879.                     p = (w1+1)|0, pup = 1;
  880.                     for(i = 0, k = 0; i < h0; ++i, ++p, ++pup) {
  881.                         s = s2 = 0;
  882.                         for(j = 0; j <= w0-2; j+=2, k+=2, p+=2, pup+=2) {
  883.                             v = src_d[k];
  884.                             s += v, s2 += v*v;
  885.                             dst_sum[p] = dst_sum[pup] + s;
  886.                             dst_sqsum[p] = dst_sqsum[pup] + s2;
  887.  
  888.                             v = src_d[k+1];
  889.                             s += v, s2 += v*v;
  890.                             dst_sum[p+1] = dst_sum[pup+1] + s;
  891.                             dst_sqsum[p+1] = dst_sqsum[pup+1] + s2;
  892.                         }
  893.                         for(; j < w0; ++j, ++k, ++p, ++pup) {
  894.                             v = src_d[k];
  895.                             s += v, s2 += v*v;
  896.                             dst_sum[p] = dst_sum[pup] + s;
  897.                             dst_sqsum[p] = dst_sqsum[pup] + s2;
  898.                         }
  899.                     }
  900.                 } else if(dst_sum) {
  901.                     // fill first row with zeros
  902.                     for(; i < w1; ++i) {
  903.                         dst_sum[i] = 0;
  904.                     }
  905.                     p = (w1+1)|0, pup = 1;
  906.                     for(i = 0, k = 0; i < h0; ++i, ++p, ++pup) {
  907.                         s = 0;
  908.                         for(j = 0; j <= w0-2; j+=2, k+=2, p+=2, pup+=2) {
  909.                             s += src_d[k];
  910.                             dst_sum[p] = dst_sum[pup] + s;
  911.                             s += src_d[k+1];
  912.                             dst_sum[p+1] = dst_sum[pup+1] + s;
  913.                         }
  914.                         for(; j < w0; ++j, ++k, ++p, ++pup) {
  915.                             s += src_d[k];
  916.                             dst_sum[p] = dst_sum[pup] + s;
  917.                         }
  918.                     }
  919.                 } else if(dst_sqsum) {
  920.                     // fill first row with zeros
  921.                     for(; i < w1; ++i) {
  922.                         dst_sqsum[i] = 0;
  923.                     }
  924.                     p = (w1+1)|0, pup = 1;
  925.                     for(i = 0, k = 0; i < h0; ++i, ++p, ++pup) {
  926.                         s2 = 0;
  927.                         for(j = 0; j <= w0-2; j+=2, k+=2, p+=2, pup+=2) {
  928.                             v = src_d[k];
  929.                             s2 += v*v;
  930.                             dst_sqsum[p] = dst_sqsum[pup] + s2;
  931.                             v = src_d[k+1];
  932.                             s2 += v*v;
  933.                             dst_sqsum[p+1] = dst_sqsum[pup+1] + s2;
  934.                         }
  935.                         for(; j < w0; ++j, ++k, ++p, ++pup) {
  936.                             v = src_d[k];
  937.                             s2 += v*v;
  938.                             dst_sqsum[p] = dst_sqsum[pup] + s2;
  939.                         }
  940.                     }
  941.                 }
  942.  
  943.                 if(dst_tilted) {
  944.                     // fill first row with zeros
  945.                     for(i = 0; i < w1; ++i) {
  946.                         dst_tilted[i] = 0;
  947.                     }
  948.                     // diagonal
  949.                     p = (w1+1)|0, pup = 0;
  950.                     for(i = 0, k = 0; i < h0; ++i, ++p, ++pup) {
  951.                         for(j = 0; j <= w0-2; j+=2, k+=2, p+=2, pup+=2) {
  952.                             dst_tilted[p] = src_d[k] + dst_tilted[pup];
  953.                             dst_tilted[p+1] = src_d[k+1] + dst_tilted[pup+1];
  954.                         }
  955.                         for(; j < w0; ++j, ++k, ++p, ++pup) {
  956.                             dst_tilted[p] = src_d[k] + dst_tilted[pup];
  957.                         }
  958.                     }
  959.                     // diagonal
  960.                     p = (w1+w0)|0, pup = w0;
  961.                     for(i = 0; i < h0; ++i, p+=w1, pup+=w1) {
  962.                         dst_tilted[p] += dst_tilted[pup];
  963.                     }
  964.  
  965.                     for(j = w0-1; j > 0; --j) {
  966.                         p = j+h0*w1, pup=p-w1;
  967.                         for(i = h0; i > 0; --i, p-=w1, pup-=w1) {
  968.                             dst_tilted[p] += dst_tilted[pup] + dst_tilted[pup+1];
  969.                         }
  970.                     }
  971.                 }
  972.             },
  973.             equalize_histogram: function(src, dst) {
  974.                 var w=src.cols,h=src.rows,src_d=src.data;
  975.  
  976.                 dst.resize(w, h, src.channel);
  977.  
  978.                 var dst_d=dst.data,size=w*h;
  979.                 var i=0,prev=0,hist0,norm;
  980.  
  981.                 var hist0_node = jsfeat.cache.get_buffer(256<<2);
  982.                 hist0 = hist0_node.i32;
  983.                 for(; i < 256; ++i) hist0[i] = 0;
  984.                 for (i = 0; i < size; ++i) {
  985.                     ++hist0[src_d[i]];
  986.                 }
  987.  
  988.                 prev = hist0[0];
  989.                 for (i = 1; i < 256; ++i) {
  990.                     prev = hist0[i] += prev;
  991.                 }
  992.  
  993.                 norm = 255 / size;
  994.                 for (i = 0; i < size; ++i) {
  995.                     dst_d[i] = (hist0[src_d[i]] * norm + 0.5)|0;
  996.                 }
  997.                 jsfeat.cache.put_buffer(hist0_node);
  998.             },
  999.  
  1000.             canny: function(src, dst, low_thresh, high_thresh) {
  1001.                 var w=src.cols,h=src.rows,src_d=src.data;
  1002.  
  1003.                 dst.resize(w, h, src.channel);
  1004.                
  1005.                 var dst_d=dst.data;
  1006.                 var i=0,j=0,grad=0,w2=w<<1,_grad=0,suppress=0,f=0,x=0,y=0,s=0;
  1007.                 var tg22x=0,tg67x=0;
  1008.  
  1009.                 // cache buffers
  1010.                 var dxdy_node = jsfeat.cache.get_buffer((h * w2)<<2);
  1011.                 var buf_node = jsfeat.cache.get_buffer((3 * (w + 2))<<2);
  1012.                 var map_node = jsfeat.cache.get_buffer(((h+2) * (w + 2))<<2);
  1013.                 var stack_node = jsfeat.cache.get_buffer((h * w)<<2);
  1014.                
  1015.  
  1016.                 var buf = buf_node.i32;
  1017.                 var map = map_node.i32;
  1018.                 var stack = stack_node.i32;
  1019.                 var dxdy = dxdy_node.i32;
  1020.                 var dxdy_m = new jsfeat.matrix_t(w, h, jsfeat.S32C2_t, dxdy_node.data);
  1021.                 var row0=1,row1=(w+2+1)|0,row2=(2*(w+2)+1)|0,map_w=(w+2)|0,map_i=(map_w+1)|0,stack_i=0;
  1022.  
  1023.                 this.sobel_derivatives(src, dxdy_m);
  1024.  
  1025.                 if(low_thresh > high_thresh) {
  1026.                     i = low_thresh;
  1027.                     low_thresh = high_thresh;
  1028.                     high_thresh = i;
  1029.                 }
  1030.  
  1031.                 i = (3 * (w + 2))|0;
  1032.                 while(--i>=0) {
  1033.                     buf[i] = 0;
  1034.                 }
  1035.  
  1036.                 i = ((h+2) * (w + 2))|0;
  1037.                 while(--i>=0) {
  1038.                     map[i] = 0;
  1039.                 }
  1040.  
  1041.                 for (; j < w; ++j, grad+=2) {
  1042.                     //buf[row1+j] = Math.abs(dxdy[grad]) + Math.abs(dxdy[grad+1]);
  1043.                     x = dxdy[grad], y = dxdy[grad+1];
  1044.                     //buf[row1+j] = x*x + y*y;
  1045.                     buf[row1+j] = ((x ^ (x >> 31)) - (x >> 31)) + ((y ^ (y >> 31)) - (y >> 31));
  1046.                 }
  1047.  
  1048.                 for(i=1; i <= h; ++i, grad+=w2) {
  1049.                     if(i == h) {
  1050.                         j = row2+w;
  1051.                         while(--j>=row2) {
  1052.                             buf[j] = 0;
  1053.                         }
  1054.                     } else {
  1055.                         for (j = 0; j < w; j++) {
  1056.                             //buf[row2+j] =  Math.abs(dxdy[grad+(j<<1)]) + Math.abs(dxdy[grad+(j<<1)+1]);
  1057.                             x = dxdy[grad+(j<<1)], y = dxdy[grad+(j<<1)+1];
  1058.                             //buf[row2+j] = x*x + y*y;
  1059.                             buf[row2+j] = ((x ^ (x >> 31)) - (x >> 31)) + ((y ^ (y >> 31)) - (y >> 31));
  1060.                         }
  1061.                     }
  1062.                     _grad = (grad - w2)|0;
  1063.                     map[map_i-1] = 0;
  1064.                     suppress = 0;
  1065.                     for(j = 0; j < w; ++j, _grad+=2) {
  1066.                         f = buf[row1+j];
  1067.                         if (f > low_thresh) {
  1068.                             x = dxdy[_grad];
  1069.                             y = dxdy[_grad+1];
  1070.                             s = x ^ y;
  1071.                             // seems ot be faster than Math.abs
  1072.                             x = ((x ^ (x >> 31)) - (x >> 31))|0;
  1073.                             y = ((y ^ (y >> 31)) - (y >> 31))|0;
  1074.                             //x * tan(22.5) x * tan(67.5) == 2 * x + x * tan(22.5)
  1075.                             tg22x = x * 13573;
  1076.                             tg67x = tg22x + ((x + x) << 15);
  1077.                             y <<= 15;
  1078.                             if (y < tg22x) {
  1079.                                 if (f > buf[row1+j-1] && f >= buf[row1+j+1]) {
  1080.                                     if (f > high_thresh && !suppress && map[map_i+j-map_w] != 2) {
  1081.                                         map[map_i+j] = 2;
  1082.                                         suppress = 1;
  1083.                                         stack[stack_i++] = map_i + j;
  1084.                                     } else {
  1085.                                         map[map_i+j] = 1;
  1086.                                     }
  1087.                                     continue;
  1088.                                 }
  1089.                             } else if (y > tg67x) {
  1090.                                 if (f > buf[row0+j] && f >= buf[row2+j]) {
  1091.                                     if (f > high_thresh && !suppress && map[map_i+j-map_w] != 2) {
  1092.                                         map[map_i+j] = 2;
  1093.                                         suppress = 1;
  1094.                                         stack[stack_i++] = map_i + j;
  1095.                                     } else {
  1096.                                         map[map_i+j] = 1;
  1097.                                     }
  1098.                                     continue;
  1099.                                 }
  1100.                             } else {
  1101.                                 s = s < 0 ? -1 : 1;
  1102.                                 if (f > buf[row0+j-s] && f > buf[row2+j+s]) {
  1103.                                     if (f > high_thresh && !suppress && map[map_i+j-map_w] != 2) {
  1104.                                         map[map_i+j] = 2;
  1105.                                         suppress = 1;
  1106.                                         stack[stack_i++] = map_i + j;
  1107.                                     } else {
  1108.                                         map[map_i+j] = 1;
  1109.                                     }
  1110.                                     continue;
  1111.                                 }
  1112.                             }
  1113.                         }
  1114.                         map[map_i+j] = 0;
  1115.                         suppress = 0;
  1116.                     }
  1117.                     map[map_i+w] = 0;
  1118.                     map_i += map_w;
  1119.                     j = row0;
  1120.                     row0 = row1;
  1121.                     row1 = row2;
  1122.                     row2 = j;
  1123.                 }
  1124.  
  1125.                 j = map_i - map_w - 1;
  1126.                 for(i = 0; i < map_w; ++i, ++j) {
  1127.                     map[j] = 0;
  1128.                 }
  1129.                 // path following
  1130.                 while(stack_i > 0) {
  1131.                     map_i = stack[--stack_i];
  1132.                     map_i -= map_w+1;
  1133.                     if(map[map_i] == 1) map[map_i] = 2, stack[stack_i++] = map_i;
  1134.                     map_i += 1;
  1135.                     if(map[map_i] == 1) map[map_i] = 2, stack[stack_i++] = map_i;
  1136.                     map_i += 1;
  1137.                     if(map[map_i] == 1) map[map_i] = 2, stack[stack_i++] = map_i;
  1138.                     map_i += map_w;
  1139.                     if(map[map_i] == 1) map[map_i] = 2, stack[stack_i++] = map_i;
  1140.                     map_i -= 2;
  1141.                     if(map[map_i] == 1) map[map_i] = 2, stack[stack_i++] = map_i;
  1142.                     map_i += map_w;
  1143.                     if(map[map_i] == 1) map[map_i] = 2, stack[stack_i++] = map_i;
  1144.                     map_i += 1;
  1145.                     if(map[map_i] == 1) map[map_i] = 2, stack[stack_i++] = map_i;
  1146.                     map_i += 1;
  1147.                     if(map[map_i] == 1) map[map_i] = 2, stack[stack_i++] = map_i;
  1148.                 }
  1149.  
  1150.                 map_i = map_w + 1;
  1151.                 row0 = 0;
  1152.                 for(i = 0; i < h; ++i, map_i+=map_w) {
  1153.                     for(j = 0; j < w; ++j) {
  1154.                         dst_d[row0++] = (map[map_i+j] == 2) * 0xff;
  1155.                     }
  1156.                 }
  1157.  
  1158.                 // free buffers
  1159.                 jsfeat.cache.put_buffer(dxdy_node);
  1160.                 jsfeat.cache.put_buffer(buf_node);
  1161.                 jsfeat.cache.put_buffer(map_node);
  1162.                 jsfeat.cache.put_buffer(stack_node);
  1163.             },
  1164.             // transform is 3x3 matrix_t
  1165.             warp_perspective: function(src, dst, transform, fill_value) {
  1166.                 if (typeof fill_value === "undefined") { fill_value = 0; }
  1167.                 var src_width=src.cols|0, src_height=src.rows|0, dst_width=dst.cols|0, dst_height=dst.rows|0;
  1168.                 var src_d=src.data, dst_d=dst.data;
  1169.                 var x=0,y=0,off=0,ixs=0,iys=0,xs=0.0,ys=0.0,xs0=0.0,ys0=0.0,ws=0.0,sc=0.0,a=0.0,b=0.0,p0=0.0,p1=0.0;
  1170.                 var td=transform.data;
  1171.                 var m00=td[0],m01=td[1],m02=td[2],
  1172.                     m10=td[3],m11=td[4],m12=td[5],
  1173.                     m20=td[6],m21=td[7],m22=td[8];
  1174.  
  1175.                 for(var dptr = 0; y < dst_height; ++y) {
  1176.                     xs0 = m01 * y + m02,
  1177.                     ys0 = m11 * y + m12,
  1178.                     ws  = m21 * y + m22;
  1179.                     for(x = 0; x < dst_width; ++x, ++dptr, xs0+=m00, ys0+=m10, ws+=m20) {
  1180.                         sc = 1.0 / ws;
  1181.                         xs = xs0 * sc, ys = ys0 * sc;
  1182.                         ixs = xs | 0, iys = ys | 0;
  1183.  
  1184.                         if(xs > 0 && ys > 0 && ixs < (src_width - 1) && iys < (src_height - 1)) {
  1185.                             a = Math.max(xs - ixs, 0.0);
  1186.                             b = Math.max(ys - iys, 0.0);
  1187.                             off = (src_width*iys + ixs)|0;
  1188.  
  1189.                             p0 = src_d[off] +  a * (src_d[off+1] - src_d[off]);
  1190.                             p1 = src_d[off+src_width] + a * (src_d[off+src_width+1] - src_d[off+src_width]);
  1191.  
  1192.                             dst_d[dptr] = p0 + b * (p1 - p0);
  1193.                         }
  1194.                         else dst_d[dptr] = fill_value;
  1195.                     }
  1196.                 }
  1197.             },
  1198.             // transform is 3x3 or 2x3 matrix_t only first 6 values referenced
  1199.             warp_affine: function(src, dst, transform, fill_value) {
  1200.                 if (typeof fill_value === "undefined") { fill_value = 0; }
  1201.                 var src_width=src.cols, src_height=src.rows, dst_width=dst.cols, dst_height=dst.rows;
  1202.                 var src_d=src.data, dst_d=dst.data;
  1203.                 var x=0,y=0,off=0,ixs=0,iys=0,xs=0.0,ys=0.0,a=0.0,b=0.0,p0=0.0,p1=0.0;
  1204.                 var td=transform.data;
  1205.                 var m00=td[0],m01=td[1],m02=td[2],
  1206.                     m10=td[3],m11=td[4],m12=td[5];
  1207.  
  1208.                 for(var dptr = 0; y < dst_height; ++y) {
  1209.                     xs = m01 * y + m02;
  1210.                     ys = m11 * y + m12;
  1211.                     for(x = 0; x < dst_width; ++x, ++dptr, xs+=m00, ys+=m10) {
  1212.                         ixs = xs | 0; iys = ys | 0;
  1213.  
  1214.                         if(ixs >= 0 && iys >= 0 && ixs < (src_width - 1) && iys < (src_height - 1)) {
  1215.                             a = xs - ixs;
  1216.                             b = ys - iys;
  1217.                             off = src_width*iys + ixs;
  1218.  
  1219.                             p0 = src_d[off] +  a * (src_d[off+1] - src_d[off]);
  1220.                             p1 = src_d[off+src_width] + a * (src_d[off+src_width+1] - src_d[off+src_width]);
  1221.  
  1222.                             dst_d[dptr] = p0 + b * (p1 - p0);
  1223.                         }
  1224.                         else dst_d[dptr] = fill_value;
  1225.                     }
  1226.                 }
  1227.             },
  1228.            
  1229.             // Basic RGB Skin detection filter
  1230.             // from http://popscan.blogspot.fr/2012/08/skin-detection-in-digital-images.html
  1231.             skindetector: function(src,dst) {
  1232.                 var r,g,b,j;
  1233.                 var i = src.width*src.height;
  1234.                 while(i--){
  1235.                     j = i*4;
  1236.                     r = src.data[j];
  1237.                     g = src.data[j+1];
  1238.                     b = src.data[j+2];
  1239.                     if((r>95)&&(g>40)&&(b>20)
  1240.                      &&(r>g)&&(r>b)
  1241.                      &&(r-Math.min(g,b)>15)
  1242.                      &&(Math.abs(r-g)>15)){
  1243.                          dst[i] = 255;
  1244.                     } else {
  1245.                         dst[i] = 0;
  1246.                     }
  1247.                 }                
  1248.             }
  1249.         };
  1250.     })();
  1251.  
  1252.     global.imgproc = imgproc;
  1253.  
  1254. })(jsfeat);
  1255.  
downloadjsfeat_imgproc.js Source code - Download jsfeat Source code
Related Source Codes/Software:
flakes - Flakes is an Admin Template Framework. A combinati... 2017-04-15
capstone - Capstone disassembly/disassembler framework: Core ... 2017-04-15
nginx-resources - A collection of resources covering Nginx, Nginx + ... 2017-04-15
utron - A lightweight MVC framework for Go(Golang) 2017-04-15
cfssl - CFSSL: Cloudflare's PKI and TLS toolkit ... 2017-04-15
MLeaksFinder - Find memory leaks in your iOS app at develop time. 2017-04-16
qt - Qt binding for Go (Golang) which supports Windows ... 2017-04-16
rainloop-webmail - Simple, modern & fast web-based email client ... 2017-04-16
pencil - Multiplatform GUI Prototyping/Wireframing 2017-04-16
x64dbg - An open-source x64/x32 debugger for windows. ... 2017-04-16
Toucan - Fabulous Image Processing in Swift 2017-04-23
CoffeeScriptRedux - 2017-04-23
breakpoint - Really simple media queries in Sa 2017-04-23
libsvm - 2017-04-22
grr - GRR Rapid Response: remote live forensics for inci... 2017-04-22
grit - **Grit is no longer maintained. Check out libgit2/... 2017-04-22
guard-livereload - Guard::LiveReload automatically reload your browse... 2017-04-22
Begin-Latex-in-minutes - Brief Intro to LaTeX for beginners that helps you ... 2017-04-22
wicked - Use wicked to turn your controller into a wizard ... 2017-04-22
flexboxfroggy - A game for learning CSS flexbox ... 2017-04-22

 Back to top