// //---------------------------- AMCap ImageJ Capture and Stitch Tool ------------------------------- var AMCapV=101021; // Please use the latest version on http://neutronoptics.com/AMCap.txt email:alan.hewat@neutronoptics.com // ImageJ Macro for capturing video camera snapshots or integrated video clips on Windows computers. // Up to two different cameras can be captured and their images stitched to form a corrected mosaic // This macro was developed from http://rsb.info.nih.gov/ij/macros/tools/VideoCaptureTool.txt // // (1) Download AMCap from http://noeld.com/programs.asp?cat=video#AMCap and pay $29 to register it // (2) Install AMCap with StillCap in the parent directory of ImageJ (normally "C:\Program Files" ) // (3) Download http://neutronoptics.com/AMCap.txt and copy it to the \ImageJ\macros\toolsets // Click the >> icon in the ImageJ toolbar and select the AMCap tool // (4) Right-click the NeutronOptics Camera Capture tool icon that appears and set the capture options. // For NeutronOptics cameras, choose the listed "USB 2861 Device" with PAL resolution (720x576) // You must specify a directory to store captured images, eg "C:\temp\" and the file format eg "tif" // For a double-CCD camera, specify the relative offsets & scales of the second camera wrt the first // (5) Now everything is ready for image capture with this macro: Left-click the camera icon to start capturing // Left-click the capture icon. This calls StillCap to capture a snapshot from each chosen camera // With two cameras, the snapshots will be automatically stitched together and the resulting mosaic displayed // Note that both cameras can have the same name with StillCap, since they are referenced by device number var stillCap=""; var capturedNumber = 0; //Number of Images var capturedVirtualStack = 0; var nDevices = call("ij.Prefs.get", "captureTool.nDevices","1"); //Number of Devices var nCapture = call("ij.Prefs.get", "captureTool.nCapture","1"); //Number of Devices captured var captureGray = parseInt(call("ij.Prefs.get","captureTool.toGrayScale","0")); //Convert to 32-bit greyScale var captureFlip = parseInt(call("ij.Prefs.get","captureTool.flipVertical","0")); //Flip vertical var horizonFlip = parseInt(call("ij.Prefs.get","captureTool.flipHorizontal","0"));//Flip horizontal var captureTime = call("ij.Prefs.get", "captureTool.captureTime","0"); //Eventual capture integration var setResoln = call("ij.Prefs.get", "captureTool.setResoln","720x576"); //Set Resolution var captureDir = call("ij.Prefs.get", "captureTool.captureDir","C:\\temp\\"); //Working Directory var fileN = call("ij.Prefs.get", "captureTool.fileN","snap"); //File name var fileB = call("ij.Prefs.get", "captureTool.fileB",""); //Background file name var imageType = call("ij.Prefs.get", "captureTool.imageType","tif"); //Image type //var captureType = call("ij.Prefs.get", "captureTool.captureType","Sum Slices"); //Mosaic addition var K1 = call("ij.Prefs.get", "captureTool.K1s","0.0"); //K1 for lens correction var K2 = call("ij.Prefs.get", "captureTool.K2s","0.0"); //K2 for lens correction var aRotate = call("ij.Prefs.get", "captureTool.aRotate","0.0"); //Rotation angle camera#1 var bRotate = call("ij.Prefs.get", "captureTool.bRotate","0.0"); //Rotation angle camera#2 var xOff = call("ij.Prefs.get", "captureTool.xO1","0"); //Relative x-offset camera#2 var yOff = call("ij.Prefs.get", "captureTool.yO1","0"); //Relative y-offset camera#2 var ifBack = call("ij.Prefs.get", "captureTool.ifBack",false); //If ImageJ autocorrect B/G var ifDespec= call("ij.Prefs.get", "captureTool.ifDespec",true); //If ImageJ despeckle // var setSaturate = call("ij.Prefs.get", "captureTool.setSaturate","0.0"); //Set percent of saturated pixels var xS=newArray(2); var yS=newArray(2); var device= newArray(4); //Names of devices var devResoln= newArray(12); //Resolution table // var Saturate= newArray(4); //Percent of saturated pixels var ifCapture = newArray(4); //If device i to be captured macro 'NeutronOptics Camera Capture (right click to set options, left click to capture) Action Tool - C000F14faF24faP4461b1d40Cfffo5577' { requires("1.41d"); setBatchMode(true); showProgress(0,nDevices+6); showStatus("Capture in progress... Please Wait !"); ifOK=0; ifFail = "No devices selected for capture !!\nRight-click camera icon & select devices"; File.makeDirectory(captureDir); if (!File.exists(captureDir)) exit("Unable to create directory "+captureDir+"\nRight-click camera icon & check your options"); list = getFileList(captureDir); //Delete files to be overwritten for (i=0; i=0) { // showMessageWithCancel("Delete existing file "+captureDir+list[i]+" ?"); ifOK2 = File.delete(captureDir+list[i]); } status=exec("taskkill /FI \"WINDOWTITLE eq AMCap\""); //Close any active AMCap apps status=exec("taskkill /FI \"WINDOWTITLE eq stillCap\""); wait(100); //Close any active stillCap apps if(captureTime<=0) { //Run stillCap for each capture for (i=1; i0) exit("Error launching stillCap.\nUse AMCap to configure each USB device.\nUnplug then replug any bad USB device"); if(indexOf(ifFail,"Usage")>0) exit("Error launching stillCap.\nRight-click camera icon & check parameters"); open(captureDir+fileN+i+"."+imageType); wait(100); if(captureGray) run("32-bit"); if(i == 1)if(aRotate != 0) run("Arbitrarily...", "angle="+aRotate+" grid=1 interpolation=Bilinear"); if(i > 1) if(bRotate != 0) run("Arbitrarily...", "angle="+bRotate+" grid=1 interpolation=Bilinear"); if(xS[i-1]!=1.0 || yS[i-1]!=1.0) run("Scale...", "x="+xS[i-1]+" y="+yS[i-1]+" width="+getWidth+" height="+getHeight+" interpolation=Bilinear"); if(K1>0) { save(captureDir+fileN+i+"."+imageType); close(); wait(100); run("SplineDeformationGenerator ","-barrel "+captureDir+fileN+i+"."+imageType+" "+K1+" "+K2+" "+captureDir+fileN+i+"."+imageType); wait(100); open(captureDir+fileN+i+"."+imageType); wait(100); } if(ifBack) run("Subtract Background...", "rolling=50"); wait(200); if(nCapture==1) if(fileB!="") if (!File.exists(captureDir+fileB+"."+imageType)) { showMessageWithCancel(captureDir+fileB+"."+imageType+" background file was not found!"); exit;} else { setBatchMode(false); showMessageWithCancel("Subtract background image "+captureDir+fileB+"."+imageType+" ?"); open(captureDir+fileB+"."+imageType); wait(100); run("Select All"); run("Copy"); close(); if (isOpen(fileN+i+"."+imageType)) selectWindow(fileN+i+"."+imageType); setPasteMode("Subtract"); run("Paste"); } } if(ifOK == 0) exit(ifFail); } if (nCapture>=2) makeMontage(); else { wait(100); setBatchMode(false); status=exec("taskkill /FI \"WINDOWTITLE eq stillCap\""); //Close any active stillCap apps status=exec("taskkill /FI \"WINDOWTITLE eq AMCap\""); wait(100); //Close any active AMCap apps // status=exec(getDirectory("startup")+"..\\AMCap\\AMCap.exe"); } if(ifDespec) run("Despeckle"); wait(100); if(ifDespec) run("Despeckle"); // if(ifDespec) run("Remove Outliers...", "radius=2 threshold=50 which=Bright"); // if(setSaturate != "0.0") run("Enhance Contrast", "saturated="+setSaturate); // Adjust window level // run("Brightness/Contrast..."); showMessage(" OK ?\nIf not, left-click camera icon to re-capture current exposure.\nAre you sure that the video cables have not been inverted?\n \nTry adjusting contrast and levels to search for weak peaks."); exit(); } -----------------------------------makeMontage--------------------------------------------- // This macro creates a 2D montage of 2 captured images function makeMontage() { x=newArray(2); y=newArray(2); // offsets for each image x[i],y[i] xfac=newArray(2); yfac=newArray(2); // scale factors for each image xfac[i],yfac[i] iw=newArray(2); ih=newArray(2); // width, height for each image iw[i],ih[i] x[0]=0.0; x[1]=xOff; y[0]=0.0; y[1]=yOff; xfac[0]=xS[0]; xfac[1]=xS[1]; yfac[0]=yS[0]; yfac[1]=yS[1]; setPasteMode("Max"); if (isOpen(fileN+"Mosaic."+imageType)) {selectWindow(fileN+"Mosaic."+imageType); close();} if (isOpen(fileN+"1."+imageType)) selectWindow(fileN+"1."+imageType); iw[0]=getWidth; ih[0]=getHeight; run("Select All"); run("Copy"); close(); newImage(fileN+"Mosaic."+imageType,"8-bit Black", 1*iw[0]+x[0]+x[1], 2*ih[0]+y[0]+y[1], 1); if(captureGray) run("32-bit"); makeRectangle(x[0],y[0],iw[0],ih[0]); // offsets x[i],y[i] rectangle iw[i],ih[i] run("Paste"); wait(100); if (isOpen(fileN+"2."+imageType)) selectWindow(fileN+"2."+imageType); iw[1]=getWidth; ih[1]=getHeight; run("Select All"); run("Copy"); close(); if (isOpen(fileN+"Mosaic."+imageType)) selectWindow(fileN+"Mosaic."+imageType); makeRectangle(x[1],y[1]+ih[0],iw[1],ih[1]); // offsets x[i],y[i] rectangle iw[i],ih[i] run("Paste"); wait(100); run("Rotate 90 Degrees Left"); //setAutoThreshold(); //run("NaN Background"); //run("Invert"); if(fileB!="") if (!File.exists(captureDir+fileB+"."+imageType)) { showMessageWithCancel(captureDir+fileB+"."+imageType+" background file was not found!"); exit;} else { setBatchMode(false); showMessageWithCancel("Subtract background image "+captureDir+fileB+"."+imageType+" ?"); open(captureDir+fileB+"."+imageType); wait(100); run("Select All"); run("Copy"); close(); if (isOpen(fileN+"Mosaic."+imageType)) selectWindow(fileN+"Mosaic."+imageType); setPasteMode("Subtract"); run("Paste"); } saveAs(imageType, captureDir+fileN+"Mosaic."+imageType); resetMinAndMax(); setBatchMode(false); // display the montage status=exec("taskkill /FI \"WINDOWTITLE eq stillCap\""); //Close any active stillCap apps status=exec("taskkill /FI \"WINDOWTITLE eq AMCap\""); wait(100); //Close any active AMCap apps // status=exec(getDirectory("startup")+"..\\AMCap\\AMCap.exe"); if (isOpen(fileN+"Mosaic."+imageType)) selectWindow(fileN+"Mosaic."+imageType); } //-------------------- C a p t u r e T o o l O p t i o n s --------------------- macro 'NeutronOptics Camera Capture (right click to set options, left click to capture) Action Tool Options' { xS[0] = call("ij.Prefs.get", "captureTool.xS1","1.0"); //X scale factor camera#1 yS[0] = call("ij.Prefs.get", "captureTool.yS1","1.0"); //Y scale factor camera#1 xS[1] = call("ij.Prefs.get", "captureTool.xS2","1.0"); //X scale factor camera#2 yS[1] = call("ij.Prefs.get", "captureTool.yS2","1.0"); //Y scale factor camera#2 // Saturate[0]=0.0;Saturate[1]=0.0; // for(i=2; i0) exit(status); dtype = split(status,"|"); nDevices=0; nd=1; for (i=2; i= 0) {nd=nDevices;} //Use resolutions of USB 2861 Device if available ifCapture[i-2] = call("ij.Prefs.get", "captureTool.ifCapture"+i-2,ifCapture[i-2]); Dialog.addCheckbox(device[i-2], ifCapture[i-2]); } } status=exec(stillCap+" /device:"+nd+" /listresolutions"); //Use resolutions of USB 2861 Device if available if(indexOf(status,"ERROR")>0) exit(status); lines = split(status,"\n"); for (i=8; i=0) { lines[i]=replace(lines[i],"*","x");lines[i]=replace(lines[i]," ",""); devResoln[i-8]=lines[i]; if(indexOf(lines[i],"to")>=0) devResoln[i-8]=substring(lines[i],0,indexOf(lines[i],"to")); } } devResoln[7]="640x480"; if(indexOf(status,"576")>0) {devResoln[0]="720x576";} Dialog.addChoice("Resolution", devResoln,setResoln); Dialog.addString("Directory", captureDir); Dialog.addString("File name", fileN); Dialog.addChoice("Format", newArray("tif", "jpg", "png","bmp"), imageType); Dialog.addCheckbox("Despeckle to remove isolated white pixels", ifDespec); Dialog.addCheckbox("Convert to 32-bit GrayScale", captureGray); // Dialog.addCheckbox("Flip Vertical", captureFlip); // Dialog.addCheckbox("Flip Horizontal", horizonFlip); Dialog.addCheckbox("Calculate Background else input File name", ifBack); Dialog.addString("Background File name", fileB); // Dialog.addChoice("Fraction of pixels saturated", Saturate,setSaturate); // Dialog.addChoice("For several cameras", newArray("Sum Cameras", "Average Intensity", "Median", "Stack", "Virtual Stack"), captureType); // if(ifSpline>0) { Dialog.addMessage("Set K1=0 to skip GrayScale Lens Corrections"); Dialog.addNumber("Barrel / Pincushion Corr K1", K1,3,6,"(0.13)"); Dialog.addNumber("Barrel / Pincushion Corr K2", K2,3,6,"(0.00)"); // } Dialog.addMessage(""); Dialog.addNumber("Camera #1 relative rotation", aRotate,3,6,"degrees"); Dialog.addNumber("Camera #1 X Scale Factor", xS[0],3,6,"factor"); Dialog.addNumber("Camera #1 Y Scale Factor", yS[0],3,6,"factor"); Dialog.addMessage(""); if(nDevices>1) { Dialog.addNumber("Camera #2 relative rotation", bRotate,3,6,"degrees"); Dialog.addNumber("Camera #2 relative X offset", xOff,0,6,"pixels"); Dialog.addNumber("Camera #2 relative Y offset", yOff,0,6,"pixels"); Dialog.addNumber("Camera #2 X Scale Factor", xS[1],3,6,"factor"); Dialog.addNumber("Camera #2 Y Scale Factor", yS[1],3,6,"factor"); } Dialog.addMessage("* Check AMCap parameters for all cameras *"); Dialog.addHelp("http://www.neutronoptics.com/ijinstall.html"); Dialog.show(); if (List.get("SplineDeformationGenerator ")=="") { if(K1>0 || K2>0) { showMessage("Install *SplineDeformationGenerator * Plugin to enable Barrel/Pincushion corrections"); K1=0; K2=0; //ifSpline=0; } } nCapture=0; for (i=0; i0) { K1= Dialog.getNumber(); K2= Dialog.getNumber(); // } // else K1=0; if(K1>0) captureGray=1; // if(setSaturate!="0.0") captureGray=1; aRotate= Dialog.getNumber(); xS[0]= Dialog.getNumber(); yS[0]= Dialog.getNumber(); for (i=0; i1) { bRotate= Dialog.getNumber(); xOff= Dialog.getNumber(); yOff= Dialog.getNumber(); xS[1]= Dialog.getNumber(); yS[1]= Dialog.getNumber(); call("ij.Prefs.set", "captureTool.bRotate",bRotate); call("ij.Prefs.set", "captureTool.xO1",xOff); call("ij.Prefs.set", "captureTool.yO1",yOff); call("ij.Prefs.set", "captureTool.xS2",xS[1]); call("ij.Prefs.set", "captureTool.yS2",yS[1]); } // if(nCapture==1) { status=exec("taskkill /FI \"WINDOWTITLE eq stillCap\""); //Close any active stillCap apps status=exec("taskkill /FI \"WINDOWTITLE eq AMCap\""); wait(100); // status=exec(getDirectory("startup")+"..\\AMCap\\AMCap.exe"); // } }