2017-07-27 50 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他建議,使用狀態機。