1) Is it possible to bulk read and write image pixel data without iterating width/height and using Image.sample()/Image.setSample()?
Yes. You can use the following methods of the Image object:
void Image.getSamples( Array samples[, Rect rect=0[, int channel=-1]] )Reads pixel values from the specified rectangular area of a channel of the image. If the specified rectangle
rect is a null rectangle (which is the default value), the current rectangular selection is used. If the specified
channel index is < 0, the currently selected channel is used. Pixel values are returned in the specified
samples samples. For example:
var A = [];
var I = new Image;
// ...
// Using specified coordinates
I.getSamples( A, new Rect( 100, 100, 200, 300 ), 0 );
// Using image selections
I.selectedChannel = 0;
I.selectedRect = new Rect( 100, 100, 200, 300 );
I.getSamples( A );void Image.setSamples( Array samples[, Rect rect=0[, int channel=-1]] )Writes pixel values on the specified rectangular area and channel. The rectangular and channel selections work the same as
Image.getSamples().
In addition, you can use image iterators. There are sample iterators, which iterate pixel components on a single channel of the image, and pixel iterators, which iterate pixels from a range of channels. The relevant methods are the following:
void Image.initSampleIterator( [Rect r=0[, int channel=-1]] )Initializes sample iteration. The rectangular and channel selections work as the
Image.getSamples() method.
void Image.initPixelIterator( [Rect r=0[, int firstChannel=-1[, int lastChannel=-1]]] )Initializes pixel iteration for the specified channel range. The rectangular selection works as for the
Image.getSamples() method. If the range defined by
firstChannel and
lastChannel is empty, the current channel selection of the image will be used.
Boolean Image.nextSample()Moves the current sample iterator to the next pixel in the iterated rectangular region. Returns true if the sample iterator points to a valid location within the iterated region, false on an end-of-iteration condition.
Boolean Image.nextPixel()Moves the current pixel iterator to the next pixel in the iterated rectangular region. Returns true if the pixel iterator points to a valid location within the iterated region, false on an end-of-iteration condition.
Number|Complex Image.sampleValue()Returns the value of the current sample iterator. This is the pixel component at the current iterator coordinates on the iterated channel.
void Image.setSampleValue( Number|Complex )Writes the value of the current sample iterator. This changes the value of the pixel component at the current iterator coordinates on the iterated channel.
Vector Image.pixelValue()Returns the components of the current pixel iterator. The components of the returned vector are the pixel components at the current iterator coordinates on the iterated channel range. The first vector component is the pixel component at the first iterated channel, and so on up to and including the last iterated channel.
void Image.getPixelValue( Vector v )Equivalent to Image.pixelValue(), but instead of returning a vector of pixel components stores them in the specified vector
v.
void Image.setPixelValue( Vector )Writes the components of the current pixel iterator. The components of the specified vector will replace the pixel components at the current iterator coordinates on the iterated channel range. The first vector component will replace the pixel component at the first iterated channel, and so on up to and including the last iterated channel.
Here is an example with sample iterators. The following script inverts a rectangular region of the blue channel of the active image.
var w = ImageWindow.activeWindow;
var v = w.currentView;
v.beginProcess();
var I = v.image;
I.initSampleIterator( new Rect( 250, 250, 1000, 1200 ), 2/*blue*/ );
do
{
I.setSampleValue( 1 - I.sampleValue() );
}
while ( I.nextSample() );
v.endProcess();
This is an example with pixel iterators. This script computes a color saturation map (where each pixel is proportional to the maximum separation among color components) for the active image and stores it in its red channel:
var w = ImageWindow.activeWindow;
var v = w.currentView;
v.beginProcess();
var I = v.image;
I.initPixelIterator();
var x = new Vector;
do
{
I.getPixelValue( x );
var d01 = Math.abs( x.at( 0 ) - x.at( 1 ) );
var d02 = Math.abs( x.at( 0 ) - x.at( 2 ) );
var d12 = Math.abs( x.at( 1 ) - x.at( 2 ) );
x.at( 0, Math.max( d01, d02, d12 ) );
x.at( 1, 0 );
x.at( 2, 0 );
I.setPixelValue( x );
}
while ( I.nextPixel() );
v.endProcess();
2) Is it possible to start threads to take heavy computation off the main thread (and to use my 6 core Xeon)?
No. The JavaScript engine does not support multithreading. This is actually a limitation of the JavaScript language, which might change in a future version of the ECMAScript standard, but predictably not in the short-medium term. If you want to implement parallel processing, you can use the PCL C++ development framework to write a PixInsight module.
I plan on implementing an integrated C++ compiler in PixInsight. When this happens, C++ code will be as portable as JavaScript is now. The idea is to deploy C++ source code that will be compiled dynamically on the user's machine, just as JavaScript, but with all the power and performance of C++ and native code. This is a complex and large project; hopefully I'll start working on it next Fall, along with GPU acceleration.
3) I am missing the PJSR documentation.
I am slowly starting to work on the PJSR documentation. I hope to have a first set of documents in July, but most of the documentation will be available after Summer (I really need some vacation!).