Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Other ImageJ Film Restoration macros.
#1
I've been working a bit on using ImageJ as a method for performing various film restoration methods. It is a work in progress and there are quite a few new ideas that I've yet to implement and the code is probably atrocious since I know next to nothing about javascript or imagej macros but what I have so far is:

Image Stabilization (not fully tested)
Color Matching (V2 has many more options)
Film Registration (Needs some fine tuning and batchmode for quicker processing)

I possibly might be able to implement in the future:

Grain Removal
Dirt Removal
16bit color image sequence input/output (using ffmpeg and avi import is probably limited to 8 bit for the time being at least)
Williarob has pitched a few ideas about handling of missing frames that I'm going to try to figure out as well.
Hoping to find a way to utilize more cores/threads for faster speed.

Macro for Stabilization
Code:
Dialog.create("Film Stabilization");
Dialog.addMessage("Stabilize Film Scan:")
Dialog.addChoice("Input File Type:", newArray("AVI", "Using FFmpeg", "Image Sequence"), "AVI");
Dialog.show()
TFT=Dialog.getChoice();
Targetpath = File.openDialog("Select File:");
outputtargetdir = getDirectory("Choose output folder for sprocket stabilized TIF image sequence:");
run(TFT+"...", "open=["+Targetpath+"] sort use");
rename("target");
wait(1000);
setLocation(0,0,360,240);
selectWindow("Log");
setLocation(0,241);
print("Stabilizing...Please Wait.");
run("Image Stabilizer", "output=["+outputtargetdir+"] transformation=Translation maximum_pyramid_levels=1 template_update_coefficient=0.90 maximum_iterations=200 error_tolerance=0.0000001");
print("\\Clear");
close("*");
call("java.lang.System.gc");
beep();
waitForUser("Image stabilization is finished.");

Macro for Color Matching
Code:
Dialog.create("Colormatching");
Dialog.addMessage("Match color of Target film to Source film:")
Dialog.addChoice("Save Target Output Image Sequence As:", newArray("tif", "bmp", "png", "jpeg"), "tif");
//Dialog.addChoice("Save Source Image Sequence As:", newArray("tif", "bmp", "png", "jpeg"), "tif");
Dialog.addString("Prefix text to Output Image Sequence:", "Target");
//Dialog.addString("Prefix text to Source Image Sequence:", "Source");
Dialog.addChoice("Target File Type:", newArray("AVI", "Using FFmpeg", "Image Sequence"), "AVI");
Dialog.addChoice("Source File Type:", newArray("AVI", "Using FFmpeg", "Image Sequence"), "AVI");
//Dialog.addCheckbox("Enable Colormatching", false);
//Dialog.addChoice("Colormatching Direction:", newArray("Source->Target", "Target->Source"), "Source->Target");
Dialog.show()
totype=Dialog.getChoice();
//sotype=Dialog.getChoice();
TPT=Dialog.getString();
SPT="source"//Dialog.getString();
TFT=Dialog.getChoice();
SFT=Dialog.getChoice();
//CM=Dialog.getCheckbox();
//CMD=Dialog.getChoice();
Targetpath = File.openDialog("Select Target File (This file will be colormatched to the source file:");
Sourcepath = File.openDialog("Select Source File:");
outputtargetdir = getDirectory("Choose output folder for color matched TARGET image sequence files:");
//outputsourcedir = getDirectory("Choose output folder for registered SOURCE image sequence files:");
outputlandmarkdir = getDirectory("Choose output folder for Landmark files:");
run(TFT+"...", "open=["+Targetpath+"] sort use");
rename("target");
slices=nSlices();
run(SFT+"...", "open=["+Sourcepath+"] sort use]");
rename("source");

//Search for first frame that contains enough detail for a good transform.
//If colormatching is true, this loop will also ask for user input to confirm cropping.
setBatchMode(true);
var done = false; // used to prematurely terminate loop
for (j=1; j<=slices && !done; j++) {
targetname=TPT+"-"+pad(j);
   sourcename=SPT+"-"+pad(j);
   selectWindow("target");
setSlice(j);
run("Make Substack...", "slices=" +j);
selectWindow("Substack ("+j+")");
   rename(targetname);
   selectWindow("source");
   setSlice(j);
   run("Make Substack...", "slices=" +j);
   selectWindow("Substack ("+j+")");
   rename(sourcename);
   getStatistics(area,mean);
run("Extract SIFT Correspondences", "source_image=["+sourcename+"] target_image=["+targetname+"] initial_gaussian_blur=1.60 steps_per_scale_octave=3 minimum_image_size=64 maximum_image_size=1024 feature_descriptor_size=4 feature_descriptor_orientation_bins=8 closest/next_closest_ratio=0.92 filter maximal_alignment_error=25 minimal_inlier_ratio=0.2 minimal_number_of_inliers=30 expected_transformation=Affine");
   selectWindow(sourcename);
stype0=selectionType();
selectWindow(targetname);
stype1=selectionType();
   if (stype0 & stype1 == 10 && mean > 32) {
    done=true; //terminate the loop
   } else {
close(sourcename);
close(targetname);
   }
}
setBatchMode("exit and display");
//Save the initial transform.
selectWindow(sourcename);
saveAs("Selection", outputlandmarkdir + "source.roi");
selectWindow(targetname);
saveAs("Selection", outputlandmarkdir + "target.roi");
run("Landmark Correspondences", "source_image=["+sourcename+"] template_image=["+targetname+"] transformation_method=[Least Squares] alpha=1 mesh_resolution=32 transformation_class=Affine interpolate");
close(sourcename);
selectWindow("Transformed"+sourcename);
rename(sourcename);
imageCalculator("Multiply create", targetname,sourcename);
setTool("rectangle");
waitForUser("Cropping","Use the Rectangle tool to draw a selection inside the colored/white box\n to crop Target and Source to common active image area.\nMake the selection a bit smaller than the white box to account for gate weave, etc.\nPress OK when finished.\nThe macro will enter batch mode and exit when finished.");
saveAs("Selection", outputlandmarkdir + "cropping.roi");
selectWindow("target");
setSlice(1);
setLocation(0,0,360,240);
selectWindow("source");
setSlice(1);
setLocation(0,241,360,240);
selectWindow("Log");
setLocation(0,481);
close(targetname);
close(sourcename);
close("Result of "+targetname);
setBatchMode(true);
//Start Registration from beginning of clip using initial transform found above as anchor if needed.
//Saves last known good set of correspondences and uses them on frames that have none.
for (i=1; i<=slices; i++) {
showProgress(i,slices);
targetname1=TPT+"-"+pad(i);
sourcename1=SPT+"-"+pad(i);
selectWindow("target");
setSlice(i);
run("Make Substack...", "slices=" +i);
selectWindow("Substack ("+i+")");
rename(targetname1);
selectWindow("source");
setSlice(i);
run("Make Substack...", "slices=" +i);
selectWindow("Substack ("+i+")");
rename(sourcename1);
run("Extract SIFT Correspondences", "source_image=["+sourcename1+"] target_image=["+targetname1+"] initial_gaussian_blur=1.60 steps_per_scale_octave=3 minimum_image_size=64 maximum_image_size=1024 feature_descriptor_size=4 feature_descriptor_orientation_bins=8 closest/next_closest_ratio=0.92 filter maximal_alignment_error=25 minimal_inlier_ratio=0.05 minimal_number_of_inliers=20 expected_transformation=Affine");
selectWindow(sourcename1);
stype2=selectionType();
selectWindow(targetname1);
stype3=selectionType();
if (stype2 & stype3 == 10) {
selectWindow(sourcename1);
saveAs("Selection", outputlandmarkdir + "source.roi");
selectWindow(targetname1);
saveAs("Selection", outputlandmarkdir + "target.roi");
    run("Landmark Correspondences", "source_image=["+sourcename1+"] template_image=["+targetname1+"] transformation_method=[Least Squares] alpha=1 mesh_resolution=32 transformation_class=Affine interpolate");
close(sourcename1);
selectWindow("Transformed"+sourcename1);
rename(sourcename1);
selectWindow(sourcename1);
open(outputlandmarkdir + "cropping.roi");
setBackgroundColor(0, 0, 0);
run("Clear Outside");
run("Select None");
selectWindow(targetname1);
open(outputlandmarkdir + "cropping.roi");
setBackgroundColor(0, 0, 0);
run("Clear Outside");
run("Select None");
selectWindow(targetname1);
run("Split Channels");
selectWindow(sourcename1);
run("Split Channels");
run("Concatenate...", "  title=red image1=["+sourcename1+" (red)] image2=["+targetname1+" (red)] image3=[-- None --]");
run("Concatenate...", "  title=green image1=["+sourcename1+" (green)] image2=["+targetname1+" (green)] image3=[-- None --]");
run("Concatenate...", "  title=blue image1=["+sourcename1+" (blue)] image2=["+targetname1+" (blue)] image3=[-- None --]");
selectWindow("red");
run("Bleach Correction", "correction=[Histogram Matching]");
selectWindow("green");
run("Bleach Correction", "correction=[Histogram Matching]");
selectWindow("blue");
run("Bleach Correction", "correction=[Histogram Matching]");
close("red");
close("green");
close("blue");
selectWindow("DUP_red");
run("Stack to Images");
selectWindow("DUP_green");
run("Stack to Images");
selectWindow("DUP_blue");
run("Stack to Images");
run("Concatenate...", "  title=newsource image1=DUP_red-0001 image2=DUP_green-0001 image3=DUP_blue-0001 image4=[-- None --]");
run("Concatenate...", "  title=newtarget image1=DUP_red-0002 image2=DUP_green-0002 image3=DUP_blue-0002 image4=[-- None --]");
selectWindow("newtarget");
run("Stack to RGB");
close("newtarget");
selectWindow("newsource");
run("Stack to RGB");
close("newsource");
selectWindow("newtarget (RGB)");
rename(targetname1);
saveAs(totype, outputtargetdir + targetname1);
close(targetname1+"."+totype);
selectWindow("newsource (RGB)");
rename(sourcename1);
//saveAs(sotype, outputsourcedir + sourcename1);
close(sourcename1);//+"."+sotype);
} else {
selectWindow(sourcename1);
open(outputlandmarkdir + "source.roi");
selectWindow(targetname1);
open(outputlandmarkdir + "target.roi");
run("Landmark Correspondences", "source_image=["+sourcename1+"] template_image=["+targetname1+"] transformation_method=[Least Squares] alpha=1 mesh_resolution=32 transformation_class=Affine interpolate");
close(sourcename1);
selectWindow("Transformed"+sourcename1);
rename(sourcename1);
selectWindow(sourcename1);
open(outputlandmarkdir + "cropping.roi");
setBackgroundColor(0, 0, 0);
run("Clear Outside");
run("Select None");
selectWindow(targetname1);
open(outputlandmarkdir + "cropping.roi");
setBackgroundColor(0, 0, 0);
run("Clear Outside");
run("Select None");
selectWindow(targetname1);
run("Split Channels");
selectWindow(sourcename1);
run("Split Channels");
run("Concatenate...", "  title=red image1=["+sourcename1+" (red)] image2=["+targetname1+" (red)] image3=[-- None --]");
run("Concatenate...", "  title=green image1=["+sourcename1+" (green)] image2=["+targetname1+" (green)] image3=[-- None --]");
run("Concatenate...", "  title=blue image1=["+sourcename1+" (blue)] image2=["+targetname1+" (blue)] image3=[-- None --]");
selectWindow("red");
run("Bleach Correction", "correction=[Histogram Matching]");
selectWindow("green");
run("Bleach Correction", "correction=[Histogram Matching]");
selectWindow("blue");
run("Bleach Correction", "correction=[Histogram Matching]");
close("red");
close("green");
close("blue");
selectWindow("DUP_red");
run("Stack to Images");
selectWindow("DUP_green");
run("Stack to Images");
selectWindow("DUP_blue");
run("Stack to Images");
run("Concatenate...", "  title=newsource image1=DUP_red-0001 image2=DUP_green-0001 image3=DUP_blue-0001 image4=[-- None --]");
run("Concatenate...", "  title=newtarget image1=DUP_red-0002 image2=DUP_green-0002 image3=DUP_blue-0002 image4=[-- None --]");
selectWindow("newtarget");
run("Stack to RGB");
close("newtarget");
selectWindow("newsource");
run("Stack to RGB");
close("newsource");
selectWindow("newtarget (RGB)");
rename(targetname1);
saveAs(totype, outputtargetdir + targetname1);
close(targetname1+"."+totype);
selectWindow("newsource (RGB)");
rename(sourcename1);
//saveAs(sotype, outputsourcedir + sourcename1);
close(sourcename1);//+"."+sotype);
}
print("\\Clear");
//run("Collect Garbage");
call("java.lang.System.gc");
}

setBatchMode(false);
close("*");
//run("Collect Garbage");
call("java.lang.System.gc");
beep();
waitForUser("The color matching macro is finished.");

function pad(n) {
    str = toString(n);
    while (lengthOf(str)<6)
    str = "0" + str;
    return str;
}

Macro for Color Matching V2
Code:
Dialog.create("Fast Film Registration with optional Colormatching");
Dialog.addMessage("Register Source film to Target film")
Dialog.addChoice("Save Target Image Sequence As:", newArray("tif", "bmp", "png", "jpeg"), "tif");
Dialog.addChoice("Save Source Image Sequence As:", newArray("tif", "bmp", "png", "jpeg"), "tif");
Dialog.addString("Prefix text to Target Image Sequence:", "Target");
Dialog.addString("Prefix text to Source Image Sequence:", "Source");
Dialog.addChoice("Target File Type:", newArray("AVI", "Using FFmpeg", "Image Sequence"), "AVI");
Dialog.addChoice("Source File Type:", newArray("AVI", "Using FFmpeg", "Image Sequence"), "AVI");
Dialog.addCheckbox("Enable Colormatching", false);
Dialog.addChoice("Colormatching Direction:", newArray("Source->Target", "Target->Source"), "Source->Target");
Dialog.show()
totype=Dialog.getChoice();
sotype=Dialog.getChoice();
TPT=Dialog.getString();
SPT=Dialog.getString();
TFT=Dialog.getChoice();
SFT=Dialog.getChoice();
CM=Dialog.getCheckbox();
CMD=Dialog.getChoice();
Targetpath = File.openDialog("Select Target File");
Sourcepath = File.openDialog("Select Source File (this file will be deformed to match the Target File)");
outputtargetdir = getDirectory("Choose output folder for registered TARGET image sequence files:");
outputsourcedir = getDirectory("Choose output folder for registered SOURCE image sequence files:");
outputlandmarkdir = getDirectory("Choose output folder for Landmark files:");
run(TFT+"...", "open=["+Targetpath+"] sort use");
rename("target");
slices=nSlices();
run(SFT+"...", "open=["+Sourcepath+"] sort use]");
rename("source");

//Search for first frame that contains enough detail for a good transform.
//If colormatching is true, this loop will also ask for user input to confirm cropping.
setBatchMode(true);
var done = false; // used to prematurely terminate loop
for (j=1; j<=slices && !done; j++) {
targetname=TPT+"-"+pad(j);
   sourcename=SPT+"-"+pad(j);
   selectWindow("target");
setSlice(j);
run("Make Substack...", "slices=" +j);
selectWindow("Substack ("+j+")");
   rename(targetname);
   selectWindow("source");
   setSlice(j);
   run("Make Substack...", "slices=" +j);
   selectWindow("Substack ("+j+")");
   rename(sourcename);
   getStatistics(area,mean);
run("Extract SIFT Correspondences", "source_image=["+sourcename+"] target_image=["+targetname+"] initial_gaussian_blur=1.60 steps_per_scale_octave=3 minimum_image_size=64 maximum_image_size=1024 feature_descriptor_size=4 feature_descriptor_orientation_bins=8 closest/next_closest_ratio=0.92 filter maximal_alignment_error=25 minimal_inlier_ratio=0.2 minimal_number_of_inliers=30 expected_transformation=Affine");
   selectWindow(sourcename);
stype0=selectionType();
selectWindow(targetname);
stype1=selectionType();
   if (stype0 & stype1 == 10 && mean > 32) {
    done=true; //terminate the loop
   } else {
close(sourcename);
close(targetname);
   }
}
setBatchMode("exit and display");
//Save the initial transform.
selectWindow(sourcename);
saveAs("Selection", outputlandmarkdir + "source.roi");
selectWindow(targetname);
saveAs("Selection", outputlandmarkdir + "target.roi");
run("Landmark Correspondences", "source_image=["+sourcename+"] template_image=["+targetname+"] transformation_method=[Least Squares] alpha=1 mesh_resolution=32 transformation_class=Affine interpolate");
close(sourcename);
selectWindow("Transformed"+sourcename);
rename(sourcename);
imageCalculator("Multiply create", targetname,sourcename);
setTool("rectangle");
waitForUser("Cropping","Use the Rectangle tool to draw a selection inside the white box\n to crop Target and Source to common active image area.\nMake the selection a bit smaller than the white box to account for gate weave, etc.\nPress OK when finished.\nThe macro will enter batch mode and exit when finished.");
saveAs("Selection", outputlandmarkdir + "cropping.roi");
selectWindow("target");
setSlice(1);
setLocation(0,0,360,240);
selectWindow("source");
setSlice(1);
setLocation(0,241,360,240);
selectWindow("Log");
setLocation(0,481);
close(targetname);
close(sourcename);
close("Result of "+targetname);
setBatchMode(true);
//Start Registration from beginning of clip using initial transform found above as anchor if needed.
//Saves last known good set of correspondences and uses them on frames that have none.
for (i=1; i<=slices; i++) {
showProgress(i,slices);
targetname1=TPT+"-"+pad(i);
sourcename1=SPT+"-"+pad(i);
selectWindow("target");
setSlice(i);
run("Make Substack...", "slices=" +i);
selectWindow("Substack ("+i+")");
rename(targetname1);
selectWindow("source");
setSlice(i);
run("Make Substack...", "slices=" +i);
selectWindow("Substack ("+i+")");
rename(sourcename1);
run("Extract SIFT Correspondences", "source_image=["+sourcename1+"] target_image=["+targetname1+"] initial_gaussian_blur=1.60 steps_per_scale_octave=3 minimum_image_size=64 maximum_image_size=1024 feature_descriptor_size=4 feature_descriptor_orientation_bins=8 closest/next_closest_ratio=0.92 filter maximal_alignment_error=25 minimal_inlier_ratio=0.05 minimal_number_of_inliers=20 expected_transformation=Affine");
selectWindow(sourcename1);
stype2=selectionType();
selectWindow(targetname1);
stype3=selectionType();
if (stype2 & stype3 == 10) {
selectWindow(sourcename1);
saveAs("Selection", outputlandmarkdir + "source.roi");
selectWindow(targetname1);
saveAs("Selection", outputlandmarkdir + "target.roi");
    run("Landmark Correspondences", "source_image=["+sourcename1+"] template_image=["+targetname1+"] transformation_method=[Least Squares] alpha=1 mesh_resolution=32 transformation_class=Affine interpolate");
close(sourcename1);
selectWindow("Transformed"+sourcename1);
rename(sourcename1);
if (CM==false){
selectWindow(sourcename1);
open(outputlandmarkdir + "cropping.roi");
setBackgroundColor(0, 0, 0);
run("Clear Outside");
run("Select None");
saveAs(sotype, outputsourcedir + sourcename1);
close(sourcename1+"."+sotype);
selectWindow(targetname1);
open(outputlandmarkdir + "cropping.roi");
setBackgroundColor(0, 0, 0);
run("Clear Outside");
run("Select None");
saveAs(totype, outputtargetdir + targetname1);
close(targetname1+"."+totype);
} else if (CM==true && CMD=="Source->Target") {
selectWindow(sourcename1);
open(outputlandmarkdir + "cropping.roi");
setBackgroundColor(0, 0, 0);
run("Clear Outside");
run("Select None");
selectWindow(targetname1);
open(outputlandmarkdir + "cropping.roi");
setBackgroundColor(0, 0, 0);
run("Clear Outside");
run("Select None");
selectWindow(targetname1);
run("Split Channels");
selectWindow(sourcename1);
run("Split Channels");
run("Concatenate...", "  title=red image1=["+targetname1+" (red)] image2=["+sourcename1+" (red)] image3=[-- None --]");
run("Concatenate...", "  title=green image1=["+targetname1+" (green)] image2=["+sourcename1+" (green)] image3=[-- None --]");
run("Concatenate...", "  title=blue image1=["+targetname1+" (blue)] image2=["+sourcename1+" (blue)] image3=[-- None --]");
selectWindow("red");
run("Bleach Correction", "correction=[Histogram Matching]");
selectWindow("green");
run("Bleach Correction", "correction=[Histogram Matching]");
selectWindow("blue");
run("Bleach Correction", "correction=[Histogram Matching]");
close("red");
close("green");
close("blue");
selectWindow("DUP_red");
run("Stack to Images");
selectWindow("DUP_green");
run("Stack to Images");
selectWindow("DUP_blue");
run("Stack to Images");
run("Concatenate...", "  title=newtarget image1=DUP_red-0001 image2=DUP_green-0001 image3=DUP_blue-0001 image4=[-- None --]");
run("Concatenate...", "  title=newsource image1=DUP_red-0002 image2=DUP_green-0002 image3=DUP_blue-0002 image4=[-- None --]");
selectWindow("newtarget");
run("Stack to RGB");
close("newtarget");
selectWindow("newsource");
run("Stack to RGB");
close("newsource");
selectWindow("newtarget (RGB)");
rename(targetname1);
saveAs(totype, outputtargetdir + targetname1);
close(targetname1+"."+totype);
selectWindow("newsource (RGB)");
rename(sourcename1);
saveAs(sotype, outputsourcedir + sourcename1);
close(sourcename1+"."+sotype);// if (CM==true && CMD=="Target->Source")
} else {
selectWindow(sourcename1);
open(outputlandmarkdir + "cropping.roi");
setBackgroundColor(0, 0, 0);
run("Clear Outside");
run("Select None");
selectWindow(targetname1);
open(outputlandmarkdir + "cropping.roi");
setBackgroundColor(0, 0, 0);
run("Clear Outside");
run("Select None");
selectWindow(targetname1);
run("Split Channels");
selectWindow(sourcename1);
run("Split Channels");
run("Concatenate...", "  title=red image1=["+sourcename1+" (red)] image2=["+targetname1+" (red)] image3=[-- None --]");
run("Concatenate...", "  title=green image1=["+sourcename1+" (green)] image2=["+targetname1+" (green)] image3=[-- None --]");
run("Concatenate...", "  title=blue image1=["+sourcename1+" (blue)] image2=["+targetname1+" (blue)] image3=[-- None --]");
selectWindow("red");
run("Bleach Correction", "correction=[Histogram Matching]");
selectWindow("green");
run("Bleach Correction", "correction=[Histogram Matching]");
selectWindow("blue");
run("Bleach Correction", "correction=[Histogram Matching]");
close("red");
close("green");
close("blue");
selectWindow("DUP_red");
run("Stack to Images");
selectWindow("DUP_green");
run("Stack to Images");
selectWindow("DUP_blue");
run("Stack to Images");
run("Concatenate...", "  title=newsource image1=DUP_red-0001 image2=DUP_green-0001 image3=DUP_blue-0001 image4=[-- None --]");
run("Concatenate...", "  title=newtarget image1=DUP_red-0002 image2=DUP_green-0002 image3=DUP_blue-0002 image4=[-- None --]");
selectWindow("newtarget");
run("Stack to RGB");
close("newtarget");
selectWindow("newsource");
run("Stack to RGB");
close("newsource");
selectWindow("newtarget (RGB)");
rename(targetname1);
saveAs(totype, outputtargetdir + targetname1);
close(targetname1+"."+totype);
selectWindow("newsource (RGB)");
rename(sourcename1);
saveAs(sotype, outputsourcedir + sourcename1);
close(sourcename1+"."+sotype);
}
} else {
selectWindow(sourcename1);
open(outputlandmarkdir + "source.roi");
selectWindow(targetname1);
open(outputlandmarkdir + "target.roi");
run("Landmark Correspondences", "source_image=["+sourcename1+"] template_image=["+targetname1+"] transformation_method=[Least Squares] alpha=1 mesh_resolution=32 transformation_class=Affine interpolate");
close(sourcename1);
selectWindow("Transformed"+sourcename1);
rename(sourcename1);
if (CM==false){
selectWindow(sourcename1);
open(outputlandmarkdir + "cropping.roi");
setBackgroundColor(0, 0, 0);
run("Clear Outside");
run("Select None");
saveAs(sotype, outputsourcedir + sourcename1);
close(sourcename1+"."+sotype);
selectWindow(targetname1);
open(outputlandmarkdir + "cropping.roi");
setBackgroundColor(0, 0, 0);
run("Clear Outside");
run("Select None");
saveAs(totype, outputtargetdir + targetname1);
close(targetname1+"."+totype);
} else if (CM==true && CMD=="Source->Target") {
selectWindow(sourcename1);
open(outputlandmarkdir + "cropping.roi");
setBackgroundColor(0, 0, 0);
run("Clear Outside");
run("Select None");
selectWindow(targetname1);
open(outputlandmarkdir + "cropping.roi");
setBackgroundColor(0, 0, 0);
run("Clear Outside");
run("Select None");
selectWindow(targetname1);
run("Split Channels");
selectWindow(sourcename1);
run("Split Channels");
run("Concatenate...", "  title=red image1=["+targetname1+" (red)] image2=["+sourcename1+" (red)] image3=[-- None --]");
run("Concatenate...", "  title=green image1=["+targetname1+" (green)] image2=["+sourcename1+" (green)] image3=[-- None --]");
run("Concatenate...", "  title=blue image1=["+targetname1+" (blue)] image2=["+sourcename1+" (blue)] image3=[-- None --]");
selectWindow("red");
run("Bleach Correction", "correction=[Histogram Matching]");
selectWindow("green");
run("Bleach Correction", "correction=[Histogram Matching]");
selectWindow("blue");
run("Bleach Correction", "correction=[Histogram Matching]");
close("red");
close("green");
close("blue");
selectWindow("DUP_red");
run("Stack to Images");
selectWindow("DUP_green");
run("Stack to Images");
selectWindow("DUP_blue");
run("Stack to Images");
run("Concatenate...", "  title=newtarget image1=DUP_red-0001 image2=DUP_green-0001 image3=DUP_blue-0001 image4=[-- None --]");
run("Concatenate...", "  title=newsource image1=DUP_red-0002 image2=DUP_green-0002 image3=DUP_blue-0002 image4=[-- None --]");
selectWindow("newtarget");
run("Stack to RGB");
close("newtarget");
selectWindow("newsource");
run("Stack to RGB");
close("newsource");
selectWindow("newtarget (RGB)");
rename(targetname1);
saveAs(totype, outputtargetdir + targetname1);
close(targetname1+"."+totype);
selectWindow("newsource (RGB)");
rename(sourcename1);
saveAs(sotype, outputsourcedir + sourcename1);
close(sourcename1+"."+sotype);//if (CM==true && CMD=="Target->Source")
} else {
selectWindow(sourcename1);
open(outputlandmarkdir + "cropping.roi");
setBackgroundColor(0, 0, 0);
run("Clear Outside");
run("Select None");
selectWindow(targetname1);
open(outputlandmarkdir + "cropping.roi");
setBackgroundColor(0, 0, 0);
run("Clear Outside");
run("Select None");
selectWindow(targetname1);
run("Split Channels");
selectWindow(sourcename1);
run("Split Channels");
run("Concatenate...", "  title=red image1=["+sourcename1+" (red)] image2=["+targetname1+" (red)] image3=[-- None --]");
run("Concatenate...", "  title=green image1=["+sourcename1+" (green)] image2=["+targetname1+" (green)] image3=[-- None --]");
run("Concatenate...", "  title=blue image1=["+sourcename1+" (blue)] image2=["+targetname1+" (blue)] image3=[-- None --]");
selectWindow("red");
run("Bleach Correction", "correction=[Histogram Matching]");
selectWindow("green");
run("Bleach Correction", "correction=[Histogram Matching]");
selectWindow("blue");
run("Bleach Correction", "correction=[Histogram Matching]");
close("red");
close("green");
close("blue");
selectWindow("DUP_red");
run("Stack to Images");
selectWindow("DUP_green");
run("Stack to Images");
selectWindow("DUP_blue");
run("Stack to Images");
run("Concatenate...", "  title=newsource image1=DUP_red-0001 image2=DUP_green-0001 image3=DUP_blue-0001 image4=[-- None --]");
run("Concatenate...", "  title=newtarget image1=DUP_red-0002 image2=DUP_green-0002 image3=DUP_blue-0002 image4=[-- None --]");
selectWindow("newtarget");
run("Stack to RGB");
close("newtarget");
selectWindow("newsource");
run("Stack to RGB");
close("newsource");
selectWindow("newtarget (RGB)");
rename(targetname1);
saveAs(totype, outputtargetdir + targetname1);
close(targetname1+"."+totype);
selectWindow("newsource (RGB)");
rename(sourcename1);
saveAs(sotype, outputsourcedir + sourcename1);
close(sourcename1+"."+sotype);
}
}
print("\\Clear");
//run("Collect Garbage");
call("java.lang.System.gc");
}

setBatchMode(false);
close("*");
//run("Collect Garbage");
call("java.lang.System.gc");
beep();
waitForUser("The registration macro is finished.");

function pad(n) {
    str = toString(n);
    while (lengthOf(str)<6)
    str = "0" + str;
    return str;
}

Macro for Film Registration
Code:
Dialog.create("Register Film");
Dialog.addMessage("Register Source film to Target film")
Dialog.addChoice("Save Image Sequence As:", newArray("tif", "bmp", "png", "jpeg"));
Dialog.show()
type=Dialog.getChoice();
Targetpath = File.openDialog("Select Target File");
Sourcepath = File.openDialog("Select Source File (this file will be registered to the Target File)");
outputsourcedir = getDirectory("Choose output folder for SOURCE file:");
outputlandmarkdir = getDirectory("Choose output folder for Landmark files:");
run("Using FFmpeg...", "open=[" +Targetpath+ "]");
rename("target");
slices=nSlices();
run("Using FFmpeg...", "open=[" +Sourcepath+ "]");
rename("source");

//Search for first frame that contains enough detail for a good transform.
var done = false; // used to prematurely terminate loop
for (j=1; j<=slices && !done; j++) {
targetname="target-"+pad(j);
   sourcename="source-"+pad(j);
   selectWindow("target");
setSlice(j);
run("Make Substack...", "slices=" +j);
selectWindow("Substack ("+j+")");
   rename(targetname);
   selectWindow("source");
   setSlice(j);
   run("Make Substack...", "slices=" +j);
   selectWindow("Substack ("+j+")");
   rename(sourcename);
   run("Extract SIFT Correspondences", "source_image=["+sourcename+"] target_image=["+targetname+"] initial_gaussian_blur=1.60 steps_per_scale_octave=3 minimum_image_size=64 maximum_image_size=1024 feature_descriptor_size=4 feature_descriptor_orientation_bins=8 closest/next_closest_ratio=0.92 filter maximal_alignment_error=25 minimal_inlier_ratio=0.2 minimal_number_of_inliers=100 expected_transformation=Affine");
   selectWindow(sourcename);
stype0=selectionType();
selectWindow(targetname);
stype1=selectionType();
   if (stype0 & stype1 == 10) {
    done=true; //terminate the loop
   }
else {
   close(sourcename);
   close(targetname);
   }
}
//Save the initial transform.
selectWindow(sourcename);
saveAs("Selection", outputlandmarkdir + "source.roi");
//Roi.setName(source);
//roiManager("add"); //index 0
selectWindow(targetname);
saveAs("Selection", outputlandmarkdir + "target.roi");
//Roi.setName(target);
//roiManager("add"); //index 1
run("Landmark Correspondences", "source_image=["+sourcename+"] template_image=["+targetname+"] transformation_method=[Least Squares] alpha=1 mesh_resolution=32 transformation_class=Affine interpolate");
close(sourcename);
selectWindow("Transformed"+sourcename);
rename(sourcename);
run("Extract SIFT Correspondences", "source_image=["+sourcename+"] target_image=["+targetname+"] initial_gaussian_blur=1.60 steps_per_scale_octave=3 minimum_image_size=64 maximum_image_size=1024 feature_descriptor_size=4 feature_descriptor_orientation_bins=8 closest/next_closest_ratio=0.92 filter maximal_alignment_error=25 minimal_inlier_ratio=0.05 minimal_number_of_inliers=50 expected_transformation=Affine");
selectWindow(sourcename);
saveAs("Selection", outputlandmarkdir + "newsource.roi");
//Roi.setName(newsource);
//roiManager("add"); //index 2
selectWindow(targetname);
saveAs("Selection", outputlandmarkdir + "newtarget.roi");
//Roi.setName(newtarget);
//roiManager("add"); //index 3
run("bUnwarpJ", "source_image=["+sourcename+"] target_image=["+targetname+"] registration=Mono image_subsample_factor=0 initial_deformation=Coarse final_deformation=Fine divergence_weight=0 curl_weight=0 landmark_weight=1 image_weight=0 consistency_weight=0 stop_threshold=0.01");
selectWindow("target");
setSlice(1);
selectWindow("source");
setSlice(1);
close("Registered Source Image");
close(targetname);
close(sourcename);

//Start Registration from beginning of clip using initial transform found above as anchor if needed.
for (i=1; i<=slices; i++) {
showProgress(i,slices);
targetname1="target-"+pad(i);
sourcename1="source-"+pad(i);
selectWindow("target");
setSlice(i);
run("Make Substack...", "slices=" +i);
selectWindow("Substack ("+i+")");
rename(targetname1);
selectWindow("source");
setSlice(i);
run("Make Substack...", "slices=" +i);
selectWindow("Substack ("+i+")");
rename(sourcename1);
run("Extract SIFT Correspondences", "source_image=["+sourcename1+"] target_image=["+targetname1+"] initial_gaussian_blur=1.60 steps_per_scale_octave=3 minimum_image_size=64 maximum_image_size=1024 feature_descriptor_size=4 feature_descriptor_orientation_bins=8 closest/next_closest_ratio=0.92 filter maximal_alignment_error=25 minimal_inlier_ratio=0.05 minimal_number_of_inliers=50 expected_transformation=Affine");
selectWindow(sourcename1);
stype2=selectionType();
selectWindow(targetname1);
stype3=selectionType();
if (stype2 & stype3 == 10) {
selectWindow(sourcename1);
print("save source roi");
saveAs("Selection", outputlandmarkdir + "source.roi");
selectWindow(targetname1);
print("save target roi");
saveAs("Selection", outputlandmarkdir + "target.roi");
    run("Landmark Correspondences", "source_image=["+sourcename1+"] template_image=["+targetname1+"] transformation_method=[Least Squares] alpha=1 mesh_resolution=32 transformation_class=Affine interpolate");
close(sourcename1);
selectWindow("Transformed"+sourcename1);
rename(sourcename1);
run("Extract SIFT Correspondences", "source_image=["+sourcename1+"] target_image=["+targetname1+"] initial_gaussian_blur=1.60 steps_per_scale_octave=3 minimum_image_size=64 maximum_image_size=1024 feature_descriptor_size=4 feature_descriptor_orientation_bins=8 closest/next_closest_ratio=0.92 filter maximal_alignment_error=25 minimal_inlier_ratio=0.05 minimal_number_of_inliers=10 expected_transformation=Affine");
selectWindow(sourcename1);
print("save newsource roi");
saveAs("Selection", outputlandmarkdir + "newsource.roi");
selectWindow(targetname1);
print("save newtarget roi");
saveAs("Selection", outputlandmarkdir + "newtarget.roi");
run("bUnwarpJ", "source_image=["+sourcename1+"] target_image=["+targetname1+"] registration=Mono image_subsample_factor=0 initial_deformation=Coarse final_deformation=Fine divergence_weight=0 curl_weight=0 landmark_weight=1 image_weight=0 consistency_weight=0 stop_threshold=0.01");
selectWindow("Registered Source Image");
run("Stack to Images");
close("Warped Source Mask");
close("Target Image");
close(sourcename1);
selectWindow("Registered Source Image");
saveAs(type, outputsourcedir + sourcename1);
close();
close(targetname1);
}
else {
roiManager("Open", outputlandmarkdir + "source.roi");
roiManager("Open", outputlandmarkdir + "target.roi");
selectWindow(sourcename1);
roiManager("select",0);
selectWindow(targetname1);
roiManager("select",1);
run("Landmark Correspondences", "source_image=["+sourcename1+"] template_image=["+targetname1+"] transformation_method=[Least Squares] alpha=1 mesh_resolution=32 transformation_class=Affine interpolate");
close(sourcename1);
selectWindow("Transformed"+sourcename1);
rename(sourcename1);
//run("Extract SIFT Correspondences", "source_image=["+sourcename1+"] target_image=["+targetname1+"] initial_gaussian_blur=0.60 steps_per_scale_octave=3 minimum_image_size=64 maximum_image_size=1024 feature_descriptor_size=4 feature_descriptor_orientation_bins=8 closest/next_closest_ratio=0.92 filter maximal_alignment_error=25 minimal_inlier_ratio=0.05 minimal_number_of_inliers=7 expected_transformation=Affine");
roiManager("reset");
roiManager("Open", outputlandmarkdir + "newsource.roi");
roiManager("Open", outputlandmarkdir + "newtarget.roi");
selectWindow(sourcename1);
roiManager("select",0);
selectWindow(targetname1);
roiManager("select",1);
run("bUnwarpJ", "source_image=["+sourcename1+"] target_image=["+targetname1+"] registration=Mono image_subsample_factor=0 initial_deformation=Coarse final_deformation=Fine divergence_weight=0 curl_weight=0 landmark_weight=1 image_weight=0 consistency_weight=0 stop_threshold=0.01");
selectWindow("Registered Source Image");
run("Stack to Images");
close("Warped Source Mask");
close("Target Image");
close(sourcename1);
selectWindow("Registered Source Image");
saveAs(type, outputsourcedir + sourcename1);
close();
close(targetname1);
close("ROI Manager");
}
print("\\Clear");
//run("Collect Garbage");
call("java.lang.System.gc");
}

//setBatchMode(false);
close("Roi Manager");
close("*");
//run("Collect Garbage");
call("java.lang.System.gc");
beep();
waitForUser("The registration macro is finished.");

function pad(n) {
    str = toString(n);
    while (lengthOf(str)<6)
    str = "0" + str;
    return str;
}

I've packaged all of this into a custom imagej zip. It relies on an existing java installation and if it can't find javaw, it will ask you where it is located. You can't download vanilla imagej packages and then use these macros as there are some custom plugins I've drawn from the interwebs that aren't a part of a normal installation.

Extract the ImageJ folder to the root of your C drive and run the executable to get it up and running.

Plugin tutorial link
I have changed the names of the plugins and such but you should get the idea.
The numbered plugins are the macros I've made. The rest are the plugins that the macros require to run.

Custom Imagej zip

I will keep this first post up to date with changes.
Reply
Thanks given by: PDB , williarob , TomArrow
#2
I'm probably making some really dumb mistake but here's what I get when I try to run Image Registration on two PNG files that sit in the same folder (they have random names from screenshotting):

Quote:ImageJ 1.52a; Java 1.8.0_202 [64-bit]; Windows 7 6.1; 40MB of 6067MB (<1%)

java.lang.IllegalArgumentException: First frame is out of range 0:-1
at ffmpeg_video_import.FFmpeg_FrameReader.makeStack(FFmpeg_FrameReader.java:221)
at ffmpeg_video_import.FFmpeg_FrameReader.run(FFmpeg_FrameReader.java:83)
at ij.IJ.runUserPlugIn(IJ.java:221)
at ij.IJ.runPlugIn(IJ.java:185)
at ij.Executer.runCommand(Executer.java:137)
at ij.Executer.run(Executer.java:66)
at ij.IJ.run(IJ.java:301)
at ij.macro.Functions.doRun(Functions.java:613)
at ij.macro.Functions.doFunction(Functions.java:96)
at ij.macro.Interpreter.doStatement(Interpreter.java:249)
at ij.macro.Interpreter.doStatements(Interpreter.java:235)
at ij.macro.Interpreter.run(Interpreter.java:118)
at ij.macro.Interpreter.run(Interpreter.java:89)
at ij.macro.Interpreter.run(Interpreter.java:100)
at ij.plugin.Macro_Runner.runMacro(Macro_Runner.java:161)
at ij.plugin.Macro_Runner.runMacroFile(Macro_Runner.java:145)
at ij.plugin.Macro_Runner.run(Macro_Runner.java:60)
at ij.IJ.runPlugIn(IJ.java:191)
at ij.Executer.runCommand(Executer.java:137)
at ij.Executer.run(Executer.java:66)
at java.lang.Thread.run(Unknown Source)

Edit: I was using the 02 Registration Macro
Reply
Thanks given by:
#3
The macro requires the images to be in separate folders as it's meant to be importing image sequences. If you are simply trying to register 2 images the macro is not needed at all.

You would simply open the two images in imagej, then go to Plugins->Feature Extraction and run "extract sift correspondences". When the settings window pops up, change the expected transformation to affine and hit ok.

After the correspondences are found don't click on the images or you might lose them. Now, go to Plugins->Transform and click on Landmark correspondences. Make sure you have the source image and template image in the correct place, change the transformation class to affine and hit ok.

That's it. If you need something more robust or non-rigid you can use bunwarpj but this method gets it right most of the time and the bunwarpj method would require a lot more typing.
Reply
Thanks given by: TomArrow
#4
Awesome, thank you. That worked.

Now, I noticed that the image I chose to transform was resized down to the resolution of the template. Is there a way to keep the original resolution or will I have to upscale the other (DVD) source? Will your macro accept an .avs input file? And will your macro just apply the same transformation on every single frame or will it adapt frame-by-frame?

I also noticed that the resulting frames weren't perfectly aligned out of the box and I had to run a second-pass alignment in Photoshop to get them to match up perfectly. I don't think it's a big deal, but is there anything I can do to make them match even better out of the box?
Reply
Thanks given by:
#5
Great!

I will try to answer your questions in order here:

1) Is there a way to keep the original resolution or will I have to upscale the other (DVD) source?

A: It's probably better to upscale the other source or switch which source you are using as a template.

2) Will your macro accept an .avs input file?

A: No. I have not found a way to connect avisynth and imagej this way. Hopefully somebody will.
Currently you have to import with ffmpeg, an image sequence, or a raw avi that works with imagej.

3) Will your macro just apply the same transformation on every single frame or will it adapt frame-by-frame?

A: It will adapt frame-by-frame where it can. Currently, if there are none or not enough correspondences between the 2 images it will call upon the last known good set of correspondences to perform registration.
Williarob has some ideas that I'd like to implement that will account for mismatched frames but I've yet to implement those in a way that would be helpful so I haven't updated the macro with it.

4) Is there anything I can do to make registration match even better out of the box?

A: The macro goes through a more extensive registration process and will likely give better results than just doing an affine transformation on the landmark correspondences.

If I remember right, the macro performs:

1) The steps I told you about in the previous post.
2) Then it goes on to do it again once they are matched in resolution which give many more correspondences usually.
3) It then does a bunwarpj step with the correspondences from step 2 which is the first non-rigid step in the process that allows(hopefully) for it to wriggle everything into it's proper place.

The color matching macro only performs the first 2 steps as this is close enough for color matching and saves a bit of time.
Reply
Thanks given by: TomArrow
#6
Thanks for writing all that down. I'll try these tips out when I can.
Reply
Thanks given by: althor1138


Forum Jump:


Users browsing this thread: 1 Guest(s)