Loading get-image.php 0 → 100644 +48 −0 Original line number Diff line number Diff line <?php /** * @file get-image.php * @brief combat cross-origin * @copyright Copyright (C) 2016 Elphel Inc. * @author Oleg Dzhimiev <oleg@elphel.com> * * @par <b>License</b>: * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ if (isset($_GET['port'])) $port = $_GET['port']; else die(); if (isset($_GET['rel'])) $rel = $_GET['rel']; else die(); if (isset($_GET['ip'])) $ip = $_GET['ip']; else $ip = "localhost"; /* header("Location: http://{$_SERVER['HTTP_HOST']}:$port/$rel"); die(); */ header('Content-type:image/jpeg'); echo file_get_contents("http://$ip:$port/$rel"); die(); ?> index.html +6 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,12 @@ <script src="js/jquery-ui-1.12.1.custom/jquery-ui.min.js" type="text/javascript"></script> <link rel="stylesheet" type="text/css" href="js/jquery-ui-1.12.1.custom/jquery-ui.theme.min.css" /> --> <script src="js/elphel.js"></script> <script src="js/jcanvas.js"></script> <script src="js/exif.js"></script> <script src="js/jquery-jp4.js"></script> <script src="js/functions.js" type="text/javascript"></script> <script src="js/temperatures.js" type="text/javascript"></script> <script src="js/settings.js" type="text/javascript"></script> Loading js/camogm.js +4 −9 Original line number Diff line number Diff line Loading @@ -98,15 +98,10 @@ function camogm_create_table(){ } function camogm_get_ssd_free_space(mount_en){ // if (mount_en){ // //camogm_cmd("mount",false); // camogm_cmd("get_hdd_space&mount_point=/var/html/CF",false,camogm_parse_hdd_free_space); // //camogm_cmd("unmount",true); // }else{ // camogm_cmd("get_hdd_space&mount_point=/var/html/CF",true,camogm_parse_hdd_free_space); // } camogm_cmd("get_free_space&mount_point=/mnt/sda1",true,camogm_parse_hdd_free_space); //camogm_cmd("unmount",true); console.log("get_free_space is disabled"); //camogm_cmd("get_free_space&mount_point=/mnt/sda1",true,camogm_parse_hdd_free_space); } function camogm_parse_hdd_free_space(data){ Loading js/elphel.js 0 → 100644 +619 −0 Original line number Diff line number Diff line /** * @file elphel.js * @brief functions for pixel manipulation and drawing on canvas * @copyright Copyright (C) 2017 Elphel Inc. * @author Oleg Dzhimiev <oleg@elphel.com> * * @licstart The following is the entire license notice for the * JavaScript code in this page. * * The JavaScript code in this page is free software: you can * redistribute it and/or modify it under the terms of the GNU * General Public License (GNU GPL) as published by the Free Software * Foundation, either version 3 of the License, or (at your option) * any later version. The code is distributed WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU GPL for more details. * * As additional permission under GNU GPL version 3 section 7, you * may distribute non-source (e.g., minimized or compacted) forms of * that code without the copy of the GNU GPL normally required by * section 4, provided you include this license notice and a URL * through which recipients can access the Corresponding Source. * * @licend The above is the entire license notice * for the JavaScript code in this page. */ var Elphel = { // Drawing Canvas:{ /** * Name: putImageData - the same but not the same * Description: - */ putImageData: function(ctx,px,width,height){ var t0 = Date.now(); ctx.canvas.width = width; ctx.canvas.height = height; var imgdata = new ImageData(new Uint8ClampedArray(px), width, height); ctx.putImageData(imgdata,0,0); console.log("drawImageData(): "+(Date.now()-t0)/1000+" s"); /* // new: http://stackoverflow.com/questions/15908179/draw-image-from-pixel-array-on-canvas-with-putimagedata // obsolete: //var img = ctx.createImageData(ctx.canvas.width,ctx.canvas.height); //var imgdata = img.data; // byte-copy?!! for(var i=0;i<(imgdata.length>>2);i++){ imgdata[4*i+0] = px[4*i+0]; imgdata[4*i+1] = px[4*i+1]; imgdata[4*i+2] = px[4*i+2]; imgdata[4*i+3] = px[4*i+3]; } ctx.putImageData(img,0,0); */ }, /** * Name: drawScaled * Description: Plugin specific. Takes source canvas - draws a scaled * version on destination canvas */ drawScaled: function(cnv_src,cnv_dst,width){ var t0 = Date.now(); var ctx = cnv_src[0].getContext('2d'); var tw = ctx.canvas.width; var th = ctx.canvas.height; var tr = tw/th; var sctx = cnv_dst[0].getContext('2d'); var w = Math.round(width); var h = Math.round(w/tr); sctx.canvas.width = w; sctx.canvas.height = h; //cscale = Math.round(w/tw*100)/100; //option 1 //cscale = w/tw; //sctx.scale(cscale,cscale); //sctx.drawImage(cnv_src[0],0,0); // option 2 sctx.drawImage(cnv_src[0],0,0,ctx.canvas.width,ctx.canvas.height,0,0,sctx.canvas.width,sctx.canvas.height); console.log("drawScaled(): "+(Date.now()-t0)/1000+" s"); } }, // Pixel manipulation Pixels:{ /** * Name: reorderJP4Blocks * Description: clear from the function's name * * @pixels - pixel array, read from origin canvas * pixels is a long 1-D array with the following structure: * pix[i+0] - red * pix[i+1] - green * pix[i+2] - blue * pix[i+3] - alpha * @width - origin canvas width * @height - origin canvas height * @format - value comes from exif.js function * 'jpeg' - skip reordering * 'jp4' - jp4 reordeing * 'jp46' - jp46 reordering * @mosaic - [["Gr","R"],["B","Gb"]] - value comes from application * odd lines: Gr,R,Gr,R * even lines: B,Gb,B,Gb * @nwd - true/false - comes from application - demosaicing: 'Nearest Neighbor' with 1/2 scale - * put mosaic (different channels) for GrRBGb into one pixel for * faster performance */ reorderBlocksJPx: function(pixels,width,height,format="JP4",mosaic=[["Gr","R"],["B" ,"Gb"]],nwd=false){ var t0 = Date.now(); // pixels is a long 1-D array with the following structure: // pix[i+0] - red // pix[i+1] - green // pix[i+2] - blue // pix[i+3] - alpha var oPixels = new Uint8Array((nwd)?pixels.length/4:pixels.length); // buffer for reordering pixels var macroblock = new Array(); //16x16 for (var y=0;y<16;y++) macroblock[y]=new Array(); // in JP4 format the 16x16 block is 32x8 (GRBG) // the 1st line of 32x8 blocks is the left half of the image // the 2nd line of 32x8 blocks is the right half // vertical step = 16 pixels for (yb=0;yb<(height>>4);yb++){ // horizontal step = 16 pixels for (xb=0;xb<(width>>4);xb++) { if (format=="JP4") { // 32x8 block reorder into 16x16 for (nb=0;nb<4;nb++) { xbyr= nb&1; // horizontal odd-even ybyr=(nb>>1)&1; // vertical odd-even for (y=0;y<8;y++) { // xb < half image -> 1st line of 32x8 // xb >= half image -> 2nd line of 32x8 //offset=(((yb<<4)+y)*width)+(nb<<3)+((xb>=(width>>5))?(((xb<<5)-width)+(width<<3)):(xb<<5)); offset=(((yb<<4)+y)*width)+(nb<<3)+(xb<<5)+((xb>=(width>>5))?((width<<3)-width):0); for (x=0;x<8;x++) { macroblock[(y<<1)|ybyr][(x<<1)|xbyr]=pixels[4*(offset+x)]; } } } } if (format=="JP46") { for (y=0;y<16;y++) { offset=((yb<<4)+y)*width+(xb<<4); for (x=0;x<16;x++) { //Red value only macroblock[((y<<1)&0xe)|((y>>3)&0x1)][((x<<1)&0xe)|((x>>3)&0x1)]=pixels[4*(offset+x)]; } } } if (nwd){ for (y=0;y<8;y++){ offset=width/2*((yb<<4)/2+y)+(xb<<4)/2; for (x=0;x<8;x++) { for(k=0;k<4;k++){ y0 = 2*y+((k>>1)&1); x0 = 2*x+(k&1); if (mosaic[y0&1][x0&1]=="R") r = macroblock[y0][x0]; else if (mosaic[y0&1][x0&1]=="Gr") gr = macroblock[y0][x0]; else if (mosaic[y0&1][x0&1]=="Gb") gb = macroblock[y0][x0]; else if (mosaic[y0&1][x0&1]=="B") b = macroblock[y0][x0]; } g = (gr+gb)>>1; oPixels[4*(offset+x)+0] = r;//4*(8*y+x); oPixels[4*(offset+x)+1] = g;//4*(8*y+x); oPixels[4*(offset+x)+2] = b;//4*(8*y+x); oPixels[4*(offset+x)+3] = 255; } } }else{ for (y=0;y<16;y++){ offset=width*((yb<<4)+y)+(xb<<4); for (x=0;x<16;x++) { //red +0, green +1, blue +2, alpha +3 // thinking: GRBG oPixels[4*(offset+x)+0] = ((mosaic[y&1][x&1]=="R" ) )?macroblock[y][x]:0; oPixels[4*(offset+x)+1] = ((mosaic[y&1][x&1]=="Gr")||(mosaic[y%2][x%2]=="Gb"))?macroblock[y][x]:0; oPixels[4*(offset+x)+2] = ((mosaic[y&1][x&1]=="B" ) )?macroblock[y][x]:0; oPixels[4*(offset+x)+3] = 255; } } } } } console.log("reorderJP4Blocks: "+(Date.now()-t0)/1000+" s"); return oPixels; }, /** * Name: demosaicNearestNeighbor with downscale * Description: A separate function, just in case, same as in * reorderJP4Blocks * * @pixels - pixel array, read from origin canvas * pixels is a long 1-D array with the following structure: * pix[i+0] - red * pix[i+1] - green * pix[i+2] - blue * pix[i+3] - alpha * @width - origin canvas width * @height - origin canvas height * @mosaic - [["Gr","R"],["B","Gb"]] - value comes from application * odd lines: Gr,R,Gr,R * even lines: B,Gb,B,Gb */ demosaicNearestNeighbor: function(pixels,width,height,mosaic=[["Gr","R"],["B" ,"Gb"]]){ var t0 = Date.now(); var oPixels = new Uint8Array(pixels.length/4); for(var y=0;y<height/2;y++){ for(var x=0;x<width/2;x++){ for(var k=0;k<4;k++){ y0 = (k>>1)&1; x0 = k&1; if (mosaic[y0&1][x0&1]=="R") r = pixels[4*(width*(2*y+y0)+2*x+x0)+0]; else if (mosaic[y0&1][x0&1]=="Gr") gr = pixels[4*(width*(2*y+y0)+2*x+x0)+1]; else if (mosaic[y0&1][x0&1]=="Gb") gb = pixels[4*(width*(2*y+y0)+2*x+x0)+1]; else if (mosaic[y0&1][x0&1]=="B") b = pixels[4*(width*(2*y+y0)+2*x+x0)+2]; } g = (gr+gb)>>1; oPixels[4*(width/2*y+x)+0] = r; oPixels[4*(width/2*y+x)+1] = g; oPixels[4*(width/2*y+x)+2] = b; oPixels[4*(width/2*y+x)+3] = 255; } } console.log("demosaicNearestNeighbor(): "+(Date.now()-t0)/1000+" s"); return oPixels; }, /** * Name: demosaicBilinear * Description: a simple bilinear demosaicing * * @pixels - pixel array, read from origin canvas * pixels is a long 1-D array with the following structure: * pix[i+0] - red * pix[i+1] - green * pix[i+2] - blue * pix[i+3] - alpha * @width - origin canvas width * @height - origin canvas height * @mosaic - [["Gr","R"],["B","Gb"]] - value comes from application * odd lines: Gr,R,Gr,R * even lines: B,Gb,B,Gb * @precise - true/false: * true - calculate values then apply gamma - provide linear pixel array * px_linear (8bit) = px^gamma (32bit), gamma=2 * false - calculate values from gamma encoded pixels - 2-4x times faster */ demosaicBilinear: function(pixels, width, height, mosaic=[["Gr","R"],["B" ,"Gb"]], precise=false){ var t0 = Date.now(); var oPixels = new Uint8Array(pixels.length); var x_l = 0, x_r = 0; var y_t = 0, y_b = 0; var x = width; var y = height; for(var y=0;y<height;y++){ for(var x=0;x<width;x++){ x_l = (x==0)?1:(x-1); x_r = (x==(width-1))?(width-2):(x+1); y_t = (y==0)?1:(y-1); y_b = (y==(height-1))?(height-2):(y+1); //Gr if (mosaic[y%2][x%2]=="Gr"){ Pr_y0xl = pixels[4*(width*(y+0)+(x_l))+0]; Pr_y0xr = pixels[4*(width*(y+0)+(x_r))+0]; Pb_ybx0 = pixels[4*(width*(y_b)+(x+0))+2]; Pb_ytx0 = pixels[4*(width*(y_t)+(x+0))+2]; if (precise){ //Pr = pixel_l2g(1/2*(pixel_g2l(Pr_y0xl)+pixel_g2l(Pr_y0xr))); //Pb = pixel_l2g(1/2*(pixel_g2l(Pb_ybx0)+pixel_g2l(Pb_ytx0))); Pr = this.Functions.l2g(1/2*(Pr_y0xl+Pr_y0xr)); Pb = this.Functions.l2g(1/2*(Pb_ybx0+Pb_ytx0)); }else{ Pr = 1/2*(Pr_y0xl+Pr_y0xr); Pb = 1/2*(Pb_ybx0+Pb_ytx0); } oPixels[4*(width*y+x)+0]=Math.round(Pr); oPixels[4*(width*y+x)+2]=Math.round(Pb); } //R if (mosaic[y%2][x%2]=="R"){ Pg_ytx0 = pixels[4*(width*(y_t)+(x+0))+1]; Pg_y0xl = pixels[4*(width*(y+0)+(x_l))+1]; Pg_y0xr = pixels[4*(width*(y+0)+(x_r))+1]; Pg_ybx0 = pixels[4*(width*(y_b)+(x+0))+1]; Pb_ytxl = pixels[4*(width*(y_t)+(x_l))+2]; Pb_ytxr = pixels[4*(width*(y_t)+(x_r))+2]; Pb_ybxl = pixels[4*(width*(y_b)+(x_l))+2]; Pb_ybxr = pixels[4*(width*(y_b)+(x_r))+2]; if (precise){ Pg = this.Functions.l2g(1/4*(Pg_ytx0+Pg_y0xl+Pg_y0xr+Pg_ybx0)); Pb = this.Functions.l2g(1/4*(Pb_ytxl+Pb_ytxr+Pb_ybxl+Pb_ybxr)); }else{ Pg = 1/4*(Pg_ytx0+Pg_y0xl+Pg_y0xr+Pg_ybx0); Pb = 1/4*(Pb_ytxl+Pb_ytxr+Pb_ybxl+Pb_ybxr); } oPixels[4*(width*y+x)+1]=Math.round(Pg); oPixels[4*(width*y+x)+2]=Math.round(Pb); } //B if (mosaic[y%2][x%2]=="B"){ Pr_ytxl = pixels[4*(width*(y_t)+(x_l))+0]; Pr_ytxr = pixels[4*(width*(y_t)+(x_r))+0]; Pr_ybxl = pixels[4*(width*(y_b)+(x_l))+0]; Pr_ybxr = pixels[4*(width*(y_b)+(x_r))+0]; Pg_ytx0 = pixels[4*(width*(y_t)+(x+0))+1]; Pg_y0xl = pixels[4*(width*(y+0)+(x_l))+1]; Pg_y0xr = pixels[4*(width*(y+0)+(x_r))+1]; Pg_ybx0 = pixels[4*(width*(y_b)+(x+0))+1]; if (precise){ Pr = this.Functions.l2g(1/4*(Pr_ytxl+Pr_ytxr+Pr_ybxl+Pr_ybxr)); Pg = this.Functions.l2g(1/4*(Pg_ytx0+Pg_y0xl+Pg_y0xr+Pg_ybx0)); }else{ Pr = 1/4*(Pr_ytxl+Pr_ytxr+Pr_ybxl+Pr_ybxr); Pg = 1/4*(Pg_ytx0+Pg_y0xl+Pg_y0xr+Pg_ybx0); } oPixels[4*(width*y+x)+0]=Math.round(Pr); oPixels[4*(width*y+x)+1]=Math.round(Pg); } //Gb if (mosaic[y%2][x%2]=="Gb"){ Pr_ytx0 = pixels[4*(width*(y_t)+(x+0))+0]; Pr_ybx0 = pixels[4*(width*(y_b)+(x+0))+0]; Pb_y0xl = pixels[4*(width*(y+0)+(x_l))+2]; Pb_y0xr = pixels[4*(width*(y+0)+(x_r))+2]; if (precise){ Pr = this.Functions.l2g(1/2*(Pr_ytx0+Pr_ybx0)); Pb = this.Functions.l2g(1/2*(Pb_y0xl+Pb_y0xr)); }else{ Pr = 1/2*(Pr_ytx0+Pr_ybx0); Pb = 1/2*(Pb_y0xl+Pb_y0xr); } oPixels[4*(width*y+x)+0]=Math.round(Pr); oPixels[4*(width*y+x)+2]=Math.round(Pb); } } } console.log("demosaicBilinear(): "+(Date.now()-t0)/1000+" s"); return oPixels; }, /** * Name: showSingleColorChannel * Description: make a BW from selected channel * * @pixels - pixel array, read from origin canvas * pixels is a long 1-D array with the following structure: * pix[i+0] - red * pix[i+1] - green * pix[i+2] - blue * pix[i+3] - alpha * @width - origin canvas width (not really needed) * @height - origin canvas height (not really needed) * @channel - string - "red","green","blue" */ showSingleColorChannel: function(pixels, width, height, channel){ for(var y=0;y<height;y++){ for(var x=0;x<width;x++){ r = pixels[4*(width*y+x)+0]; g = pixels[4*(width*y+x)+1]; b = pixels[4*(width*y+x)+2]; if (channel=="red"){ pixels[4*(width*y+x)+0]=r; pixels[4*(width*y+x)+1]=r; pixels[4*(width*y+x)+2]=r; }else if (channel=="green"){ pixels[4*(width*y+x)+0]=g; pixels[4*(width*y+x)+1]=g; pixels[4*(width*y+x)+2]=g; }else if (channel=="blue"){ pixels[4*(width*y+x)+0]=b; pixels[4*(width*y+x)+1]=b; pixels[4*(width*y+x)+2]=b; } } } return pixels; }, /** * Name: applySaturation * Description: get data from ctx saturate and redraw * * @pixels - pixel array, read from origin canvas * pixels is a long 1-D array with the following structure: * pix[i+0] - red * pix[i+1] - green * pix[i+2] - blue * pix[i+3] - alpha * @width - origin canvas width * @height - origin canvas height * @s - saturation coefficient */ applySaturation: function(pixels,width,height,s){ var r,g,b; var Y,Cb,Cr; for(var y=0;y<height;y++){ for(var x=0;x<width;x++){ r = pixels[4*(width*y+x)+0]; g = pixels[4*(width*y+x)+1]; b = pixels[4*(width*y+x)+2]; Y = 0.299*r+0.5870*g+ 0.144*b; Cb = 128+s*(-0.1687*r-0.3313*g+ 0.500*b); Cr = 128+s*( 0.5*r-0.4187*g-0.0813*b); if (Cb<0) Cb=0; if (Cb>255) Cb=255; if (Cr<0) Cr=0; if (Cr>255) Cr=255; r = Y + 1.402*(Cr-128); g = Y - 0.34414*(Cb-128)-0.71414*(Cr-128); b = Y + 1.772*(Cb-128); if (r<0) r=0; if (r>255) r=255; if (g<0) g=0; if (g>255) g=255; if (b<0) b=0; if (b>255) b=255; pixels[4*(width*y+x)+0]=r; pixels[4*(width*y+x)+1]=g; pixels[4*(width*y+x)+2]=b; pixels[4*(width*y+x)+3]=255; } } return pixels; }, /** * Name: diffColorChannels * Description: color channel difference * */ diffColorChannels: function(pixels,chn1,chn2,k=1){ var t0 = Date.now(); var i1 = 0; if (chn1=="green") i1 = 1; if (chn1=="blue") i1 = 2; var i2 = 0; if (chn2=="green") i2 = 1; if (chn2=="blue") i2 = 2; for(var i=0;i<(pixels.length>>2);i++){ diff = k*pixels[4*i+i1] - pixels[4*i+i2]; pixels[4*i+0] = diff; pixels[4*i+1] = diff; pixels[4*i+2] = diff; pixels[4*i+3] = 255; } console.log("diffColorChannels(): "+(Date.now()-t0)/1000+" s"); return pixels; }, /** * Name: ndvi_experimental * Description: get ndvi */ ndvi_experimental: function(pixels){ var r,g,b; var NIR,RED,NDVI; for(var i=0;i<(pixels.length>>2);i++){ r = pixels[4*i+0]; g = pixels[4*i+1]; b = pixels[4*i+2]; if ((b>r)||(g>r)) { console.log("Color error!"); NIR = 0; RED = 1; //if (b>r) pixels[4*(width*y+x)+2]=255; if (b>r) pixels[4*i+2]=0; if (g>r) pixels[4*i+1]=0; pixels[4*i+0]=200; }else{ if ((r-b)<20) b = 0; k = 0.6; RED = (r-g)/(1-k); NIR = (r - RED)*2.5; NDVI = (NIR-RED)/(NIR+RED); //color if (NDVI<0.00){r=0;g= 0;b= 0;} else if (NDVI<0.50){r=200 ;g=400*(0.5-NDVI);b=0;} else if (NDVI<1.00){r=400*(1-NDVI);g=200; b=0;} else{ r = 150; g = 150; b = 150; } //console.log("RED="+RED+" NIR="+NIR); pixels[4*i+0]=r; pixels[4*i+1]=g; pixels[4*i+2]=b; } } return pixels; }, /** * Name: gammaEncode * Description: - */ gammaEncode: function(pixels){ for(var i=0;i<(pixels.length>>2);i++){ pixels[4*i+0] = this.Functions.l2g(pixels[4*i+0]); pixels[4*i+1] = this.Functions.l2g(pixels[4*i+1]); pixels[4*i+2] = this.Functions.l2g(pixels[4*i+2]); } return pixels; }, /** * Name: gammaDecode * Description: - */ gammaDecode: function(pixels){ for(var i=0;i<(pixels.length>>2);i++){ pixels[4*i+0] = this.Functions.g2l(pixels[4*i+0]); pixels[4*i+1] = this.Functions.g2l(pixels[4*i+1]); pixels[4*i+2] = this.Functions.g2l(pixels[4*i+2]); } return pixels; } }, // simple funcitons Functions:{ /** * Name: l2g * Desctiptin: convert a value from linear to gamma encoded, * close to square root */ l2g: function(pv){ // assuming gamma=2 var tmp = Math.sqrt(pv); if (tmp>255) tmp = 255; return tmp; }, /* * Name: g2l * Desctiptin: convert a value gamma encoded to linear, * close to square */ g2l: function(pv){ // assuming gamma = 2 var tmp = pv*pv; return tmp; } }, test: function(){ console.log("Test message from elphel.js: ok"); } } No newline at end of file Loading
get-image.php 0 → 100644 +48 −0 Original line number Diff line number Diff line <?php /** * @file get-image.php * @brief combat cross-origin * @copyright Copyright (C) 2016 Elphel Inc. * @author Oleg Dzhimiev <oleg@elphel.com> * * @par <b>License</b>: * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ if (isset($_GET['port'])) $port = $_GET['port']; else die(); if (isset($_GET['rel'])) $rel = $_GET['rel']; else die(); if (isset($_GET['ip'])) $ip = $_GET['ip']; else $ip = "localhost"; /* header("Location: http://{$_SERVER['HTTP_HOST']}:$port/$rel"); die(); */ header('Content-type:image/jpeg'); echo file_get_contents("http://$ip:$port/$rel"); die(); ?>
index.html +6 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,12 @@ <script src="js/jquery-ui-1.12.1.custom/jquery-ui.min.js" type="text/javascript"></script> <link rel="stylesheet" type="text/css" href="js/jquery-ui-1.12.1.custom/jquery-ui.theme.min.css" /> --> <script src="js/elphel.js"></script> <script src="js/jcanvas.js"></script> <script src="js/exif.js"></script> <script src="js/jquery-jp4.js"></script> <script src="js/functions.js" type="text/javascript"></script> <script src="js/temperatures.js" type="text/javascript"></script> <script src="js/settings.js" type="text/javascript"></script> Loading
js/camogm.js +4 −9 Original line number Diff line number Diff line Loading @@ -98,15 +98,10 @@ function camogm_create_table(){ } function camogm_get_ssd_free_space(mount_en){ // if (mount_en){ // //camogm_cmd("mount",false); // camogm_cmd("get_hdd_space&mount_point=/var/html/CF",false,camogm_parse_hdd_free_space); // //camogm_cmd("unmount",true); // }else{ // camogm_cmd("get_hdd_space&mount_point=/var/html/CF",true,camogm_parse_hdd_free_space); // } camogm_cmd("get_free_space&mount_point=/mnt/sda1",true,camogm_parse_hdd_free_space); //camogm_cmd("unmount",true); console.log("get_free_space is disabled"); //camogm_cmd("get_free_space&mount_point=/mnt/sda1",true,camogm_parse_hdd_free_space); } function camogm_parse_hdd_free_space(data){ Loading
js/elphel.js 0 → 100644 +619 −0 Original line number Diff line number Diff line /** * @file elphel.js * @brief functions for pixel manipulation and drawing on canvas * @copyright Copyright (C) 2017 Elphel Inc. * @author Oleg Dzhimiev <oleg@elphel.com> * * @licstart The following is the entire license notice for the * JavaScript code in this page. * * The JavaScript code in this page is free software: you can * redistribute it and/or modify it under the terms of the GNU * General Public License (GNU GPL) as published by the Free Software * Foundation, either version 3 of the License, or (at your option) * any later version. The code is distributed WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU GPL for more details. * * As additional permission under GNU GPL version 3 section 7, you * may distribute non-source (e.g., minimized or compacted) forms of * that code without the copy of the GNU GPL normally required by * section 4, provided you include this license notice and a URL * through which recipients can access the Corresponding Source. * * @licend The above is the entire license notice * for the JavaScript code in this page. */ var Elphel = { // Drawing Canvas:{ /** * Name: putImageData - the same but not the same * Description: - */ putImageData: function(ctx,px,width,height){ var t0 = Date.now(); ctx.canvas.width = width; ctx.canvas.height = height; var imgdata = new ImageData(new Uint8ClampedArray(px), width, height); ctx.putImageData(imgdata,0,0); console.log("drawImageData(): "+(Date.now()-t0)/1000+" s"); /* // new: http://stackoverflow.com/questions/15908179/draw-image-from-pixel-array-on-canvas-with-putimagedata // obsolete: //var img = ctx.createImageData(ctx.canvas.width,ctx.canvas.height); //var imgdata = img.data; // byte-copy?!! for(var i=0;i<(imgdata.length>>2);i++){ imgdata[4*i+0] = px[4*i+0]; imgdata[4*i+1] = px[4*i+1]; imgdata[4*i+2] = px[4*i+2]; imgdata[4*i+3] = px[4*i+3]; } ctx.putImageData(img,0,0); */ }, /** * Name: drawScaled * Description: Plugin specific. Takes source canvas - draws a scaled * version on destination canvas */ drawScaled: function(cnv_src,cnv_dst,width){ var t0 = Date.now(); var ctx = cnv_src[0].getContext('2d'); var tw = ctx.canvas.width; var th = ctx.canvas.height; var tr = tw/th; var sctx = cnv_dst[0].getContext('2d'); var w = Math.round(width); var h = Math.round(w/tr); sctx.canvas.width = w; sctx.canvas.height = h; //cscale = Math.round(w/tw*100)/100; //option 1 //cscale = w/tw; //sctx.scale(cscale,cscale); //sctx.drawImage(cnv_src[0],0,0); // option 2 sctx.drawImage(cnv_src[0],0,0,ctx.canvas.width,ctx.canvas.height,0,0,sctx.canvas.width,sctx.canvas.height); console.log("drawScaled(): "+(Date.now()-t0)/1000+" s"); } }, // Pixel manipulation Pixels:{ /** * Name: reorderJP4Blocks * Description: clear from the function's name * * @pixels - pixel array, read from origin canvas * pixels is a long 1-D array with the following structure: * pix[i+0] - red * pix[i+1] - green * pix[i+2] - blue * pix[i+3] - alpha * @width - origin canvas width * @height - origin canvas height * @format - value comes from exif.js function * 'jpeg' - skip reordering * 'jp4' - jp4 reordeing * 'jp46' - jp46 reordering * @mosaic - [["Gr","R"],["B","Gb"]] - value comes from application * odd lines: Gr,R,Gr,R * even lines: B,Gb,B,Gb * @nwd - true/false - comes from application - demosaicing: 'Nearest Neighbor' with 1/2 scale - * put mosaic (different channels) for GrRBGb into one pixel for * faster performance */ reorderBlocksJPx: function(pixels,width,height,format="JP4",mosaic=[["Gr","R"],["B" ,"Gb"]],nwd=false){ var t0 = Date.now(); // pixels is a long 1-D array with the following structure: // pix[i+0] - red // pix[i+1] - green // pix[i+2] - blue // pix[i+3] - alpha var oPixels = new Uint8Array((nwd)?pixels.length/4:pixels.length); // buffer for reordering pixels var macroblock = new Array(); //16x16 for (var y=0;y<16;y++) macroblock[y]=new Array(); // in JP4 format the 16x16 block is 32x8 (GRBG) // the 1st line of 32x8 blocks is the left half of the image // the 2nd line of 32x8 blocks is the right half // vertical step = 16 pixels for (yb=0;yb<(height>>4);yb++){ // horizontal step = 16 pixels for (xb=0;xb<(width>>4);xb++) { if (format=="JP4") { // 32x8 block reorder into 16x16 for (nb=0;nb<4;nb++) { xbyr= nb&1; // horizontal odd-even ybyr=(nb>>1)&1; // vertical odd-even for (y=0;y<8;y++) { // xb < half image -> 1st line of 32x8 // xb >= half image -> 2nd line of 32x8 //offset=(((yb<<4)+y)*width)+(nb<<3)+((xb>=(width>>5))?(((xb<<5)-width)+(width<<3)):(xb<<5)); offset=(((yb<<4)+y)*width)+(nb<<3)+(xb<<5)+((xb>=(width>>5))?((width<<3)-width):0); for (x=0;x<8;x++) { macroblock[(y<<1)|ybyr][(x<<1)|xbyr]=pixels[4*(offset+x)]; } } } } if (format=="JP46") { for (y=0;y<16;y++) { offset=((yb<<4)+y)*width+(xb<<4); for (x=0;x<16;x++) { //Red value only macroblock[((y<<1)&0xe)|((y>>3)&0x1)][((x<<1)&0xe)|((x>>3)&0x1)]=pixels[4*(offset+x)]; } } } if (nwd){ for (y=0;y<8;y++){ offset=width/2*((yb<<4)/2+y)+(xb<<4)/2; for (x=0;x<8;x++) { for(k=0;k<4;k++){ y0 = 2*y+((k>>1)&1); x0 = 2*x+(k&1); if (mosaic[y0&1][x0&1]=="R") r = macroblock[y0][x0]; else if (mosaic[y0&1][x0&1]=="Gr") gr = macroblock[y0][x0]; else if (mosaic[y0&1][x0&1]=="Gb") gb = macroblock[y0][x0]; else if (mosaic[y0&1][x0&1]=="B") b = macroblock[y0][x0]; } g = (gr+gb)>>1; oPixels[4*(offset+x)+0] = r;//4*(8*y+x); oPixels[4*(offset+x)+1] = g;//4*(8*y+x); oPixels[4*(offset+x)+2] = b;//4*(8*y+x); oPixels[4*(offset+x)+3] = 255; } } }else{ for (y=0;y<16;y++){ offset=width*((yb<<4)+y)+(xb<<4); for (x=0;x<16;x++) { //red +0, green +1, blue +2, alpha +3 // thinking: GRBG oPixels[4*(offset+x)+0] = ((mosaic[y&1][x&1]=="R" ) )?macroblock[y][x]:0; oPixels[4*(offset+x)+1] = ((mosaic[y&1][x&1]=="Gr")||(mosaic[y%2][x%2]=="Gb"))?macroblock[y][x]:0; oPixels[4*(offset+x)+2] = ((mosaic[y&1][x&1]=="B" ) )?macroblock[y][x]:0; oPixels[4*(offset+x)+3] = 255; } } } } } console.log("reorderJP4Blocks: "+(Date.now()-t0)/1000+" s"); return oPixels; }, /** * Name: demosaicNearestNeighbor with downscale * Description: A separate function, just in case, same as in * reorderJP4Blocks * * @pixels - pixel array, read from origin canvas * pixels is a long 1-D array with the following structure: * pix[i+0] - red * pix[i+1] - green * pix[i+2] - blue * pix[i+3] - alpha * @width - origin canvas width * @height - origin canvas height * @mosaic - [["Gr","R"],["B","Gb"]] - value comes from application * odd lines: Gr,R,Gr,R * even lines: B,Gb,B,Gb */ demosaicNearestNeighbor: function(pixels,width,height,mosaic=[["Gr","R"],["B" ,"Gb"]]){ var t0 = Date.now(); var oPixels = new Uint8Array(pixels.length/4); for(var y=0;y<height/2;y++){ for(var x=0;x<width/2;x++){ for(var k=0;k<4;k++){ y0 = (k>>1)&1; x0 = k&1; if (mosaic[y0&1][x0&1]=="R") r = pixels[4*(width*(2*y+y0)+2*x+x0)+0]; else if (mosaic[y0&1][x0&1]=="Gr") gr = pixels[4*(width*(2*y+y0)+2*x+x0)+1]; else if (mosaic[y0&1][x0&1]=="Gb") gb = pixels[4*(width*(2*y+y0)+2*x+x0)+1]; else if (mosaic[y0&1][x0&1]=="B") b = pixels[4*(width*(2*y+y0)+2*x+x0)+2]; } g = (gr+gb)>>1; oPixels[4*(width/2*y+x)+0] = r; oPixels[4*(width/2*y+x)+1] = g; oPixels[4*(width/2*y+x)+2] = b; oPixels[4*(width/2*y+x)+3] = 255; } } console.log("demosaicNearestNeighbor(): "+(Date.now()-t0)/1000+" s"); return oPixels; }, /** * Name: demosaicBilinear * Description: a simple bilinear demosaicing * * @pixels - pixel array, read from origin canvas * pixels is a long 1-D array with the following structure: * pix[i+0] - red * pix[i+1] - green * pix[i+2] - blue * pix[i+3] - alpha * @width - origin canvas width * @height - origin canvas height * @mosaic - [["Gr","R"],["B","Gb"]] - value comes from application * odd lines: Gr,R,Gr,R * even lines: B,Gb,B,Gb * @precise - true/false: * true - calculate values then apply gamma - provide linear pixel array * px_linear (8bit) = px^gamma (32bit), gamma=2 * false - calculate values from gamma encoded pixels - 2-4x times faster */ demosaicBilinear: function(pixels, width, height, mosaic=[["Gr","R"],["B" ,"Gb"]], precise=false){ var t0 = Date.now(); var oPixels = new Uint8Array(pixels.length); var x_l = 0, x_r = 0; var y_t = 0, y_b = 0; var x = width; var y = height; for(var y=0;y<height;y++){ for(var x=0;x<width;x++){ x_l = (x==0)?1:(x-1); x_r = (x==(width-1))?(width-2):(x+1); y_t = (y==0)?1:(y-1); y_b = (y==(height-1))?(height-2):(y+1); //Gr if (mosaic[y%2][x%2]=="Gr"){ Pr_y0xl = pixels[4*(width*(y+0)+(x_l))+0]; Pr_y0xr = pixels[4*(width*(y+0)+(x_r))+0]; Pb_ybx0 = pixels[4*(width*(y_b)+(x+0))+2]; Pb_ytx0 = pixels[4*(width*(y_t)+(x+0))+2]; if (precise){ //Pr = pixel_l2g(1/2*(pixel_g2l(Pr_y0xl)+pixel_g2l(Pr_y0xr))); //Pb = pixel_l2g(1/2*(pixel_g2l(Pb_ybx0)+pixel_g2l(Pb_ytx0))); Pr = this.Functions.l2g(1/2*(Pr_y0xl+Pr_y0xr)); Pb = this.Functions.l2g(1/2*(Pb_ybx0+Pb_ytx0)); }else{ Pr = 1/2*(Pr_y0xl+Pr_y0xr); Pb = 1/2*(Pb_ybx0+Pb_ytx0); } oPixels[4*(width*y+x)+0]=Math.round(Pr); oPixels[4*(width*y+x)+2]=Math.round(Pb); } //R if (mosaic[y%2][x%2]=="R"){ Pg_ytx0 = pixels[4*(width*(y_t)+(x+0))+1]; Pg_y0xl = pixels[4*(width*(y+0)+(x_l))+1]; Pg_y0xr = pixels[4*(width*(y+0)+(x_r))+1]; Pg_ybx0 = pixels[4*(width*(y_b)+(x+0))+1]; Pb_ytxl = pixels[4*(width*(y_t)+(x_l))+2]; Pb_ytxr = pixels[4*(width*(y_t)+(x_r))+2]; Pb_ybxl = pixels[4*(width*(y_b)+(x_l))+2]; Pb_ybxr = pixels[4*(width*(y_b)+(x_r))+2]; if (precise){ Pg = this.Functions.l2g(1/4*(Pg_ytx0+Pg_y0xl+Pg_y0xr+Pg_ybx0)); Pb = this.Functions.l2g(1/4*(Pb_ytxl+Pb_ytxr+Pb_ybxl+Pb_ybxr)); }else{ Pg = 1/4*(Pg_ytx0+Pg_y0xl+Pg_y0xr+Pg_ybx0); Pb = 1/4*(Pb_ytxl+Pb_ytxr+Pb_ybxl+Pb_ybxr); } oPixels[4*(width*y+x)+1]=Math.round(Pg); oPixels[4*(width*y+x)+2]=Math.round(Pb); } //B if (mosaic[y%2][x%2]=="B"){ Pr_ytxl = pixels[4*(width*(y_t)+(x_l))+0]; Pr_ytxr = pixels[4*(width*(y_t)+(x_r))+0]; Pr_ybxl = pixels[4*(width*(y_b)+(x_l))+0]; Pr_ybxr = pixels[4*(width*(y_b)+(x_r))+0]; Pg_ytx0 = pixels[4*(width*(y_t)+(x+0))+1]; Pg_y0xl = pixels[4*(width*(y+0)+(x_l))+1]; Pg_y0xr = pixels[4*(width*(y+0)+(x_r))+1]; Pg_ybx0 = pixels[4*(width*(y_b)+(x+0))+1]; if (precise){ Pr = this.Functions.l2g(1/4*(Pr_ytxl+Pr_ytxr+Pr_ybxl+Pr_ybxr)); Pg = this.Functions.l2g(1/4*(Pg_ytx0+Pg_y0xl+Pg_y0xr+Pg_ybx0)); }else{ Pr = 1/4*(Pr_ytxl+Pr_ytxr+Pr_ybxl+Pr_ybxr); Pg = 1/4*(Pg_ytx0+Pg_y0xl+Pg_y0xr+Pg_ybx0); } oPixels[4*(width*y+x)+0]=Math.round(Pr); oPixels[4*(width*y+x)+1]=Math.round(Pg); } //Gb if (mosaic[y%2][x%2]=="Gb"){ Pr_ytx0 = pixels[4*(width*(y_t)+(x+0))+0]; Pr_ybx0 = pixels[4*(width*(y_b)+(x+0))+0]; Pb_y0xl = pixels[4*(width*(y+0)+(x_l))+2]; Pb_y0xr = pixels[4*(width*(y+0)+(x_r))+2]; if (precise){ Pr = this.Functions.l2g(1/2*(Pr_ytx0+Pr_ybx0)); Pb = this.Functions.l2g(1/2*(Pb_y0xl+Pb_y0xr)); }else{ Pr = 1/2*(Pr_ytx0+Pr_ybx0); Pb = 1/2*(Pb_y0xl+Pb_y0xr); } oPixels[4*(width*y+x)+0]=Math.round(Pr); oPixels[4*(width*y+x)+2]=Math.round(Pb); } } } console.log("demosaicBilinear(): "+(Date.now()-t0)/1000+" s"); return oPixels; }, /** * Name: showSingleColorChannel * Description: make a BW from selected channel * * @pixels - pixel array, read from origin canvas * pixels is a long 1-D array with the following structure: * pix[i+0] - red * pix[i+1] - green * pix[i+2] - blue * pix[i+3] - alpha * @width - origin canvas width (not really needed) * @height - origin canvas height (not really needed) * @channel - string - "red","green","blue" */ showSingleColorChannel: function(pixels, width, height, channel){ for(var y=0;y<height;y++){ for(var x=0;x<width;x++){ r = pixels[4*(width*y+x)+0]; g = pixels[4*(width*y+x)+1]; b = pixels[4*(width*y+x)+2]; if (channel=="red"){ pixels[4*(width*y+x)+0]=r; pixels[4*(width*y+x)+1]=r; pixels[4*(width*y+x)+2]=r; }else if (channel=="green"){ pixels[4*(width*y+x)+0]=g; pixels[4*(width*y+x)+1]=g; pixels[4*(width*y+x)+2]=g; }else if (channel=="blue"){ pixels[4*(width*y+x)+0]=b; pixels[4*(width*y+x)+1]=b; pixels[4*(width*y+x)+2]=b; } } } return pixels; }, /** * Name: applySaturation * Description: get data from ctx saturate and redraw * * @pixels - pixel array, read from origin canvas * pixels is a long 1-D array with the following structure: * pix[i+0] - red * pix[i+1] - green * pix[i+2] - blue * pix[i+3] - alpha * @width - origin canvas width * @height - origin canvas height * @s - saturation coefficient */ applySaturation: function(pixels,width,height,s){ var r,g,b; var Y,Cb,Cr; for(var y=0;y<height;y++){ for(var x=0;x<width;x++){ r = pixels[4*(width*y+x)+0]; g = pixels[4*(width*y+x)+1]; b = pixels[4*(width*y+x)+2]; Y = 0.299*r+0.5870*g+ 0.144*b; Cb = 128+s*(-0.1687*r-0.3313*g+ 0.500*b); Cr = 128+s*( 0.5*r-0.4187*g-0.0813*b); if (Cb<0) Cb=0; if (Cb>255) Cb=255; if (Cr<0) Cr=0; if (Cr>255) Cr=255; r = Y + 1.402*(Cr-128); g = Y - 0.34414*(Cb-128)-0.71414*(Cr-128); b = Y + 1.772*(Cb-128); if (r<0) r=0; if (r>255) r=255; if (g<0) g=0; if (g>255) g=255; if (b<0) b=0; if (b>255) b=255; pixels[4*(width*y+x)+0]=r; pixels[4*(width*y+x)+1]=g; pixels[4*(width*y+x)+2]=b; pixels[4*(width*y+x)+3]=255; } } return pixels; }, /** * Name: diffColorChannels * Description: color channel difference * */ diffColorChannels: function(pixels,chn1,chn2,k=1){ var t0 = Date.now(); var i1 = 0; if (chn1=="green") i1 = 1; if (chn1=="blue") i1 = 2; var i2 = 0; if (chn2=="green") i2 = 1; if (chn2=="blue") i2 = 2; for(var i=0;i<(pixels.length>>2);i++){ diff = k*pixels[4*i+i1] - pixels[4*i+i2]; pixels[4*i+0] = diff; pixels[4*i+1] = diff; pixels[4*i+2] = diff; pixels[4*i+3] = 255; } console.log("diffColorChannels(): "+(Date.now()-t0)/1000+" s"); return pixels; }, /** * Name: ndvi_experimental * Description: get ndvi */ ndvi_experimental: function(pixels){ var r,g,b; var NIR,RED,NDVI; for(var i=0;i<(pixels.length>>2);i++){ r = pixels[4*i+0]; g = pixels[4*i+1]; b = pixels[4*i+2]; if ((b>r)||(g>r)) { console.log("Color error!"); NIR = 0; RED = 1; //if (b>r) pixels[4*(width*y+x)+2]=255; if (b>r) pixels[4*i+2]=0; if (g>r) pixels[4*i+1]=0; pixels[4*i+0]=200; }else{ if ((r-b)<20) b = 0; k = 0.6; RED = (r-g)/(1-k); NIR = (r - RED)*2.5; NDVI = (NIR-RED)/(NIR+RED); //color if (NDVI<0.00){r=0;g= 0;b= 0;} else if (NDVI<0.50){r=200 ;g=400*(0.5-NDVI);b=0;} else if (NDVI<1.00){r=400*(1-NDVI);g=200; b=0;} else{ r = 150; g = 150; b = 150; } //console.log("RED="+RED+" NIR="+NIR); pixels[4*i+0]=r; pixels[4*i+1]=g; pixels[4*i+2]=b; } } return pixels; }, /** * Name: gammaEncode * Description: - */ gammaEncode: function(pixels){ for(var i=0;i<(pixels.length>>2);i++){ pixels[4*i+0] = this.Functions.l2g(pixels[4*i+0]); pixels[4*i+1] = this.Functions.l2g(pixels[4*i+1]); pixels[4*i+2] = this.Functions.l2g(pixels[4*i+2]); } return pixels; }, /** * Name: gammaDecode * Description: - */ gammaDecode: function(pixels){ for(var i=0;i<(pixels.length>>2);i++){ pixels[4*i+0] = this.Functions.g2l(pixels[4*i+0]); pixels[4*i+1] = this.Functions.g2l(pixels[4*i+1]); pixels[4*i+2] = this.Functions.g2l(pixels[4*i+2]); } return pixels; } }, // simple funcitons Functions:{ /** * Name: l2g * Desctiptin: convert a value from linear to gamma encoded, * close to square root */ l2g: function(pv){ // assuming gamma=2 var tmp = Math.sqrt(pv); if (tmp>255) tmp = 255; return tmp; }, /* * Name: g2l * Desctiptin: convert a value gamma encoded to linear, * close to square */ g2l: function(pv){ // assuming gamma = 2 var tmp = pv*pv; return tmp; } }, test: function(){ console.log("Test message from elphel.js: ok"); } } No newline at end of file