Skip to content
New issue

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

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

Already on GitHub? # 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!

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

No branches or pull requests

2 participants