Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mesh_closest_points.ijm does not mesh closest points #14

Open
pdd2110 opened this issue Jul 15, 2020 · 4 comments
Open

mesh_closest_points.ijm does not mesh closest points #14

pdd2110 opened this issue Jul 15, 2020 · 4 comments

Comments

@pdd2110
Copy link

pdd2110 commented Jul 15, 2020

I was using your mesh_closest_points.ijm as a starting point for a macro and found an error stemming from

Ext.CLIJ2_generateDistanceMatrix(pointlist, pointlist, distance_matrix);

specifically, generateDistanceMatrix() creates a distance matrix of (n+1)*(m+1) pixels, that has all (X, 0) and (0, Y) pixels set to '0' intensity, and the 'desired' distances are shifted by X+1 and Y+1 pixels. For example, if there are 15 points, the distance_matrix is 16x16 pixels, with all pixels at (X, 0) and (0, Y) having intensity value == 0 (i.e. the first row and column, respectively, are black). I'm guessing this is so that the intensity from the label corresponds with the X and/or Y value in the distance_matrix, rather than the index. Either way, this leads to downstream issues, e.g. when generating a Results table from these images, as the corresponding columns are right-shifted and rows are down-shifted due to the blank column1 and row1, thus throwing off the data extraction, adding a point at (0,0), and ignoring the last point (now row/column 16). I'm sure there are other ways to deal with it, but I found that cropping the first row and column of the distance_matrix solved the issue.

Here's the same code with my additions. I left the Ext.CLIJ2_pull(distance_matrix); in there so you can see what I'm referring to, but it's not required. A couple other minor bug fixes and additions too. Either way, thanks for the backbone!

`// CLIJ example macro: mesh_closest_pointsijm
//
// This macro shows how to draw lines between closest points in the GPU.
//
// Author: Robert Haase,
// September 2019
// ---------------------------------------------

// Get test data
run("Blobs (25K)");
//open("C:/structure/data/blobs.gif");
getDimensions(width, height, channels, slices, frames);
input = getTitle();
threshold = 128;

// Init GPU
run("CLIJ2 Macro Extensions", "cl_device=");
Ext.CLIJ2_clear();

// push data to GPU
Ext.CLIJ2_push(input);

// cleanup ImageJ
run("Close All");

// blur
blurred = "blurred";
Ext.CLIJ2_blur2D(input, blurred, 15, 15);

// detect spots
detected_spots = "detected_spots";
Ext.CLIJ2_detectMaximaBox(blurred, detected_spots, 10);

Ext.CLIJ2_pullBinary(detected_spots);

// get spot positions as pointlist
pointlist = "pointlist";
Ext.CLIJ2_spotsToPointList(detected_spots, pointlist);
Ext.CLIJ2_pull(pointlist);

Ext.CLIJ2_getSize(pointlist);
number_of_detected_spots = getResult("Width", nResults() - 1);
IJ.log("number of spots: " + number_of_detected_spots);

// determine distances between points
distance_matrix = "distance_matrix";
Ext.CLIJ2_generateDistanceMatrix(pointlist, pointlist, distance_matrix);
Ext.CLIJ2_pull(distance_matrix);

// crop first row and column of distance_matrix
crop_distance_matrix = "crop_distance_matrix";
Ext.CLIJ2_crop2D(distance_matrix, crop_distance_matrix, 1, 1, number_of_detected_spots, number_of_detected_spots);
Ext.CLIJ2_pull(crop_distance_matrix);

// determine n closest points
n_closest_points = 5;
cropclosestPointsIndices = "cropclosestPointsIndices";
Ext.CLIJ2_nClosestPoints(crop_distance_matrix, cropclosestPointsIndices, n_closest_points);

// empty results table
run("Clear Results");

// we build a table with 2+n rows:
// x and y of the points and n rows with indices to closes points.
// as every points is the closest to itself, row number 3 will always be 0, 1, 3, 4 ...
Ext.CLIJ2_image2DToResultsTable(pointlist);
Ext.CLIJ2_image2DToResultsTable(cropclosestPointsIndices);

crop_mesh = "crop_mesh";
Ext.CLIJ2_create2D(crop_mesh, width, height, 32);
Ext.CLIJ2_set(crop_mesh, 0);

for (p = 0; p < number_of_detected_spots; p++) {
x1 = getResult("X" + p, 0);
y1 = getResult("X" + p, 1);

// we start at 1 (and not at 0) because we 
// don't want to draw line from the point
// to itself
for (q = 1; q < n_closest_points; q++) {
	pointIndex = getResult("X" + p, q + 2);
	x2 = getResult("X" + pointIndex, 0);
	y2 = getResult("X" + pointIndex, 1);

	thickness = 1;
	Ext.CLIJ2_drawLine(crop_mesh, x1, y1, 0, x2, y2, 0, thickness,p);
}

}mesh = "mesh";
Ext.CLIJ2_create2D(mesh, width, height, 32);
Ext.CLIJ2_set(mesh, 0);

for (p = 0; p < number_of_detected_spots; p++) {
x1 = getResult("X" + p, 0);
y1 = getResult("X" + p, 1);

// we start at 1 (and not at 0) because we 
// don't want to draw line from the point
// to itself
for (q = 1; q < n_closest_points; q++) {
	pointIndex = getResult("X" + p, q + 2);
	x2 = getResult("X" + pointIndex, 0);
	y2 = getResult("X" + pointIndex, 1);

	thickness = 1;
	Ext.CLIJ2_drawLine(mesh, x1, y1, 0, x2, y2, 0, thickness, p);
}

}
Table.rename("Results", "closestPointsIndices");
// show result
Ext.CLIJ2_pull(mesh);
run("3-3-2 RGB");`

@haesleinhuepf
Copy link
Member

Hey @pdd2110,

you have a valid point here! In fact, the documentation was misleading. I just updated it to make this aspect clear. Let me know what you think:
https://clij.github.io/clij2-docs/reference_generateDistanceMatrix

Yes, the distance matrix contains an additional entry which is supposed to represent the background. In ImageJ and in CLIJ we do work a lot with label images, where the intensity (1, 2, 3, ...) represents the identifier of the object 1, 2, 3.... 0 usually represents the background, "no object". Thus, you find the distance of object 1 to 2 in the distance matrix in entry [1][2]. Operations such as spotsToPointlist and labelledSpotsToPointlist help to make the correspoinding pointlists from label images.
Furthermore, by thresholding the distance matrix, you can generate a touch matrix which allows you for drawing a mesh. That makes the loop in the example macro obsolete btw. And: without the loop accessing the table it's muuuuch faster. Give it a try ;-) You find example code for doing all this here:
https://clij.github.io/clij2-docs/md/spots_pointlists_matrices_tables/

Anyway, I would like to incorporate your changes in the macro. Do you want to send a pull-request or shall I copy&paste the stuff over?

Thanks for the feedback! You made clij better today!

Cheers,
Robert

@pdd2110
Copy link
Author

pdd2110 commented Jul 15, 2020

Thanks Robert, happy to help! I really appreciate the explanation of how the distance matrix is set up and the "no object" column/row. And thanks for pointing me to how you can use those functions and the example code. I just started playing with CLIJ yesterday, so I'm really proud I was able to contribute!

I'm very new to GitHub (probably second time using it) so it would probably be easier if you copy/paste it over rather than me figuring out how to send a pull-request. (I'll get it eventually, but today is not the day!) An acknowledgement would be cool, but my contribution is really minor comparatively.

Thanks again, really great code and super user-friendly!

Cheers,
Patrick

@haesleinhuepf
Copy link
Member

Alright! Thanks again. If you need further support, I'm also happy to chat on https://image.sc

Cheers,
Robert

@pdd2110
Copy link
Author

pdd2110 commented Jul 15, 2020

Thanks, I'll probably take you up on that!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants