2017-07-27 63 views
0

我正在开发一个node.js应用程序,需要通过tcp套接字从光传感器(本质上是摄像头)接收.bmp图像。根据设置,本相机可以以手动触发模式或连续模式(每秒几帧)模式进行拍摄。node.js net.socket客户端接收位图(.bmp)图像

我有一些工作,虽然不是一个理想的解决方案,使用net.sockets。我说不太理想,因为我得到嘈杂的图像,偶尔会出现腐败的图像,有时会错过图像。我知道它不是相机,因为我们已经有了一个.net解决方案,可以可靠且高保真地获取图像。不同之处在于.net解决方案轮询定时器上的传感器,并且net.sockets基于异步事件。

相机固件的设计使得每个图像都会发布一个描述图像的64字节标题(大小以字节,宽度,高度,类型,版本等)。使用标题中的信息,我知道接下来会发生什么。此时,我没有任何改变相机提供图像的方式。也许在未来,一旦我证明目前的固件可以实现某些功能。

我是新来的node.js,我正在寻找更好的解决方案。最终,我希望能够通过socket.io发布接收到的图像以供AngularJS客户端显示。目前,可靠地获取高保真图像并将其写入磁盘就足够了。

下面的代码我现在有工作:

<!-- language: lang-js --> 
let net = require('net'); 
let fs = require('fs'); 
//let stream = require('stream'); //will likely need this 

let client = new net.Socket(); 

const IMAGE_HEADER_SIZE = 64; 
const IMAGE_PREFIX_SIZE = 16; 

let headerImageSizeBytes = 0; 
let headerImageFrameNumber = 0; 
let imageBytesNeeded = 0; 
let imageByteCount = 0; 
let bytesAvailable = 0; 
let bytesRead = 0; 

client.connect(32200, '192.168.0.20', function() // 2MP 
{ 
    //client.bufferSize = 100;  // Doesn't seem to work 
    client.setNoDelay(true); 
    console.log('connected'); 
}); 

client.on('data', function (buffer) { 

    // Do we have a header frame? 
    if (buffer.length == 64) { 
     // Process that header 
     console.log(bytesRead == 0 ? 
      "Acquiring next image" : 
      "Last Image Bytes read = " + bytesRead); 
     bytesRead = 0; 
     headerImageSizeBytes = 0; 

     // Parse the header (Don't need 1st 16 Prefix bytes at this time) 
     var offset = IMAGE_PREFIX_SIZE; 
     headerImageSizeBytes = buffer.readUInt32LE(offset += 4); 
     headerImageFrameNumber = buffer.readUInt32LE(offset += 4); 
     imageBytesNeeded = headerImageSizeBytes; 
     return; 
    } 

    // Collecting image bytes 
    bytesRead += buffer.length; 
    if (bytesRead > 0) { 
     imageByteCount = bytesRead; 

     // TODO: Eventually going to need base64 to render as HTML image via Socket.io 
     fs.appendFile('c:/temp/_IMG_FOLDER/image' 
      + headerImageFrameNumber + '.bmp', buffer, function (err) { 
      if (err) { 
       console.log(err.message); 
      } 
     }); 
     console.log("\t\t" + buffer.length); 
    } 
}); 

client.on('close', function() { 
    console.log('Connection closed'); 
}); 

如何做到这一点的一个快速,高效,可靠的方式任何建议,将不胜感激。

如果你觉得它,一个如何准备图像张贴到我的AngularJS客户端作为图像源显示的例子。

感谢

回答

0

从社区进制窥视,所以我会回答我与我想出了使用状态机来处理标题,然后解决问题落入捕获图像描述的状态。该解决方案以非常可靠的方式生成高质量图像(即更少的图像丢失)。

'use strict';

let net = require('net'); 
let fs = require('fs'); 

let client = new net.Socket(); 

const IMAGE_HEADER_SIZE = 64; 
const IMAGE_PREFIX_SIZE = 16; 
const STATE_INIT = 0; 
const STATE_DATA = 1; 
let state = STATE_INIT; 
let imageData; 
let imageOffset = 0; 


let headerImageSizeBytes = 0; 
let headerImageFrameNumber = 0; 
let imageBytesNeeded = 0; 
let bytesRead = 0; 

client.connect(32200, '192.168.0.20', function() 
{ 
    client.setNoDelay(true); 
    console.log('connected'); 
}); 


client.on('data', function (buffer) { 
    switch (state) { 

    case STATE_INIT: 

     // Ideally we'd have a more robust test here, i.e. consider scenario 
     // where header and image data arrive in same buffer 
     if (buffer.length !== 64) { 
     console.error('unexpected data received (bytes: ' + buffer.length + ')'); 
     return; 
     } 

     console.log(bytesRead == 0 ? 
     "Acquiring next image" : 
     "Last Image Bytes read = " + bytesRead); 
     bytesRead = 0; 
     headerImageSizeBytes = 0; 

     // Parse the header (Don't need 1st 16 Prefix bytes at this time) 
     var offset = IMAGE_PREFIX_SIZE; 
     headerImageSizeBytes = buffer.readUInt32LE(offset += 4); 
     headerImageFrameNumber = buffer.readUInt32LE(offset += 4); 
     imageBytesNeeded = headerImageSizeBytes; 
     imageData = Buffer.alloc(imageBytesNeeded) 
     imageOffset = 0; 
     state = STATE_DATA; 
     break; 

    case STATE_DATA: 
     imageOffset += buffer.copy(imageData, imageOffset); 
     if (imageOffset >= imageBytesNeeded) { 
     fs.appendFile('c:/temp/_FTP_FOLDER/image' + headerImageFrameNumber + '.bmp', imageData, function (err) { 
      if (err) { 
      console.log(err.message); 
      } 
     }); 
     state = STATE_INIT; 
     } // else continue acquiring image until all bytes received 
     break; 
    } 
}); 

client.on('end', function() { 
    console.log('Transimission end'); 
}); 

client.on('close', function() { 
    console.log('Connection closed'); 
}); 

感谢我Intertech collegue @ryanharvey他建议,使用状态机。