Subscribe Bookmark RSS Feed

Create a JMP Function

Samir7791

Occasional Contributor

Joined:

Feb 7, 2017

Dear everybody,

My knowledge in JMP scripting is small and SAS doesn't allow me to do what I can do in JMP in terms of image processing.

I adapted a little an existing JMP script (JohnPonte) that allow me to generate RGB data from images.

the scripte allow me to do it for one image and I have more than 300 images.

in SAS it is easy for me to create a macro to do it in an automated way but not in JMP.

the input (image) and the output (SAS dataset) will have the same name (in red), this means that the function will have only one argument.

the names of all the images I want treat are stored in JMP dataset (dataset with one column).

Here is the script:

 

NamesDefaultToHere(1);
// Read the image into JMP
img = NewImage("D:\M1_ACTIVE_ZL_T00.jpg");
w = newWindow("image", img);
// Get the pixel values as 3 distinct matrices (red, green and blue)
// RGB colors are in normalized color space (0.0-1.0)
{r, g, b} = img << getPixels("rgb");
// Convert rgb to gray-scale (intensity) matrix
i = 0.3*r + 0.59*g + 0.11*b;
// Get the pixel values as JSL colors then convert to hue, lightness and saturation
// HLS colors are in normalized color space (0.0-1.0)
jslColors = img << getPixels();
{h, l, s} = ColorToHLS(jslColors);
// Get the dimensions of the image/matrices
numRows = nrow(r);
numCols = ncol(r);
// Create a data table
dt = New Table("Image Data",
newColumn("X", set values(repeat(1::numCols, numRows))),
newColumn("Y", set values(shape(repeat(1::numRows,numCols)`,numCols,numRows))),
newColumn("r", set values(r)),
newColumn("g", set values(g)),
newColumn("b", set values(b)),
newColumn("i", set values(i)),
newColumn("h", set values(h)),
newColumn("l", set values(l)),
newColumn("s", set values(s))
);
dt << Save("D:\M1_ACTIVE_ZL_T00.sas7bdat");
Close(dt);
img<<close Window();
w<<close Window(); 

 

Thanks in advance for our help.

 

very kind regards,

 

Samir

 

1 ACCEPTED SOLUTION

Accepted Solutions
txnelson

Super User

Joined:

Jun 22, 2012

Solution

I assume the reason it stopped after only one image is that I mistakenly used the variable "dt" to point to the data table that has the image names in it, and inside the function, it also used the variable "dt", which changed it's value.  This can be easily solved by either localizing the "dt" variable inside of the function, or to just change the variable "dt" outside of the function.  I chose the latter and in the example below, I renamed it to "dtimage"

Names Default To Here( 1 );
// Read the image into JMP M1_ACTIVE_ZL_T00
ImageProcessing = Function( {ImagePath},
	img = New Image( "D:\" || ImagePath || ".jpg" );
	w = New Window( "image", img );
// Get the pixel values as 3 distinct matrices (red, green and blue)
	// RGB colors are in normalized color space (0.0-1.0)
	{r, g, b} = img << getPixels( "rgb" );
// Convert rgb to gray-scale (intensity) matrix
	i = 0.3 * r + 0.59 * g + 0.11 * b;
// Get the pixel values as JSL colors then convert to hue, lightness and saturation
	// HLS colors are in normalized color space (0.0-1.0)
	jslColors = img << getPixels();
	{h, l, s} = Color To HLS( jslColors );
// Get the dimensions of the image/matrices
	numRows = N Row( r );
	numCols = N Col( r );
// Create a data table
	dt = New Table( "Image Data",
		New Column( "X", set values( Repeat( 1 :: numCols, numRows ) ) ),
		New Column( "Y", set values( Shape( Repeat( 1 :: numRows, numCols )`, numCols, numRows ) ) ),
		New Column( "r", set values( r ) ),
		New Column( "g", set values( g ) ),
		New Column( "b", set values( b ) ),
		New Column( "i", set values( i ) ),
		New Column( "h", set values( h ) ),
		New Column( "l", set values( l ) ),
		New Column( "s", set values( s ) )
	);
	dt << Save( "D:\" || ImagePath || ".sas7bdat" );
	Close( dt, nosave );
	img << close Window();
	w << close Window();
);

dtimage = Open( "path to data table with the one column with image names" );

// We will pretend that the column name is "TheImage"
For( i = 1, i <= N Rows( dtimage ), i++,
	return = ImageProcessing( dtimage:TheImage[i] )
);
Jim
10 REPLIES
txnelson

Super User

Joined:

Jun 22, 2012

I will admit, that in the relitive scope of SAS vs. JMP, SAS is a much larger system, but I cannot agree with you that JMP is small.  Here is your script modified very simply that shoul do what you want.  JMP does not have to have a separate Macro language as SAS does, because the language of JMP(JSL) has the code generation, etc built right into it.

Here is the code I came up with

Names Default To Here( 1 );
// Read the image into JMP M1_ACTIVE_ZL_T00
ImageProcessing = Function( {ImagePath},
	img = New Image( "D:\" || ImagePath || ".jpg" );
	w = New Window( "image", img );
// Get the pixel values as 3 distinct matrices (red, green and blue)
	// RGB colors are in normalized color space (0.0-1.0)
	{r, g, b} = img << getPixels( "rgb" );
// Convert rgb to gray-scale (intensity) matrix
	i = 0.3 * r + 0.59 * g + 0.11 * b;
// Get the pixel values as JSL colors then convert to hue, lightness and saturation
	// HLS colors are in normalized color space (0.0-1.0)
	jslColors = img << getPixels();
	{h, l, s} = Color To HLS( jslColors );
// Get the dimensions of the image/matrices
	numRows = N Row( r );
	numCols = N Col( r );
// Create a data table
	dt = New Table( "Image Data",
		New Column( "X", set values( Repeat( 1 :: numCols, numRows ) ) ),
		New Column( "Y", set values( Shape( Repeat( 1 :: numRows, numCols )`, numCols, numRows ) ) ),
		New Column( "r", set values( r ) ),
		New Column( "g", set values( g ) ),
		New Column( "b", set values( b ) ),
		New Column( "i", set values( i ) ),
		New Column( "h", set values( h ) ),
		New Column( "l", set values( l ) ),
		New Column( "s", set values( s ) )
	);
	dt << Save( "D:\" || ImagePath || ".sas7bdat" );
	Close( dt, nosave );
	img << close Window();
	w << close Window();
);

dt = Open( "path to data table with the one column with image names" );

// We will pretend that the column name is "TheImage"
For( i = 1, i <= N Rows( dt ), i++,
	return = ImageProcessing( dt:TheImage[i] )
);
Jim
Samir7791

Occasional Contributor

Joined:

Feb 7, 2017

Dear Jim,

Thanks a lot for the code, It is exactly what I want.

The only problem is that the function execute only the first row of my table.

do you have an idea why?

When I say "Small", I speak about my knowledge of JMP not about JMP :)

vThank in advance for your feedbacks.

Samir

txnelson

Super User

Joined:

Jun 22, 2012

Solution

I assume the reason it stopped after only one image is that I mistakenly used the variable "dt" to point to the data table that has the image names in it, and inside the function, it also used the variable "dt", which changed it's value.  This can be easily solved by either localizing the "dt" variable inside of the function, or to just change the variable "dt" outside of the function.  I chose the latter and in the example below, I renamed it to "dtimage"

Names Default To Here( 1 );
// Read the image into JMP M1_ACTIVE_ZL_T00
ImageProcessing = Function( {ImagePath},
	img = New Image( "D:\" || ImagePath || ".jpg" );
	w = New Window( "image", img );
// Get the pixel values as 3 distinct matrices (red, green and blue)
	// RGB colors are in normalized color space (0.0-1.0)
	{r, g, b} = img << getPixels( "rgb" );
// Convert rgb to gray-scale (intensity) matrix
	i = 0.3 * r + 0.59 * g + 0.11 * b;
// Get the pixel values as JSL colors then convert to hue, lightness and saturation
	// HLS colors are in normalized color space (0.0-1.0)
	jslColors = img << getPixels();
	{h, l, s} = Color To HLS( jslColors );
// Get the dimensions of the image/matrices
	numRows = N Row( r );
	numCols = N Col( r );
// Create a data table
	dt = New Table( "Image Data",
		New Column( "X", set values( Repeat( 1 :: numCols, numRows ) ) ),
		New Column( "Y", set values( Shape( Repeat( 1 :: numRows, numCols )`, numCols, numRows ) ) ),
		New Column( "r", set values( r ) ),
		New Column( "g", set values( g ) ),
		New Column( "b", set values( b ) ),
		New Column( "i", set values( i ) ),
		New Column( "h", set values( h ) ),
		New Column( "l", set values( l ) ),
		New Column( "s", set values( s ) )
	);
	dt << Save( "D:\" || ImagePath || ".sas7bdat" );
	Close( dt, nosave );
	img << close Window();
	w << close Window();
);

dtimage = Open( "path to data table with the one column with image names" );

// We will pretend that the column name is "TheImage"
For( i = 1, i <= N Rows( dtimage ), i++,
	return = ImageProcessing( dtimage:TheImage[i] )
);
Jim
Samir7791

Occasional Contributor

Joined:

Feb 7, 2017

Thank you Jim,

It works now :)

But I replaced also i by j.

I don't undestand why i doesn' work.

Have a nice day,

Samir

 

pmroz

Super User

Joined:

Jun 23, 2011

I would avoid the use of "j" as a variable because it's also a JSL function.  Try "k" instead.

 

J(nrows, <ncols>, <value>)
Description: Creates a matrix of identical values.
Returns: The matrix.
Arguments:
nrows Number of rows in matrix. If ncols is not specified, nrows is also used as ncols.
ncols Number of columns in matrix.
value The value used to populate the matrix. If value is not specified, 1 is used.

txnelson

Super User

Joined:

Jun 22, 2012

I am glad that you caught the "i" variable issue too.  What really should probably be done, is to declare the variables in the function to be local to the function.  This would solve the issue without having to change the variable names

ImageProcessing = Function( {ImagePath},
	{img,w,i,r,g,b,h,l,s,numRows,numCols,dt},
	
Jim
Craige_Hales

Staff

Joined:

Mar 21, 2013

Here's some ideas that might help.

 

dt = New Table( "Untitled",
    Add Rows( 3 ),
    New Column( "name",
        Character,
        "Nominal",
        Set Selected,
        Set Values( {"aaa", "bb", "cccc"} )
    )
);

processFun = Function( {inputfile, outputfile},
    {default local},
    Show( inputfile, outputfile )
);

For( irow = 1, irow <= N Rows( dt ), irow++,
    input = "c:/directory3/" || dt:name[irow] || ".jpg";
    output = "c:/directory2/" || dt:name[irow] || ".png";
    processFun( input, output );
);
/*:

inputfile = "c:/directory3/aaa.jpg";
outputfile = "c:/directory2/aaa.png";
inputfile = "c:/directory3/bb.jpg";
outputfile = "c:/directory2/bb.png";
inputfile = "c:/directory3/cccc.jpg";
outputfile = "c:/directory2/cccc.png";

The example shows a user function "processFun" that has two arguments, and shows a loop reading a data table, and shows some string concatenation operators to build up the names you need.

Craige
Samir7791

Occasional Contributor

Joined:

Feb 7, 2017

Hi Craige,

Thanks a lot for your answer, Am sure I will need this in the nexts days.

Krs,

Samir

M_Anderson

Staff

Joined:

Nov 21, 2014

A related thought - If you have a multi-image file (i.e. an animated GIF or the TIF stacks that are common in microscopy) JMP 13 (windows version only) will load these directly as one data set.  You might consider taking this route and packaging your images into a multi-image file if you have sequential image data.  It also makes maintaining your image archives easier.

 

M