Copy link to clipboard
Copied
Hello everyone,
I edit a lot of pictures of carpets and a lot of times this angle right here is not mirrored perfectly:
i don't want it to be mirrored because every side is different, but i want the shape to be mirrored. I created an action that takes half the carpet from the left half and shows it on the right, also created the difference between the mirrored red layer and the carpet, and half of the difference as well.
If i'll use Free Transform > Skew to put half the difference on the red layer and then skew the carpet to touch the half difference i should have auto mirrored skewed carpet.
the problem is that i want it to be as automated as it can be, i don't know how to skew the half difference to the red layer not manually.
and also auto skew to mirror automatically.
I'm sure there's a better way or idea than mine, anyone?
If your carpet is a separate layer with transparency, then you can try this method skew.
It is assumed that the upper and lower parts of the trapezoid are fairly horizontal.
...app.activeDocument.suspendHistory("Skew","skew_straighten_layer()");
function skew_straighten_layer()
{
try {
app.preferences.rulerUnits = Units.PIXELS;
var doc = app.activeDocument;
var layer = app.activeDocument.activeLayer;
selection_from_layer();
var dh = Number(l
Copy link to clipboard
Copied
If your carpet is a separate layer with transparency, then you can try this method skew.
It is assumed that the upper and lower parts of the trapezoid are fairly horizontal.
app.activeDocument.suspendHistory("Skew","skew_straighten_layer()");
function skew_straighten_layer()
{
try {
app.preferences.rulerUnits = Units.PIXELS;
var doc = app.activeDocument;
var layer = app.activeDocument.activeLayer;
selection_from_layer();
var dh = Number(layer.bounds[3].value - layer.bounds[1].value)*0.01;
select_single_line(Number(layer.bounds[1].value) + dh, true, stringIDToTypeID("intersectWith"));
var x0 = Number(doc.selection.bounds[2].value + doc.selection.bounds[0].value)/2;
var y0 = Number(doc.selection.bounds[3].value);
selection_from_layer();
select_single_line(Number(layer.bounds[3].value) - dh, true, stringIDToTypeID("intersectWith"));
var x1 = Number(doc.selection.bounds[2].value + doc.selection.bounds[0].value)/2;
var y1 = Number(doc.selection.bounds[3].value);
doc.selection.deselect();
var w = x1 - x0;
var h = y1 - y0;
var angle;
if (h != 0)
{
angle = Math.atan(w/h) * 180.0 / Math.PI;
skew(layer, -angle,0, x1, y1);
}
}
catch (e) { alert(e) }
}
function select_single_line(x, h, mode)
{
try
{
if (mode == undefined) mode = stringIDToTypeID("set");
var r = new ActionReference();
r.putProperty(stringIDToTypeID("channel"), stringIDToTypeID("selection"));
var d = new ActionDescriptor();
d.putReference(stringIDToTypeID("target"), r);
var d1 = new ActionDescriptor();
d1.putUnitDouble(stringIDToTypeID(h?"top":"left"), stringIDToTypeID("pixelsUnit"), x);
d.putObject(stringIDToTypeID("to"), stringIDToTypeID(h?"singleRow":"singleColumn"), d1);
executeAction(mode, d, DialogModes.NO);
}
catch (e) { throw(e); }
}
function selection_from_layer()
{
try
{
var r = new ActionReference();
r.putProperty(stringIDToTypeID("channel"), stringIDToTypeID("selection"));
var d = new ActionDescriptor();
d.putReference(stringIDToTypeID("target"), r);
var r = new ActionReference();
r.putEnumerated(stringIDToTypeID("channel"), stringIDToTypeID("channel"), stringIDToTypeID("transparencyEnum"));
d.putReference(stringIDToTypeID("to"), r);
executeAction(stringIDToTypeID("set"), d, DialogModes.NO);
}
catch (e) { throw(e); }
}
function skew(layer, h,v, x, y)
{
try
{
app.activeDocument.activeLayer = layer;
var d1 = new ActionDescriptor();
var d2 = new ActionDescriptor();
var d3 = new ActionDescriptor();
var d4 = new ActionDescriptor();
var r1 = new ActionReference();
r1.putEnumerated( charIDToTypeID( "Lyr " ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );
d1.putReference( charIDToTypeID( "null" ), r1 );
d1.putEnumerated( charIDToTypeID( "FTcs" ), charIDToTypeID( "QCSt" ), charIDToTypeID( "Qcsi" ) );
if (x != undefined && y != undefined)
{
d2.putUnitDouble( charIDToTypeID( "Hrzn" ), charIDToTypeID( "#Pxl" ), x );
d2.putUnitDouble( charIDToTypeID( "Vrtc" ), charIDToTypeID( "#Pxl" ), y );
d1.putObject( charIDToTypeID( "Pstn" ), charIDToTypeID( "Pnt " ), d2 );
}
d4.putUnitDouble( charIDToTypeID( "Hrzn" ), charIDToTypeID( "#Ang" ), h );
d4.putUnitDouble( charIDToTypeID( "Vrtc" ), charIDToTypeID( "#Ang" ), v );
d1.putObject( charIDToTypeID( "Skew" ), charIDToTypeID( "Pnt " ), d4 );
executeAction( charIDToTypeID( "Trnf" ), d1, DialogModes.NO );
}
catch (e) { throw(e); }
}
Copy link to clipboard
Copied
it was perfect in the last 10 carpets i tried that on!
thank you!
you think it may work on other shapes, for example this corner of the carpet:
Copy link to clipboard
Copied
you think it may work on other shapes, for example this corner of the carpet:
It's not clear how to straighten.
If you use Skew, you get something like this.
You can use Rotation. The result will also be with gaps. The use of Distort distorts everything at all.
Copy link to clipboard
Copied
this is the end result i'm targeting to:
Copy link to clipboard
Copied
I can not think of a distortion algorithm. If you show me how to manually (by steps) do the distortion to get the result, maybe I can help
Copy link to clipboard
Copied
i'm showing the action i made, i'm sorry if it's long most of it pictures:
1.so this is how i'm getting the image
2. I clean the background (either Select>Subject, JJ-Mack's Script to clear background, or manually: Lasso/Magic Wand/Quick Selection tool),
then Image>Trim to see nothing left and i'm getting here:
3. as we can see it's not symmetric
4. I have an action from this point: Convert to Smart Object, Canvas Size to my needs: 1200x1200, and then Script: Fit Layer to Canvas (and i keep the aspect ratio) so the layer is exactly on the edges of the canvas:
5. I have couple of transforms i do the work for most carpets, we can see what they actually do on the left, the next one involves mostly enlarging
next one involves small rotation
now i align the carpet, first to horizontal center
next align is to top edges so the top of the carpet will be on the line of the top of the canvas
the next two transforms are just moving the carpet up to get rid of the white space created on the top-right corner, and afterwards more enlarging
the last step before saving it is manual distortion
that's it.
i probably made a lot of Free Transform recording, but that's an action so it's running in the background, i would really want to improve that so it will work on more carpets, since other carpets in this angle can look different so my free transforms would not work as this one above.
Copy link to clipboard
Copied
OK. Here is a simple version that uses only Skew.
It is assumed that the edges of the layer on the left and right completely extend beyond the canvas, approximately as in the pictures
app.activeDocument.suspendHistory("Skew 2","skew_straighten_layer2()");
function skew_straighten_layer2()
{
try {
app.preferences.rulerUnits = Units.PIXELS;
var doc = app.activeDocument;
var layer = app.activeDocument.activeLayer;
doc.selection.selectAll();
selection_from_layer(stringIDToTypeID("intersect"));
select_single_line(0, false, stringIDToTypeID("intersectWith"));
var x0 = 0;
var y0 = Number(doc.selection.bounds[3].value);
doc.selection.selectAll();
selection_from_layer(stringIDToTypeID("intersect"));
select_single_line(Number(doc.width.value)-1, false, stringIDToTypeID("intersectWith"));
var x1 = Number(doc.width.value)-1;
var y1 = Number(doc.selection.bounds[3].value);
doc.selection.deselect();
var h = x1 - x0;
var w = y1 - y0;
if (h != 0)
{
var angle = Math.atan(w/h) * 180.0 / Math.PI;
if (y0 > y1)
skew(layer, 0, -angle, x1, y1);
else
skew(layer, 0, -angle, x0, y0);
}
}
catch (e) { alert(e) }
}
function select_single_line(x, h, mode)
{
try
{
if (mode == undefined) mode = stringIDToTypeID("set");
var r = new ActionReference();
r.putProperty(stringIDToTypeID("channel"), stringIDToTypeID("selection"));
var d = new ActionDescriptor();
d.putReference(stringIDToTypeID("target"), r);
var d1 = new ActionDescriptor();
d1.putUnitDouble(stringIDToTypeID(h?"top":"left"), stringIDToTypeID("pixelsUnit"), x);
d.putObject(stringIDToTypeID("to"), stringIDToTypeID(h?"singleRow":"singleColumn"), d1);
executeAction(mode, d, DialogModes.NO);
}
catch (e) { throw(e); }
}
function selection_from_layer(mode)
{
try
{
if (mode == undefined)
{
var d = new ActionDescriptor();
var r = new ActionReference();
r.putProperty(stringIDToTypeID("channel"), stringIDToTypeID("selection"));
d.putReference(stringIDToTypeID("target"), r);
var r = new ActionReference();
r.putEnumerated(stringIDToTypeID("channel"), stringIDToTypeID("channel"), stringIDToTypeID("transparencyEnum"));
d.putReference(stringIDToTypeID("to"), r);
executeAction(stringIDToTypeID("set"), d, DialogModes.NO);
}
else
{
var d = new ActionDescriptor();
var r = new ActionReference();
r.putEnumerated(stringIDToTypeID("channel"), stringIDToTypeID("channel"), stringIDToTypeID("transparencyEnum"));
d.putReference(stringIDToTypeID("null"), r);
var r = new ActionReference();
r.putProperty(stringIDToTypeID("channel"), stringIDToTypeID("selection"));
d.putReference(stringIDToTypeID("with"), r);
executeAction(mode, d, DialogModes.NO);
}
}
catch (e) { throw(e); }
}
function skew(layer, h,v, x, y)
{
try
{
app.activeDocument.activeLayer = layer;
var d1 = new ActionDescriptor();
var d2 = new ActionDescriptor();
var d3 = new ActionDescriptor();
var d4 = new ActionDescriptor();
var r1 = new ActionReference();
r1.putEnumerated( charIDToTypeID( "Lyr " ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );
d1.putReference( charIDToTypeID( "null" ), r1 );
d1.putEnumerated( charIDToTypeID( "FTcs" ), charIDToTypeID( "QCSt" ), charIDToTypeID( "Qcsi" ) );
if (x != undefined && y != undefined)
{
d2.putUnitDouble( charIDToTypeID( "Hrzn" ), charIDToTypeID( "#Pxl" ), x );
d2.putUnitDouble( charIDToTypeID( "Vrtc" ), charIDToTypeID( "#Pxl" ), y );
d1.putObject( charIDToTypeID( "Pstn" ), charIDToTypeID( "Pnt " ), d2 );
}
d4.putUnitDouble( charIDToTypeID( "Hrzn" ), charIDToTypeID( "#Ang" ), h );
d4.putUnitDouble( charIDToTypeID( "Vrtc" ), charIDToTypeID( "#Ang" ), v );
d1.putObject( charIDToTypeID( "Skew" ), charIDToTypeID( "Pnt " ), d4 );
executeAction( charIDToTypeID( "Trnf" ), d1, DialogModes.NO );
}
catch (e) { throw(e); }
}