Copy link to clipboard
Copied
I have shots comprised of jpg image sequences. I'm processing the shots. When I process them, position and scale for a portion of the image is offset. I'm trying to use a script to perspective auto align the processed image to match the original image.
So I believe I need a script to:
1. Load original image into layer 1.
2. Load processed image into layer 2.
3. Designate the original image on layer 1 as the reference, so that the processed image on layer 2 is perpective transformed to match the original image on layer 1.
4. Auto-align layer 2 to layer 1.
5. Export the aligned layers, with layer 2 on top, to an uncompressed file (not .psd).
6. Repeat script on each matched pair until all pairs in the folders are procesed.
I assume the folder structures should be:
"Folder 1" = original files (contains the first set of matched pairs identically named as their match in folder 2).
"Folder 2" = processed files (contains the other set of matched pairs identically named as their match in folder 1).
"Output Folder" = photoshop aligned exported file.
FYI - The processed image is only the portion of the frame that has been position and scale offset by the processing. So the result I'm looking for is exactly what photoshop does when you manually auto-align the two uploaded images. I don't want the processed image to be auto-aligned to full frame, just aligned against the portion of the original image that came from.
I have found a plugin called Image Processor Pro, that will auto process every image in a folder. I've also found a script that I think will stack images in adobe bridge, but it's 10 years old, for Windows 7.
I just can't think of the right combination of search terms for google. This has to be out there somwhere.
Totally willing to pay for your time for a solution. We can DM or Discord, or something.
Thanks!
Copy link to clipboard
Copied
It would be very helpful if you could upload sample images to the forum, your CC share, Dropbox etc.
Sample filenames showing how each pair or sequence of images can be automatically determined.
Additionally if you can post cropped screenshots of the settings that you are happy with when doing this manually.
Copy link to clipboard
Copied
You would need he explain what your step 3 is in great detail.
"3. Designate the original image on layer 1 as the reference, so that the processed image on layer 2 is perpective transformed to match the original image on layer 1."
How do you want to distort image 2 to match some projective that image 1 has to be able to align something. Are you trying to stitch images or do some kind of stack mode blending?
Have you tried any of Photoshop features like Photomerge and stack mode blending?
Copy link to clipboard
Copied
Hello @JJMack and @Stephen_A_Marsh ,
Thank you for asking for clarification. Here is what I would like a script to do:
Step 1: Open Photoshop.
Copy link to clipboard
Copied
Copy link to clipboard
Copied
You you should be able to stack two images using photoshop scripting with the small smaller image on top. Target both layers , use Photoshop menu Edit>Auto Align Layers to do your alignment, save a jpeg composite and close the document. Repete for the next two images.
Auto Align Layers worked with you sample image when I did the steps Manually. Though Edit>Auto Align Layers opened a dialog window that I had to click on its OK button. When I recorder that step in an Action the layers just aligned there was no dialog that opened it would work in a script without showing a dialog.
Copy link to clipboard
Copied
Try this modification to the script that I pointed to earlier in the thread:
/*
Photoshop script to auto stack pair of images, then auto-align, and export.
https://community.adobe.com/t5/photoshop/photoshop-script-to-auto-stack-pair-of-images-then-auto-align-and-export/td-p/11989171
Auto Align Files from 2 Folders to TIFF.jsx
Stephen Marsh
Version 1.3 - 26th April 2021
*/
#target photoshop
(function () {
if (app.documents.length === 0) {
// Save the current dialog display settings
var savedDisplayDialogs = app.displayDialogs;
app.displayDialogs = DialogModes.NO;
// Input folder 1
var folder1 = Folder.selectDialog("Please select the originals folder");
if (folder1 === null) return;
// Input folder 2
var folder2 = Folder.selectDialog("Please select the processed files folder");
if (folder2 === null) return;
// Validate input folder selection
var validateInputDir = (folder1.fsName === folder2.fsName);
if (validateInputDir === true) {
alert("Script cancelled as both the input folders are the same");
return;
}
var searchMask = '*.???';
var list1 = folder1.getFiles(searchMask);
var list2 = folder2.getFiles(searchMask);
// Alpha-numeric sort
list1.sort();
list2.sort();
// Validate that folder 1 & 2 lists are not empty
var validateEmptyList = (list1.length > 0 && list2.length > 0);
if (validateEmptyList === false) {
alert("Script cancelled as one of the input folders is empty");
return;
}
// Validate that the item count in folder 1 & 2 matches
var validateListLength = (list1.length === list2.length);
if (validateListLength === false) {
alert("Script cancelled as the input folders don't have equal quantities of images");
return;
}
// Output folder
var saveFolder = Folder.selectDialog("Please select the folder to save to");
if (saveFolder === null) return;
for (var i = 0; i < list1.length; i++) {
var doc = open(list1[i]);
var docName = doc.name.replace(/\.[^\.]+$/, '');
backgroundLayerNameToVariableName(docName, 100, 2);
app.activeDocument.activeLayer.allLocked = true;
placeFile(list2[i], 100);
app.runMenuItem(stringIDToTypeID('rasterizePlaced'));
app.runMenuItem(stringIDToTypeID("selectAllLayers"));
// Auto = "auto", Reposition = "translation"
autoAlignLayers(false, "auto", false, false);
tiffSaveOptions = new TiffSaveOptions();
tiffSaveOptions.embedColorProfile = true;
tiffSaveOptions.byteOrder = ByteOrder.IBM;
tiffSaveOptions.transparency = true;
tiffSaveOptions.layers = false;
tiffSaveOptions.layerCompression = LayerCompression.ZIP;
tiffSaveOptions.interleaveChannels = true;
tiffSaveOptions.alphaChannels = true;
tiffSaveOptions.annotations = true;
tiffSaveOptions.spotColors = true;
tiffSaveOptions.saveImagePyramid = false;
tiffSaveOptions.imageCompression = TIFFEncoding.NONE;
doc.saveAs(new File(saveFolder + '/' + docName + '.tif'), tiffSaveOptions);
doc.close(SaveOptions.DONOTSAVECHANGES);
}
alert('Script completed!' + '\n' + 'Files saved to:' + '\r' + saveFolder.fsName);
// Restore the dialogs
app.displayDialogs = savedDisplayDialogs;
// Here be functions
function placeFile(file, scale) {
var idPlc = charIDToTypeID("Plc ");
var desc2 = new ActionDescriptor();
var idnull = charIDToTypeID("null");
desc2.putPath(idnull, new File(file));
var idFTcs = charIDToTypeID("FTcs");
var idQCSt = charIDToTypeID("QCSt");
var idQcsa = charIDToTypeID("Qcsa");
desc2.putEnumerated(idFTcs, idQCSt, idQcsa);
var idOfst = charIDToTypeID("Ofst");
var desc3 = new ActionDescriptor();
var idHrzn = charIDToTypeID("Hrzn");
var idPxl = charIDToTypeID("#Pxl");
desc3.putUnitDouble(idHrzn, idPxl, 0.000000);
var idVrtc = charIDToTypeID("Vrtc");
var idPxl = charIDToTypeID("#Pxl");
desc3.putUnitDouble(idVrtc, idPxl, 0.000000);
var idOfst = charIDToTypeID("Ofst");
desc2.putObject(idOfst, idOfst, desc3);
var idWdth = charIDToTypeID("Wdth");
var idPrc = charIDToTypeID("#Prc");
desc2.putUnitDouble(idWdth, idPrc, scale);
var idHght = charIDToTypeID("Hght");
var idPrc = charIDToTypeID("#Prc");
desc2.putUnitDouble(idHght, idPrc, scale);
var idAntA = charIDToTypeID("AntA");
desc2.putBoolean(idAntA, true);
executeAction(idPlc, desc2, DialogModes.NO);
}
function autoAlignLayers(alignToCanvas, projValue, vignette, radialDistort) {
var c2t = function (s) {
return app.charIDToTypeID(s);
}
var s2t = function (s) {
return app.stringIDToTypeID(s);
}
var descriptor = new ActionDescriptor();
var reference = new ActionReference();
reference.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("targetEnum"));
descriptor.putReference(c2t("null"), reference);
descriptor.putEnumerated(s2t("using"), s2t("alignDistributeSelector"), s2t("ADSContent"));
descriptor.putBoolean(s2t("alignToCanvas"), alignToCanvas);
// projValue - Auto = "auto", Reposition = "translation"
descriptor.putEnumerated(s2t("apply"), s2t("projection"), s2t(projValue));
descriptor.putBoolean(s2t("vignette"), vignette);
descriptor.putBoolean(s2t("radialDistort"), radialDistort);
executeAction(c2t("Algn"), descriptor, DialogModes.NO);
}
function backgroundLayerNameToVariableName(layerName, opacity, layerID) {
var c2t = function (s) {
return app.charIDToTypeID(s);
};
var s2t = function (s) {
return app.stringIDToTypeID(s);
};
var descriptor = new ActionDescriptor();
var descriptor2 = new ActionDescriptor();
var reference = new ActionReference();
reference.putProperty(s2t("layer"), s2t("background"));
descriptor.putReference(c2t("null"), reference);
descriptor2.putString(s2t("name"), layerName);
descriptor2.putUnitDouble(s2t("opacity"), s2t("percentUnit"), opacity);
descriptor2.putEnumerated(s2t("mode"), s2t("blendMode"), s2t("normal"));
descriptor.putObject(s2t("to"), s2t("layer"), descriptor2);
descriptor.putInteger(s2t("layerID"), layerID);
executeAction(s2t("set"), descriptor, DialogModes.NO);
}
}
else {
alert('Please close all open documents before running this script!');
}
}());
Instructions for saving/running scripts here:
https://prepression.blogspot.com/2017/11/downloading-and-installing-adobe-scripts.html
Copy link to clipboard
Copied
Hello @Stephen_A_Marsh
Wow!!!! That was a fast response! Thank you! The script is almost perfect!
When I run my image sequence through the script, photoshop is changing the scale and position of both the original and the processed files so they align. Sometimes shrinking the original and blowing up the processed file, morhping them both to meet in the middle so they align.
The perspective shift is happening (instead of just a position shift) because my processed files are actually slightly different in shape and size then the originals. So "auto" mode adds the perspective morph.
Is there anyway to lock the original's layer so that it does not change, and only the processed layer is morphed to align?
Again thanks so much!
Copy link to clipboard
Copied
Hi @Stephen_A_Marsh ,
Could I lock the layer the original is on, somewhere in here, before autoAlign-Auto:
app.runMenuItem(stringIDToTypeID('rasterizePlaced'));
app.runMenuItem(stringIDToTypeID("selectAllLayers"));
autoAlign_Auto();
My googling skills must be limited. I just tried "photoshop" + "lock" + "layer" + "javascript". Why wouldn't that pull something up?
What is this section of the script doing?:
function placeFile(file, scale) {
var idPlc = charIDToTypeID("Plc ");
var desc2 = new ActionDescriptor();
var idnull = charIDToTypeID("null");
desc2.putPath(idnull, new File(file));
var idFTcs = charIDToTypeID("FTcs");
var idQCSt = charIDToTypeID("QCSt");
var idQcsa = charIDToTypeID("Qcsa");
desc2.putEnumerated(idFTcs, idQCSt, idQcsa);
var idOfst = charIDToTypeID("Ofst");
var desc3 = new ActionDescriptor();
var idHrzn = charIDToTypeID("Hrzn");
var idPxl = charIDToTypeID("#Pxl");
desc3.putUnitDouble(idHrzn, idPxl, 0.000000);
var idVrtc = charIDToTypeID("Vrtc");
var idPxl = charIDToTypeID("#Pxl");
desc3.putUnitDouble(idVrtc, idPxl, 0.000000);
var idOfst = charIDToTypeID("Ofst");
desc2.putObject(idOfst, idOfst, desc3);
var idWdth = charIDToTypeID("Wdth");
var idPrc = charIDToTypeID("#Prc");
desc2.putUnitDouble(idWdth, idPrc, scale);
var idHght = charIDToTypeID("Hght");
var idPrc = charIDToTypeID("#Prc");
desc2.putUnitDouble(idHght, idPrc, scale);
var idAntA = charIDToTypeID("AntA");
desc2.putBoolean(idAntA, true);
executeAction(idPlc, desc2, DialogModes.NO);
Thank you!
Copy link to clipboard
Copied
Thanks, it was just a case of modifying an existing script that was close to what you wanted.
I have since updated the original code into a 1.1 version, introducing a lock all step to the original layer.
app.activeDocument.activeLayer.allLocked = true;
Let me know how this goes in resolving the issue.
EDIT: The other section of the script that you asked about is a function using the place embedded method to place each file in the processed folder onto the original file at 100% scale.
Copy link to clipboard
Copied
Thanks @Stephen_A_Marsh ,
The script moves so fast on my system, I can't tell if when it's locking the background layer. It looked like to processed the files exactly the same. I know locking the layer sets it as a reference, but maybe we need to only select the top layer to auto-align.
https://www.dummies.com/software/adobe/photoshop/how-to-auto-align-layers-in-photoshop-cs6/
Copy link to clipboard
Copied
I think the background layer might need to be locked after rastorization. Rastorization would unlock the layer, allowing the original layer to be perspective morphed along with the processed layer.
That would need a differen target in the code for locking right? Instead fo "active" layer, it would have to be the layer number or "background layer" or something like that?
Thanks!
Copy link to clipboard
Copied
Here are the processing steps:
(1) open sorted file from originals folder 1 (this is a flattened file)
(2) change Background layer to normal layer, rename layer
(3) lock the only layer currently in the file which is the original image
(4) place sorted file from processed folder 2 (embedded smart object 100% scale)
(5) rasterize selected SO layer to normal layer
(6) select all layers
(7) auto align, auto
(8) save as TIFF to final folder 3
... repeat until input folder list is empty
So it all looks linear and correct. I have verified the steps, but I could be missing something.
I could add a flatten step after step 1, to ensure that the original image does only have a Background layer. I don't think the issue is there.
Steps 4 + 5 could be replaced with a different method, such as duplicate file from processed file list to the open original file.
Copy link to clipboard
Copied
EDIT: I just posted an updated 1.3 version of the script, it has some cosmetic changes. I might need to try a different appraoch to stacking the images, or perhaps the auto align is the problem...
If the problem is in my processing code and you can record an action that works correctly on a layered file, then there are two options:
1) Simply have the script play the action
2) Convert the action to a script and replace my code with the converted code
P.S. I have layered the original image over the stacked image in difference mode, the original image is exactly the same in the stacked image, so the layer locking appears to be working correctly to set this larger image as the reference.
Copy link to clipboard
Copied
Hi @Stephen_A_Marsh,
Version 3 processed the files the same way. Original layer scale is changing on almost every frame. I think the sample images I gave you process fine because there is no scale or perspetive change in the processed files. Therefore "auto" mode is not trying to morph both images. It quickly sees that a position shift of the processed file is all that is necessary, and does not need to perspective shift. The processed file is just a cut out of the original with a desturation.
There has to be something that is either unlocking, or perhaps the script is moving to quickly for the lock kick in before the next move? I know when scripting other apps, I often have to put a puase before some actions, to give the software a split second to catch up. I can't tell, because it moves so fast. Is there a log somewhere that can list the actions that photoshop just completed?
Thanks!
Copy link to clipboard
Copied
Yes, ver 1.3 only has cosmetic changes so no expected difference in processing.
I commented out the close step in the for loop after the save as. Here is a shot from the history panel:
The select all step before the align step is not listed, however, the result on your simpler sample images would be wrong if the auto align only had one layer selected.
I have also examined layered final saves, it all looks good.
So the question remains, can you record an action of the auto align step that provides the correct result on the more complex images that you are testing on?
Copy link to clipboard
Copied
Hi @Stephen_A_Marsh,
Sorry for the delay. I got sucked into another science project. I've decided to start from the beggining on a publicly available video, so that I can share each step with you, and you can see the real world video. Processing should happen overnight. I'll try tomorrow to send links to each part. I'll also google how to record an action and send it to you. Thanks again!
Copy link to clipboard
Copied
Hi @Stephen_A_Marsh ,
Welp, the sample footage I used to share with you worked perfectly during processing, so I didn't need photoshop. Let me find another sample with more movement, and see if I can recreate the error. I also sent a personal message, if there's a way for us post off the forum.
I'll touch base again tomorrow. Thanks!
Copy link to clipboard
Copied
Hi @Stephen_A_Marsh,
Sorry for the late reply. Here are the files and photoshop action:
Files:
https://drive.google.com/drive/folders/1W09nHR6Bra5yu1m5PichjpVjyrvTpkmF?usp=sharing
Recorded Action:
https://drive.google.com/file/d/1r7CxEUPD5RDGmgKhJI_NJmkxjqPDNbuA/view?usp=sharing
Completed Photoshop File:
https://drive.google.com/file/d/1q3jQrYTKGU11vonEzy81NOSKYyyOjwNd/view?usp=sharing
Notes:
Here is what we are trying to defeat. The bobble in the processed file against the original:
https://drive.google.com/file/d/1seEr_3G1H9s5q4gVchpTq6fxUxkldPDN/view?usp=sharing
In my recorded action, I'm still required to choose the two images for the default stack script. However, once I choose the image in the "processed" folder first, then the image in the "original" folder, the action runs and works. In the "JOBS_PS_OUTPUT" folder you can see the final exported tiff.
Thanks again!
Copy link to clipboard
Copied
As I side note, I can't find the edit button, to edit a post. Very strange. Anyway, when double checking that the background image is the same, and hasn't been morphed, look at the TIFF in the JOBS_PS_OUTPUT folder, inside the "FILES" folder (the first link).
Thanks!
Copy link to clipboard
Copied
Thanks for the files and action.
I have tried three different scripted methods to layer the files:
1) Two separate folders, place command
2) Two separate folders, duplicate command
3 One folder, two files, script to call the load layers into stack script
Then I used a modifed version of your action, however, the step to auto align was not altered.
The results of all three methods slightly differed from your AUTO-ALIGNED_FILE.tif example for the aligned area. The rest of the image had no differences when compared with difference blend tests.
So, I think that we are back where we started!
EDIT: Perhaps if I just revise the script to work with the action and I show you how to select the layers in a relative fashion rather than absolute, then you could perhaps get the result you want.
Copy link to clipboard
Copied
Hi @Stephen_A_Marsh,
I'll try a relative instead of absolute. The main issue is not having to select each image, one at a time. There could be tens of thousands of frames.
Are you saying the background is no longer changing? It remains locked? Then my thought is maybe pause before auto-align and after the auto-align feature. Maybe there needs to be time for PS to think?
Copy link to clipboard
Copied
The differences in stacking that I am seeing may only be due to your pre-processing and JPG vs. TIFF.
What I'm thinking is that If the action works for you when the script previously provided does not, then new script can run the action. I can't keep flogging this dead horse, I have to close this project.
Example of your .atn file modified for use in my script. I still have to adjust the script code to suit:
Download link to action set:
https://shared-assets.adobe.com/link/a8800853-6e09-4f39-4d3e-71569bebab33
Copy link to clipboard
Copied
Here is the v1.4 script to run the revised action using relative layer selection steps:
/*
Photoshop script to auto stack pair of images, then auto-align, and export.
https://community.adobe.com/t5/photoshop/photoshop-script-to-auto-stack-pair-of-images-then-auto-align-and-export/td-p/11989171
Auto Align Files from 2 Folders to TIFF.jsx
Stephen Marsh
Version 1.4 - 6th May 2021
*/
#target photoshop
(function () {
if (app.documents.length === 0) {
// Save the current dialog display settings
var savedDisplayDialogs = app.displayDialogs;
app.displayDialogs = DialogModes.NO;
// Input folder 1
var folder1 = Folder.selectDialog("Please select the originals folder");
if (folder1 === null) return;
// Input folder 2
var folder2 = Folder.selectDialog("Please select the processed files folder");
if (folder2 === null) return;
// Validate input folder selection
var validateInputDir = (folder1.fsName === folder2.fsName);
if (validateInputDir === true) {
alert("Script cancelled as both the input folders are the same");
return;
}
var searchMask = '*.???';
var list1 = folder1.getFiles(searchMask);
var list2 = folder2.getFiles(searchMask);
// Alpha-numeric sort
list1.sort();
list2.sort();
// Validate that folder 1 & 2 lists are not empty
var validateEmptyList = (list1.length > 0 && list2.length > 0);
if (validateEmptyList === false) {
alert("Script cancelled as one of the input folders is empty");
return;
}
// Validate that the item count in folder 1 & 2 matches
var validateListLength = (list1.length === list2.length);
if (validateListLength === false) {
alert("Script cancelled as the input folders don't have equal quantities of images");
return;
}
// Output folder
var saveFolder = Folder.selectDialog("Please select the folder to save to");
if (saveFolder === null) return;
for (var i = 0; i < list1.length; i++) {
var doc = open(list1[i]);
var docName = doc.name.replace(/\.[^\.]+$/, '');
backgroundLayerNameToVariableName(docName, 100, 2);
placeFile(list2[i], 100);
app.runMenuItem(stringIDToTypeID('rasterizePlaced'));
// Action set to run
var actionSet = "AUTO-ALIGN-SET2";
// Action to run from set
var actionName = "AUTO_ALIGN2";
// Run it!
app.doAction(actionName, actionSet);
tiffSaveOptions = new TiffSaveOptions();
tiffSaveOptions.embedColorProfile = true;
tiffSaveOptions.byteOrder = ByteOrder.IBM;
tiffSaveOptions.transparency = true;
tiffSaveOptions.layers = false;
tiffSaveOptions.layerCompression = LayerCompression.ZIP;
tiffSaveOptions.interleaveChannels = true;
tiffSaveOptions.alphaChannels = true;
tiffSaveOptions.annotations = true;
tiffSaveOptions.spotColors = true;
tiffSaveOptions.saveImagePyramid = false;
tiffSaveOptions.imageCompression = TIFFEncoding.NONE;
doc.saveAs(new File(saveFolder + '/' + docName + '.tif'), tiffSaveOptions);
doc.close(SaveOptions.DONOTSAVECHANGES);
}
alert('Script completed!' + '\n' + 'Files saved to:' + '\r' + saveFolder.fsName);
// Restore the dialogs
app.displayDialogs = savedDisplayDialogs;
// Here be functions
function placeFile(file, scale) {
var idPlc = charIDToTypeID("Plc ");
var desc2 = new ActionDescriptor();
var idnull = charIDToTypeID("null");
desc2.putPath(idnull, new File(file));
var idFTcs = charIDToTypeID("FTcs");
var idQCSt = charIDToTypeID("QCSt");
var idQcsa = charIDToTypeID("Qcsa");
desc2.putEnumerated(idFTcs, idQCSt, idQcsa);
var idOfst = charIDToTypeID("Ofst");
var desc3 = new ActionDescriptor();
var idHrzn = charIDToTypeID("Hrzn");
var idPxl = charIDToTypeID("#Pxl");
desc3.putUnitDouble(idHrzn, idPxl, 0.000000);
var idVrtc = charIDToTypeID("Vrtc");
var idPxl = charIDToTypeID("#Pxl");
desc3.putUnitDouble(idVrtc, idPxl, 0.000000);
var idOfst = charIDToTypeID("Ofst");
desc2.putObject(idOfst, idOfst, desc3);
var idWdth = charIDToTypeID("Wdth");
var idPrc = charIDToTypeID("#Prc");
desc2.putUnitDouble(idWdth, idPrc, scale);
var idHght = charIDToTypeID("Hght");
var idPrc = charIDToTypeID("#Prc");
desc2.putUnitDouble(idHght, idPrc, scale);
var idAntA = charIDToTypeID("AntA");
desc2.putBoolean(idAntA, true);
executeAction(idPlc, desc2, DialogModes.NO);
}
function backgroundLayerNameToVariableName(layerName, opacity, layerID) {
var c2t = function (s) {
return app.charIDToTypeID(s);
};
var s2t = function (s) {
return app.stringIDToTypeID(s);
};
var descriptor = new ActionDescriptor();
var descriptor2 = new ActionDescriptor();
var reference = new ActionReference();
reference.putProperty(s2t("layer"), s2t("background"));
descriptor.putReference(c2t("null"), reference);
descriptor2.putString(s2t("name"), layerName);
descriptor2.putUnitDouble(s2t("opacity"), s2t("percentUnit"), opacity);
descriptor2.putEnumerated(s2t("mode"), s2t("blendMode"), s2t("normal"));
descriptor.putObject(s2t("to"), s2t("layer"), descriptor2);
descriptor.putInteger(s2t("layerID"), layerID);
executeAction(s2t("set"), descriptor, DialogModes.NO);
}
}
else {
alert('Please close all open documents before running this script!');
}
}());
Copy link to clipboard
Copied
Hi @Stephen_A_Marsh,
Thanks for all your effort. I don't want you to beat a dead horse either. Such as shame, if only we could lock down that background layer, then it would work perfectly.
Here is v1.4 of the script, with your modification of my actions. You see that the processed image lines up well enough with the background image, but the background image is still morphing or changing shape. I thought I saw something about align to canvas in the script, but I could not find that again to quote.
Here are the images running in real time. You can see the background layer changing scale:
https://drive.google.com/file/d/1gRTJ329sFZO75GiSQkize3QuRiYeuELO/view?usp=sharing
Thanks again!