2016-09-24 122 views
0

我只是试图将imagedata转换为高度图,以便在画布上显示。但是当我这样做时,对于我测试过的所有图像都会出现一种奇怪的现象。试图将imagedata转换为高度图

这里是我的代码:

window.onload = function() 
 
{ 
 
\t var canvas = document.getElementById('game'); 
 
\t if(!canvas) 
 
\t { 
 
\t \t alert("Impossible de récupérer le canvas."); 
 
\t \t return; 
 
\t } 
 
\t 
 
\t var context = canvas.getContext('2d'); 
 
\t if(!context) 
 
\t { 
 
\t \t alert("Impossible de récupérer le contexte du canvas."); 
 
\t \t return; \t \t 
 
\t } 
 
\t 
 
\t var img = new Image(); 
 
\t img.src = "noise.png"; 
 
\t 
 
\t var size = 250000; 
 
\t var data = new Float32Array(size); 
 
\t var pxlData = new Array(size); 
 

 
\t for (var i = 0; i < size; i ++) { 
 
     data[i] = 0 
 
    } 
 
\t 
 
\t for (var i = 0; i < size; i++) 
 
\t { 
 
\t \t pxlData[i] = new Array(4); 
 
\t \t pxlData[i][0] = 0; 
 
\t \t pxlData[i][1] = 0; 
 
\t \t pxlData[i][2] = 0; 
 
\t } 
 
\t 
 
\t img.onload = function() 
 
\t { 
 
\t \t context.drawImage(img, 0, 0); 
 
\t \t 
 
\t \t var imgd = context.getImageData(0, 0, 500, 500); 
 
\t 
 
\t \t context.clearRect(0, 0, canvas.width, canvas.height); 
 
\t \t 
 
\t \t var pix = imgd.data; 
 

 
\t \t var j=0; 
 
\t \t var x=0; 
 
\t \t var y=0; 
 
\t \t var i=0; 
 
\t \t 
 
\t \t for (var i = 0, n = pix.length; i < n; i += (4)) { 
 
\t \t \t var all = pix[i]+pix[i+1]+pix[i+2]; 
 
\t \t \t 
 
\t \t \t pxlData[j][0] = pix[i]; 
 
\t \t \t pxlData[j][1] = pix[i+1]; 
 
\t \t \t pxlData[j][2] = pix[i+2]; 
 
\t \t \t pxlData[j][3] = pix[i+3]; 
 
\t \t \t 
 
\t \t \t data[j++] = all/3; 
 
\t \t } \t \t 
 
\t \t 
 
\t \t var alpha; 
 
\t \t 
 
\t \t for(y = 0; y < 500; y++) 
 
\t \t { 
 
\t \t \t for(x = 0; x < 500; x++) 
 
\t \t \t { 
 
\t \t \t \t if(data[x * y] <= 100){ 
 
\t \t \t \t \t context.fillStyle = "blue"; 
 
\t \t \t \t }else if(data[x * y] >= 100){ 
 
\t \t \t \t \t context.fillStyle = "green"; 
 
\t \t \t \t } 
 
\t \t \t \t //context.fillStyle = 'rgba('+ data[x * y] +', '+ data[x * y] +', '+ data[x * y] +', 1)'; 
 
\t \t \t \t context.fillRect(x, y, 1, 1); 
 
\t \t \t \t 
 
\t \t \t \t // context.fillStyle = 'rgba('+ pxlData[x * y][0] +', '+ pxlData[x * y][1] +', '+ pxlData[x * y][2] +', '+ pxlData[x * y][3] +')'; 
 
\t \t \t \t // context.fillRect(x, y, 1, 1); 
 
\t \t \t } 
 
\t \t } 
 
\t }; 
 
\t 
 

 
}
<!DOCTYPE html> 
 
\t <html> 
 
\t \t <head> 
 
\t \t \t <link rel="stylesheet" href="style.css" type="text/css"> 
 
\t \t \t <script type="text/javascript" src="game.js"></script> 
 
\t \t \t <title>Génération de terrain</title> 
 
\t \t </head> 
 
\t \t <body> 
 
\t \t \t <canvas id="game" width="500" height ="500">Votre navigateur ne supporte pas les canvas.</canvas> 
 
\t \t </body> 
 
\t </html>

那就是它的期待,当我运行它,如:

canvas

+0

您试图获得什么效果? – JonSG

回答

0

错误是如何索引的像素32位浮点数组。

你有data[x * y]这意味着在0,0像素将在索引0 * 0 = 0和像素在0,100也将在0 * 100 = 0和所有其他索引将是错误的。为了获得正确的像素地址,使用x + y * width当从一个项目是像素的数组进行索引时使用x + y * width。如果索引为像素数据“imageData.data”每个像素都是4项(R,G,B,A),因此会使用data[x * 4 + y * canvas.width * 4]或者更简单地说imageData.data[x + y * canvas.width * 4]

你的代码看你有创造一些常见的错误,这将使你的代码运行速度比它能做的要慢。我简化了你的代码。它做同样的事情,但没有所有的开销。我添加了评论,删除了您的代码,并提出了相同的替代方法。

最大的变化是渲染绿色和蓝色循环。你在哪里设置每个像素context.fillRect(x,y,1,1);这是非常非常缓慢的。不是为每个像素绘制一个矩形,而是使用您获得的imageData并在读取高度后填充颜色,然后将该数据重新放回画布上。我使用了两个typeArray视图来设置和读取数据,这也提高了性能。

// convert r,g,b,a to 32 bit colour using correct little or big endian 
function create32Pixel(r, g, b, a){ // dont call this inside loops as very slow 
    var endianConvert = new Uint8ClampedArray(4); // use to convert to correct endian 
    var endianConvert32 = new Uint32Array(endianConvert.buffer); 
    endianConvert[0] = r; 
    endianConvert[1] = g; 
    endianConvert[2] = b; 
    endianConvert[3] = a; 
    return endianConvert32[0]; 
} 

window.onload = function() 
{ 
    var canvas = document.getElementById('game'); 
    if(!canvas) 
    { 
     alert("Impossible de récupérer le canvas."); 
     return; 
    } 

    var context = canvas.getContext('2d'); 
    if(!context) 
    { 
     alert("Impossible de récupérer le contexte du canvas."); 
     return;  
    } 

    var img = new Image(); 
    img.src = "noise.png"; 

    var size = 250000; 
    // Do you really need floats?? 16 bit unsigned int array can hold 255 * 3 and all javascript 
    // numbers are converted to 64 bit floats so you will not lose precision from original when manipulating the 16bit values. 
    // following array is not needed. 
    //var dataFloat = new Float32Array(size); 
    // following array is not needed. 
    //var pxlData = new Array(size); // bad way to create an array 
    //var pxlData = []; // create empty array and push onto it. 


    // can use dataFloat.fill() 
    /*for (var i = 0; i < size; i ++) { 
     dataFloat[i] = 0 
    }*/ 
    //dataFloat.fill(0); // but not needed as array is zeroed when created (not from an existing buffer) 

    // Very inefficient as you are creating a new array for every pixel. Use flat array instead. 
    /*for (var i = 0; i < size; i++) 
    { 
     pxlData[i] = new Array(4); 
     pxlData[i][0] = 0; 
     pxlData[i][1] = 0; 
     pxlData[i][2] = 0; 
    }*/ 
    // should do 
    /*var i; 
    while(i < size * 4){ 
     pxlData[i++] = 0; // array grows as you increase i; 
    }*/ 

    img.onload = function() 
    { 
     context.drawImage(img, 0, 0); 

     var imgd = context.getImageData(0, 0, canvas.width, canvas.height); 

     // don't need to clear 
     // context.clearRect(0, 0, canvas.width, canvas.height); 

     // make two views one 8bit and the other 32bit. Both point to the same data change one 
     // changes the other 
     var pixChannels = imgd.data; 
     var pixels = new Uint32Array(pixChannels.buffer); 

     var j,x,y,j; 
     j = x = y = i = 0; 


     // Create pixel colours. Need to ensure correct order as some systems 
     // use little edian and others big endian 
     // see https://en.wikipedia.org/wiki/Endianness for info. 
     var green = create32Pixel(0,255,0,255); 
     var blue = create32Pixel(0,0,255,255); 


     // use j as 32bit pixel index and i as 8bit index 
     // read the height and set pixel colour accordingly. 
     while(j < pixels.length){ 
      var height = pixChannels[i++] + pixChannels[i++] + pixChannels[i++]; 
      if(height <= 300){ // no need to divide by 3 just test for 3 time 100 
       pixels[j++] = blue; 
      }else{ 
       pixels[j++] = green; 
      } 
      i++; // skip alpha channel 
     } 
     context.putImageData(imgd,0,0); // put pixels back to canvas. 

    }; 



}