question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

node fromPNG toPNG and generic fromPixels toPixels

See original GitHub issue

I won’t use fromPixels and toPixels in node since It uses Cairo and I’m focused on Windows and Mac. Cairo on Windows apart of having to maintain additional binaries it’s not as easy to install as other OS.

If you are like me that want to keep the binaries to the bare minimum here is a very fast fromPNG and toPNG for node purely using js.

npm install pngjs
const fs      = require('fs'),
const PNG  = require('pngjs').PNG; 

async function fromPNG(path, numChannels)
{
    numChannels = numChannels || 3;
    
    return new Promise((resolve, reject) => 
    {
        fs.createReadStream(path).pipe(
        new PNG({colorType: 6} ))
        .on('parsed', function() 
        {
            resolve( fromPixels(this.data, this.width, this.height, numChannels) );
        })
        .on('error', reject);
    });
}

function toPNG(tensor, path)
{
    let dst     = new PNG({width: tensor.shape[0], height: tensor.shape[1]});
    dst.data    = toPixels(tensor);
    dst.pack().pipe( fs.createWriteStream(path) );
}

function fromPixels(data, width, height, numChannels)
{
    const values    = [];
    const numPix    = width * height;
    
    for (let i = 0; i < numPix; i++) 
        for (let channel = 0; channel < numChannels; ++channel)
            values[i * numChannels + channel] = data[i * 4 + channel];

    let tensor = tf.tensor3d(values, [width, height, numChannels], 'int32');
    
    return tensor;
}

function toPixels(tensor) 
{
    const pixels    = tensor.dataSync();
    const data      = [];
    
    if (tensor.shape.length == 2 || tensor.shape[2] == 1) 
    {
        // Grayscale
        for (let i = 0; i < pixels.length; i++) {
          data[i*4+0] = pixels[i];
          data[i*4+1] = pixels[i];
          data[i*4+2] = pixels[i];
          data[i*4+3] = 255;
        }
        
    } else if (tensor.shape[2] == 3) 
    {
        // RGB
        for (let i = 0; i < pixels.length / 3; i++) 
        {
          data[i*4+0] = pixels[i*3+0];
          data[i*4+1] = pixels[i*3+1];
          data[i*4+2] = pixels[i*3+2];
          data[i*4+3] = 255;
        }
        
    }else if (tensor.shape[2] == 4) 
    {
        // RGBA
        data = pixels;
    }
    
    return data;
}

JPG could be the same using node-jpg. Of course like fromPixels or toPixels assumes that your shapes are going to be [W, H, Channels] maybe you have to swap them if your shapes are [Channels, W, H]. Also you have data on the range [0, 255] so don’t forget to preprocess and postprocess to fit your activations.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:1
  • Comments:8 (7 by maintainers)

github_iconTop GitHub Comments

1reaction
davidsoergelcommented, Oct 5, 2018

Closing based on @nkreeger’s comment. Thanks for the helpful feedback & code, though!

1reaction
nkreegercommented, Oct 5, 2018

@davidsoergel @DavidGOrtega cool nice work - we’re going to be shipping the generated tf.fromPixels() API soon. That’s the official one we want to support since it uses the TF C-library to convert JPEG/PNG/etc byte streams to Tensors in C-land.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Discrepancy between tf.node.decodePng and tf.browser ...
System information Have I written custom code (as opposed to using a stock example script provided in TensorFlow.js): Yes OS Platform and ...
Read more >
Tensorflow.js tf.browser.fromPixels() Function - GeeksforGeeks
... browser or node environment. The tf.browser.fromPixels() function is used to creates a Tensor of pixels values of an specified image.
Read more >
Creates a tf.Tensor with the provided values, shape and dtype.
The key difference between tf.model() and tf.sequential() is that tf.sequential() is less generic, supporting only a linear stack of layers. tf.model() is ...
Read more >
Having trouble transforming tensor created by tf.fromPixels()
What I'm having trouble with is the first layer in the model which takes an input shape of [28, 28] . When I...
Read more >
4. Image Tensors - Learning TensorFlow.js [Book] - O'Reilly
Conversely, images on a server running Node.js will not be sandboxed but lack easy ... toPixels with our tensor and canvas ... fromPixels...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found