Updating ImagePlus object with 1D array

What is the best way of updating ImagePlus object with intensity counts I have obtained directly from cameras?

Here a small plugin example which produces a float image and updates the image with random values 10 times. The resetMinAndMax function in this example needs only to be called after the first random values but it might be useful if you have various ranges. Instead of random values fill you 1D array in the update function!

import ij.ImagePlus;
import ij.plugin.PlugIn;
import ij.process.FloatProcessor;

public class My_Plugin implements PlugIn {

	public void run(String arg) {
		FloatProcessor ip = new FloatProcessor(500, 500);
		ImagePlus imp = new ImagePlus("Example", ip);
		imp.show();

		int width = imp.getWidth();
		int height = imp.getHeight();

		for (int i = 0; i < 10; i++) {
			update(ip, width, height);
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			imp.updateAndDraw();
		}

	}

	private void update(FloatProcessor ip, int width, int height) {

		for (int y = 0; y < height; y++) {
			for (int x = 0; x < width; x++)
				ip.putPixelValue(x, y, Math.random() * 10000);

		}
		ip.resetMinAndMax();
	}
}

From the ImageJ API:

updateAndDraw()
Updates this image from the pixel data in its associated ImageProcessor, then displays it. Does nothing if there is no window associated with this image (i.e. show() has not been called).

resetMinAndMax()
Recalculates the min and max values used to scale pixel values to 0-255 for display. This ensures that this FloatProcessor is set up to correctly display the image.

Thanks, triple for loops method works.

But somehow, when I show the ImagePlus object, status bar did not give the correct value.
Calling via ImageProcessor get() method, however, gives the correct value.

Screenshot:
Screenshot 2020-01-21 at 7.59.29 PM

Code:

IJ.log("printing java array: ");
        
        IJ.log("array[" + 1 + "]: " + outarr[0]);
        IJ.log("array[" + (size - 1) + "]: " + outarr[(size - 1)]);
        
        ImageStack ims = new ImageStack();
        update(ims, outarr, 128, 128, 1);
        ImagePlus imp = new ImagePlus("Generated imageplus from 1D array", ims);
        imp.show(); 
        
        IJ.log("printing imp: ");
        double valuefirst = imp.getStack().getProcessor(1).get(0,0);
        double valuelast = imp.getStack().getProcessor(1).get(127,127);
        IJ.log(Double.toString(valuefirst));
        IJ.log(Double.toString(valuelast));
        
        IJ.log("printing ims: ");
        
        IJ.log(Double.toString(ims.getProcessor(1).get(0,0)));
        IJ.log(Double.toString(ims.getProcessor(1).get(127,127)));

Hard to say without a more detailed description and reproducible snippet.

It seems (from the screenshot) three lines are updated but the selection of the status bar shows
x=111, y=10. But you print the values of the array of that line in your example?

You could initialize a first image with reasonable numbers for control.

A little bit of context, the ImageJ plugin is meant to access Camera reading. The native code is written in C and it has JNI interface and interfaces with ImageJ plugin.

The following code basically return a java float array once image has been captured.

public native float [] StartCaptureFrame();

Codes:

package singleframe;


public class singleFrame {
    static{
        System.load("C:/Users/user/Documents/NetBeansProjects/singleframe/src/SingleFrame.dll");
        
    }
    //test
    public native double seyHello(int n1, int n2);
    
    //main
    
    public native void SetParameters();
    public native float [] StartCaptureFrame();
    public native void Terminate();
    
    
}
import ij.plugin.PlugIn;
import ij.IJ;
import ij.gui.GenericDialog;

//NOTE THE NEW IMPORTS
import ij.ImagePlus;
import ij.ImageStack;
import ij.process.ImageProcessor;
import ij.process.FloatProcessor;
import ij.io.FileInfo;

import java.awt.GridLayout;
import java.awt.Point;
import java.awt.Dimension;

import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JLabel;
import java.io.FileWriter;
import singleframe.singleFrame;
import singleframe.singleFrame.*;

public class run_singleFrame_save implements PlugIn {

    private void update(ImageStack imagestack, float[] array1D, int width, int height, int frame) {
        FloatProcessor ip = new FloatProcessor(width, height);
        for (int k = 0; k < height; k++) {
            for (int i = 0; i < width; i++) {
                int index = (frame - 1) * (height * width) + (k * width) + i;
                ip.putPixel(i, k, (int) array1D[index]);
            }
            ip.resetMinAndMax();
        }
        imagestack.addSlice(ip);
    }

    public void run(String arg) {

        int size = (128 * 128);

        new singleframe.singleFrame().seyHello(10, 20);

        //main
        new singleframe.singleFrame().SetParameters();

        float[] outarr = new singleframe.singleFrame().StartCaptureFrame();

        new singleframe.singleFrame().Terminate();

        IJ.log("printing java array: ");
        
        IJ.log("array[" + 1 + "]: " + outarr[0]);
        IJ.log("array[" + (size - 1) + "]: " + outarr[(size - 1)]);
        
        ImageStack ims = new ImageStack();
        update(ims, outarr, 128, 128, 1);
        ImagePlus imp = new ImagePlus("Generated imageplus from 1D array", ims);
        imp.show(); // TODO it does not give the correct value// give absurd number when array is double
        
        IJ.log("printing imp: ");
        double valuefirst = imp.getStack().getProcessor(1).get(0,0);
        double valuelast = imp.getStack().getProcessor(1).get(127,127);
        IJ.log(Double.toString(valuefirst));
        IJ.log(Double.toString(valuelast));
        
        IJ.log("printing ims: ");
        
        IJ.log(Double.toString(ims.getProcessor(1).get(0,0)));
        IJ.log(Double.toString(ims.getProcessor(1).get(127,127)));
        
    }

}

Tiff from ImagePlus object:
If you look at the metadata, bitsperpixel = 32. I am not too sure if there the problem.

Generated imageplus from 1D array.tif (64.2 KB)

What kind of value range do you expect.

Which values are produced before you create the image (the display range of your image is: 1.11E-43 - 1.81E-43!). It might be that there is a number conversion error which comes from you JNI implementation

Please debug.

By the way you create three instances of singleframe whereas only one instance should be used for calling all methods:

 new singleframe.singleFrame().seyHello(10, 20);
 new singleframe.singleFrame().SetParameters();
 new singleframe.singleFrame().Terminate();

to:

singleframe sf=new singleframe();
sf.SetParameters();
sf.Terminate();

Thanks for the notice.
I am pretty sure the JNI call is correct as I am expecting to get value ~100 and I did get these value when called from java.

// value from array
IJ.log("array[" + 0 + "]: " + outarr[0]);
IJ.log("array[" + (size - 1) + "]: " + outarr[(size - 1)]);

// value from imagestack
 IJ.log(Double.toString(ims.getProcessor(1).get(0,0)));
 IJ.log(Double.toString(ims.getProcessor(1).get(127,127)));


It might be that this is the cause (read the conversion rule - also apply it to your original code):

putPixel
Stores the specified value at (x,y). The value is expected to be a float that has been converted to an int using Float.floatToIntBits().

https://imagej.nih.gov/ij/developer/api/ij/process/FloatProcessor.html#putPixel-int-int-int-

Instead of a casting to int you can also use the original float value and use the putPixelValue method, so instead:

 ip.putPixel(i, k, (int) array1D[index]);

use:

 ip.putPixelValue(i, k, array1D[index]);

Since we are using a float processor here.

You can also use a more memory efficient datatype for you range of data if you have only integers, e.g.,:

https://imagej.nih.gov/ij/developer/api/ij/process/ShortProcessor.html
https://imagej.nih.gov/ij/developer/api/ij/process/ByteProcessor.html