2D Image registration method based on elastic deformations represented by B-splines. The invertibility of the deformations is forced through a consistency restriction.
For all details, visit the home page at bUnwarpJ.
ImageJ/Fiji plugin for consistent elastic registration of 2D images
Home Page: http://imagej.net/BUnwarpJ
License: GNU General Public License v3.0
2D Image registration method based on elastic deformations represented by B-splines. The invertibility of the deformations is forced through a consistency restriction.
For all details, visit the home page at bUnwarpJ.
Hello,
I want to register Tissue Micro Array cores. While it works for many cores, I have some image pairs where image registration fails when performed using the macro call but is perfect if the registration is performed using the plug-in manually with the same settings. Due to the source of the images, their dimensions are not identical. Maybe this causes issues in the macro call? Attached are the results of the macro call and the manual registration as well as the example image pair (zip file). Any idea what could cause this issue?
Thank you and best regards,
Mario
------MACRO CALL------
// ImageJ version: 1.52r
// tested bunwarpJ versions: 2.6.8 ,2.6.9 ,2.6.10 ,2.6.11
// set variables
source ="D:/TMALynch_01_A01__round2_C3.tif";
target ="D:/TMALynch_01_A01__round1_C3.tif";
target_txt=target+ ".txt";
// open images
run("Bio-Formats Windowless Importer", "open=" + target);
run("Bio-Formats Windowless Importer", "open=" + source);
// call bunwarpJ
run("bUnwarpJ", "source_image="+source+" target_image="+target+" registration=Mono image_subsample_factor=2 initial_deformation=[Very Coarse] final_deformation=[Super Fine] divergence_weight=0.1 curl_weight=0.1 landmark_weight=0 image_weight=1 consistency_weight=10 stop_threshold=0.01 save_transformations save_direct_transformation="+target_txt+" ");
Hi @iarganda,
when I call bUnwarpJ through source code, something like this:
final Transformation t = bUnwarpJ_.computeTransformationBatch(
targetImp, sourceImp, null, null,
mode, img_subsamp_fact, min_scale_deformation, max_scale_deformation,
divWeight, curlWeight, landmarkWeight, imageWeight, consistencyWeight, stopThreshold );
and then apply the transformation myself (transforming an ImgLib2 image):
t.transform( u, v, l, true );
The result turns out only to be correct if the sub_samp_fact == 0, otherwise it is somehow not corrected for it. Is there a way to achieve that?
Thanks so much,
Stephan
Dear Ignacio,
first of all, thanks for this useful plugin!
I am rather new to image analysis, since I work on AFM rather then on optical microscopy. Actually I would like to use your elastic registration on several (for the moment 2) elastic modulus maps that I get by AFM on the same object at different angles. I can export my maps as text matrices, where each pixel value represents ร Young's modulus. My averages are around 8-9e07 Pa. I then import those files in ImageJ and save them as tiff. They are saved as 32 bits files, where the decimal values are set to 0. If I directly lunch your plugin in them, the results are pretty weird. If I modify the text images by hand to pass from float to integer values, ImageJ still open the files as 32 bits with decimal part = 0, but the plugin provides some reasonable output, a part from the fact that the registering doesn't really work.
In the end I tried to convert my images to 8 bits (and I realised they need to have the same dynamics at first to be converted without deformation, I am really a novice to ImageJ!), the plugin works really good, providing a very accurate registering.
Anyway, I would be interested in working with the original values, since I would like to apply further algorithms on them.
I would like to ask you if there is a way to run your plugin on my original data, (if there is some pretreatment to do on them for example), or if this is a current limitation of it.
Thanking you in advance,
best regards
Simone
When using multipoints to set landmarks (defining, for example, 10 points in each image) and running bUnwarpJ, an additional 40 landmarks are created on top of each other in the upper left region of each image. Presumably it's maxing out the number of available landmarks as the total is always 50. Also I just noticed they are placed with the minimum y and x values of any placed points, hence appearing normally in the upper left region.
Thanks for the great plugin!
I have observed a seemingly erratic behavior when performing a registration with bUwarpJ
:
Example files:
Notice that all registrations without prior MOPS correspondence extraction fail, i.e. are significantly offset, for the given image pair.
The registrations with prior MOPS fail only for final_deformation
settings of Fine
, Very Fine
, and Super Fine
.
However, the registration with the Coarse
setting yields a reasonable result. Please see example macro:
// Runs an image registration using bUnwarpJ with two images of the same FoV
// with different final_deformation settings.
// toggle MOPS correspondence extraction
with_MOPS = false;
// load source and target images
open("source.tif");
run("Enhance Contrast", "saturated=0.35"); // improves MOPS performance
open("target.tif");
run("Enhance Contrast", "saturated=0.35");
if ( with_MOPS ) {
// identify registration points
run("Extract MOPS Correspondences",
"source_image=target.tif " +
"target_image=source.tif " +
"initial_gaussian_blur=1.60 " +
"steps_per_scale_octave=3 " +
"minimum_image_size=64 " +
"maximum_image_size=3744 " +
"feature_descriptor_size=16 " +
"closest/next_closest_ratio=0.92 " +
"maximal_alignment_error=" + 0.1 * 3744 + " " +
"inlier_ratio=0.05 " +
"expected_transformation=Rigid");
}
// perform registration with different final deformations
final_deformations = newArray("Coarse", "Fine", "Very Fine", "Super Fine");
for ( i = 0; i < final_deformations.length; i++ ) {
run("bUnwarpJ", "source_image=source.tif " +
"target_image=target.tif " +
"registration=Mono " +
"image_subsample_factor=0 " +
"initial_deformation=[Very Coarse] " +
"final_deformation=[" + final_deformations[i] +"] " +
"divergence_weight=0 " +
"curl_weight=0 " +
"landmark_weight=0 " +
"image_weight=1 " +
"consistency_weight=10 " +
"stop_threshold=0.01");
selectWindow("Registered Source Image");
if ( with_MOPS ) {
rename("MOPS + [" + final_deformations[i] + "] - Registered Source Image");
} else {
rename("[" + final_deformations[i] + "] - Registered Source Image");
}
}
This observation could be related to issue #13.
Software:
ImageJ
1.53sbUnwarpJ
2.6.13Windows
10.0.19044.1826Currently, lines 3077-3078 and presumably lines 3158-3159 for colour images (https://github.com/fiji/bUnwarpJ/blame/master/src/main/java/bunwarpj/MiscTools.java#L3077-L3078; https://github.com/fiji/bUnwarpJ/blame/master/src/main/java/bunwarpj/MiscTools.java#L3158-L3159)
are sometimes resulting in a negative image height for the last thread so that a NegativeArraySizeException is thrown when the FloatProcessor constructor is called in line 3096.
For example, when targetHeight = 327 and nProc = 40, then for the last thread block_height == -24.
Commenting out lines 3077-3078 appears to fix this issue, resulting in a last block_height == 15.
Please see this forum thread for more info: https://forum.image.sc/t/install-atlas-toolkit-plugin/32175/10
I have notice an "odd" behavior when using bUnwarpJ: the output pixel value range can exceed the input pixel value range.
Log window output:
Target Image
____Minimum: 0,
____Maximum: 255
Source Image
____Minimum: 0.9607,
____Maximum: 254.9642
Registered Source Image
____Minimum: -2.4964,
____Maximum: 255.3859
What I would have expected is that the histogram of the output (registered) image is a "washed-out" (lower contrast) version of the input histogram - within the same value bounds. However, some pixel exhibit novel values: in particular, values that exceed the input image range.
Here's a simple example ImageJ2 macro:
print("\\Clear");
// load sample as target
run("AuPbSn 40");
run("32-bit"); // grayscale
rename("Target Image");
// rotate copy of target to create source
run("Duplicate...", "title=[Source Image]");
run("Rotate... ", "angle=45 grid=1 interpolation=Bilinear enlarge");
// register source with target using MOPS registration markers
run("Extract MOPS Correspondences", "source_image=[Source Image] target_image=[Target Image] initial_gaussian_blur=1.60 steps_per_scale_octave=3 minimum_image_size=64 maximum_image_size=1024 feature_descriptor_size=16 closest/next_closest_ratio=0.92 maximal_alignment_error=25 inlier_ratio=0.05 expected_transformation=Rigid")
run("bUnwarpJ", "source_image=[Source Image] target_image=[Target Image] registration=Mono image_subsample_factor=0 initial_deformation=[Very Coarse] final_deformation=Fine divergence_weight=0 curl_weight=0 landmark_weight=0 image_weight=1 consistency_weight=10 stop_threshold=0.01");
// display extrema from target and registered source
getExtrema("Target Image"); // within 8-bit range
getExtrema("Source Image"); // within 8-bit range
getExtrema("Registered Source Image"); // exceeds 8-bit range
run("Tile"); // display all windows tiled
function getExtrema(image)
{
selectWindow(image);
print(getTitle());
getRawStatistics(nPixels, mean, min, max);
print(" Minimum: " + min + ",\n Maximum: " + max)
run("Histogram", "bins=1024 use x_min=0 x_max=1023 y_min=min y_max=max");
}
As a workaround, I'm currently clipping the extrema of the output data to match the input data.
// get extrema before registration
getRawStatistics(nPixels, mean, min, max);
// perform registration from source_transform file
call("bunwarpj.bUnwarpJ_.loadElasticTransform", source_transform, "target", "source");
// set extrema after registration
run("Min...", "value=min slice");
run("Max...", "value=max slice");
The observed effect seems to positively correlate with the contrast of the input image. - I am not sure if this is expected behavior: But I basically ended up with fanned out pixel values in my registered recordings when compared to the values of my original recordings.
Best regards,
Chris
There is a bug in both functions used to calculate the transformation - within the while loop (which checks state), there is a switch-case statement, which checks the value of state. Then, within case (state==2), there is an if-else statement that checks if state is 1 or 2, and depending on that, updates the value of state. The case 1 statement is missing a break, so when state == 1 the code goes to the if-else and then executes code within if state==1. Then the rest of the code within case state==2 is executed, which seems suspicious.
My first guess was that the if state==1 piece is supposed to be within the code section of the case statement where state ==1, and then we add a break. However I just determined this does not work, so I am investigating what the likely correction is. It would be helpful to get the author's input as to the intended behavior.
Hi @iarganda,
not sure if this is really an issue, but here it is more visible if other people experience the same problem. I apply the non-rigid transformation myself using Transformation.transform( u, v, l, true );
This works great, however, if I want to save and load the transformation, I end up with:
int intervals;
double[][] cx, double[][] cy;
How do I create a Transformation object out of that in order to use the above method in order to apply it?
Thanks so much,
Stephan
Hi,
I was trying to run this plugin in command line using:
bUnwarpJ_ -align target.jpg NULL source.jpg NULL 0 2 0 0.1 0.1 0 0 output.tif output_2.tif -landmarks 1 landmarks.txt
And this is the output:
Target image : target.jpg
Target mask : NULL
Source image : source.jpg
Source mask : NULL
Min. Scale Deformation : 0
Max. Scale Deformation : 2
Max. Subsampling factor: 0
Div. Weight : 0.1
Curl Weight : 0.1
Image Weight : 0.0
Consistency Weight : 0.0
Output 1 : output.tif
Output 2 : output_2.tif
Landmark Weight : 0.0
Landmark file :
Affine matrix file 1 :
Affine matrix file 2 :
Registration mode : Accurate
Coefficients pyramid 1024x1024
Coefficients pyramid 512x512
Coefficients pyramid 256x256
Image pyramid 1024x1024
Image pyramid 512x512
Image pyramid 256x256
The landmark argument isn't taken into account. Am I missing something here?
Thanks a lot!
--
bUnwrapJ version: 2.6.12
OS: MacOS Catalina
The given link for further details in the README.md to http://biocomp.cnb.csic.es/~iarganda/bUnwarpJ/ redirects to the main homepage https://sites.google.com/site/iargandacarreras/.
Hi,
is it possible to increase the final deformation details beyond the current maximum 'super fine' (16x16)? Long computation times would be acceptable for me.
Many Thanks,
porelius
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.