Copy link to clipboard
Copied
Hello everyone,
I attached some picture of what I want to do, I already put a threshold adjustment layer, now i want to select the biggest black object in the picture.
It is a one piece, and usually in different places so recording magic wand for example in the same location every time won't help, also Photoshop "Select Subject" isn't a good solution.
here are the pictures, let me know what you think
The value you switched to is too low as process will take too long time. Use at least value 2 or higher like I suggested so it's going to work very fast. I was aware of edges they will be rounded, and adviced to add part of code that fix that (however I guess you could do it manually).
You must specify the value of Magic Wand if you use 'Select / Grow'. I'm not sure why you then use Expand +4, but if you added additional step that selecting black pixels again you had perfect selection of your car
...Copy link to clipboard
Copied
You may change .5 to bigger value so the process will be faster but less precious, and error may occur on too small paths:
sTT = stringIDToTypeID, dsc = new ActionDescriptor()
dsc.putEnumerated(sTT('colors'), sTT('colors'), sTT('shadows'))
dsc.putInteger(sTT('shadowsUpperLimit'), 0), dsc.putBoolean(sTT('invert'), false)
ref1 = new ActionReference(), ref2 = new ActionReference(), ref1.putClass(sTT('path'))
dsc.putReference(sTT('null'), ref1), ref2.putProperty(sTT('selectionClass'), sTT('selection'))
dsc.putReference(sTT('from'), ref2), dsc.putUnitDouble(sTT('tolerance'), sTT('pixelsUnit'), .5)
executeAction(sTT('colorRange'), dsc), executeAction(sTT('make'), dsc)
len = (sPI = (pI0 = (aD = activeDocument).pathItems[0]).subPathItems).length
for(arr = [], i = 0; i < len; i++) {
for(pts = [], j = 0; j < (pP = sPI.pathPoints).length;) pts.push(pP[j++].anchor);
(sel = aD.selection).select(pts), hst = aD.histogram[0]
if (!arr.length || hst > arr[0][0]) arr[0] = [hst, pts]
}
pI0.remove(), sel.select(arr[0][1])
Copy link to clipboard
Copied
tried that with .5 and it took like 10 minutes and returned an error, is there a way to do it without paths? (i think it takes too long)
Copy link to clipboard
Copied
Didn't you try with higher value like 10? If you're getting still error link me to uploaded image you're having it with.
Copy link to clipboard
Copied
these are the 3 layers I have, which one should I choose before the script?
Copy link to clipboard
Copied
I created above layers. Bottom with White fill, middle with gray fill of objects & transparency, top with thereshold set to 255.
With all visible layers I activated the middle one, then I ran script and it worked (with 10 value) - selected the biggest object.
If you can't get expected result then like I said - upload one or more documents you're having error with so I'll see it myself.
By the error I meant Photoshop crashes what I found why happens. If you want above code worked change first 7 lines to:
sTT = stringIDToTypeID, dsc = new ActionDescriptor()
dsc.putEnumerated(c = sTT('colors'), c, sTT('shadows'))
executeAction(sTT('colorRange'), dsc)
dsc.putInteger(sTT('shadowsUpperLimit'), 0), dsc.putBoolean(sTT('invert'), false)
ref1 = new ActionReference(), ref2 = new ActionReference(), ref1.putClass(sTT('path'))
dsc.putReference(sTT('null'), ref1), ref2.putProperty(sTT('selectionClass'), sTT('selection'))
dsc.putReference(sTT('from'), ref2), dsc.putUnitDouble(sTT('tolerance'), sTT('pixelsUnit'), 1)
executeAction(sTT('make'), dsc)
You may also change 1 (prev. 0.5) value to higher one, or better add to script 'Select / Grow' so it'll select all found black px.
Copy link to clipboard
Copied
the first script:
sTT = stringIDToTypeID, dsc = new ActionDescriptor()
dsc.putEnumerated(sTT('colors'), sTT('colors'), sTT('shadows'))
dsc.putInteger(sTT('shadowsUpperLimit'), 0), dsc.putBoolean(sTT('invert'), false)
ref1 = new ActionReference(), ref2 = new ActionReference(), ref1.putClass(sTT('path'))
dsc.putReference(sTT('null'), ref1), ref2.putProperty(sTT('selectionClass'), sTT('selection'))
dsc.putReference(sTT('from'), ref2), dsc.putUnitDouble(sTT('tolerance'), sTT('pixelsUnit'), .5)
executeAction(sTT('colorRange'), dsc), executeAction(sTT('make'), dsc)
len = (sPI = (pI0 = (aD = activeDocument).pathItems[0]).subPathItems).length
for(arr = [], i = 0; i < len; i++) {
for(pts = [], j = 0; j < (pP = sPI.pathPoints).length;) pts.push(pP[j++].anchor);
(sel = aD.selection).select(pts), hst = aD.histogram[0]
if (!arr.length || hst > arr[0][0]) arr[0] = [hst, pts]
pI0.remove(), sel.select(arr[0][1])
returned:
^ it also took a lot of time
this script
sTT = stringIDToTypeID, dsc = new ActionDescriptor()
dsc.putEnumerated(sTT('colors'), sTT('colors'), sTT('shadows'))
dsc.putInteger(sTT('shadowsUpperLimit'), 0), dsc.putBoolean(sTT('invert'), false)
ref1 = new ActionReference(), ref2 = new ActionReference(), ref1.putClass(sTT('path'))
dsc.putReference(sTT('null'), ref1), ref2.putProperty(sTT('selectionClass'), sTT('selection'))
dsc.putReference(sTT('from'), ref2), dsc.putUnitDouble(sTT('tolerance'), sTT('pixelsUnit'), 1)
executeAction(sTT('colorRange'), dsc), executeAction(sTT('make'), dsc)
len = (sPI = (pI0 = (aD = activeDocument).pathItems[0]).subPathItems).length
for(arr = [], i = 0; i < len; i++) {
for(pts = [], j = 0; j < (pP = sPI.pathPoints).length;) pts.push(pP[j++].anchor);
(sel = aD.selection).select(pts), hst = aD.histogram[0]
if (!arr.length || hst > arr[0][0]) arr[0] = [hst, pts]
pI0.remove(), sel.select(arr[0][1])
returned:
this script:
sTT = stringIDToTypeID, dsc = new ActionDescriptor()
dsc.putEnumerated(c = sTT('colors'), c, sTT('shadows'))
executeAction(sTT('colorRange'), dsc)
dsc.putInteger(sTT('shadowsUpperLimit'), 0), dsc.putBoolean(sTT('invert'), false)
ref1 = new ActionReference(), ref2 = new ActionReference(), ref1.putClass(sTT('path'))
dsc.putReference(sTT('null'), ref1), ref2.putProperty(sTT('selectionClass'), sTT('selection'))
dsc.putReference(sTT('from'), ref2), dsc.putUnitDouble(sTT('tolerance'), sTT('pixelsUnit'), 1)
executeAction(sTT('make'), dsc)
returned:
so every one of them still haven't selected the main subject
Copy link to clipboard
Copied
I don't have your files, but created similar ones on my own and everything worked. So it would be helpful you shared some files it doesn't work on that I ask you now for the 3rd time. Or you do not want to help me while you want I helped you
Copy link to clipboard
Copied
Your help is much appreciated!
Here is the image. it came from a NEF file type (RAW image) and the dimensions are 6000x4000px
I saved it as a jpg because the PSD/TIF file or the NEF file is too big (let me know if you want me still to upload the big file and send you a link to it)
But still, save this jpg, Magic Wand on the white part to delete it + add a threshold adjustment layer of 253 then we will be in the same position
let me know, thank you!
Copy link to clipboard
Copied
If you shared that file in no time probably you wouldn't wait so long for the code. I've found there was a bug in my code, it didn't work well with your graphics that luckily didn't affect images I created independently. So in my last full code beside the change you did last time please change also lines 13th and 14th ie:
(sel = aD.selection).select(pts), hst = aD.histogram[0]
if (!arr.length || hst > arr[0][0]) arr[0] = [hst, pts]
to:
(sel = aD.selection).select(pts), $.level = 0; try{
sel.bounds, hst = aD.histogram[0]
if (!arr.length || hst > arr[0][0]) arr[0] = [hst, pts]
}
catch(err){}
Also to make script finished its work in 2 seconds (at least on provided image) instead of for ex. like one minute, use Magic Wand with 10 for tolerance (plus Anti-alias and Contigous) while you are clicking on white area. Remember also to use this time a value 2 or higher in the code where originally I suggested 10 and then changed to 1. Hiding panels speeds up as well.
Share more images since for now I can not imagine all circumstances to write proper script it fitted to most possible cases.
Copy link to clipboard
Copied
I switched the two lines, value is 1, here is the immediate result:
edges are a bit not precise since it relies on work path:
So I used Select > Grow Like you told me on your first reply + Expand 4px,
It's not perfect because it's via paths but it's good enough, i will try on many more pictures and share them
Thank you
Copy link to clipboard
Copied
The value you switched to is too low as process will take too long time. Use at least value 2 or higher like I suggested so it's going to work very fast. I was aware of edges they will be rounded, and adviced to add part of code that fix that (however I guess you could do it manually).
You must specify the value of Magic Wand if you use 'Select / Grow'. I'm not sure why you then use Expand +4, but if you added additional step that selecting black pixels again you had perfect selection of your carpet. Anyway here is complete code for that:
sTT = stringIDToTypeID, dsc = new ActionDescriptor()
function cR() {
dsc.putEnumerated(c = sTT('colors'), c, sTT('shadows')), executeAction(sTT('colorRange'), dsc)
}
cR(), dsc.putInteger(sTT('shadowsUpperLimit'), 0), dsc.putBoolean(sTT('invert'), false)
ref1 = new ActionReference(), ref2 = new ActionReference(), ref1.putClass(sTT('path'))
dsc.putReference(sTT('null'), ref1), ref2.putProperty(sTT('selectionClass'), sTT('selection'))
dsc.putReference(sTT('from'), ref2), dsc.putUnitDouble(sTT('tolerance'), sTT('pixelsUnit'), 2)
executeAction(sTT('make'), dsc)
len = (sPI = (pI0 = (aD = activeDocument).pathItems[0]).subPathItems).length
for(arr = [], i = 0; i < len; i++) {
for(pts = [], j = 0; j < (pP = sPI.pathPoints).length;) pts.push(pP[j++].anchor);
(sel = aD.selection).select(pts), hst = aD.histogram[0]
$.level = 0; try{
sel.bounds; if (!arr.length || hst > arr[0][0]) arr[0] = [hst, pts, i]
}
catch(err){}
}
pI0.remove(), sel.select(arr[0][1]), sel.grow(255, true), sel.expand(5), cR()
In the last line instead of sel.grow(255, true), sel.expand(5), cR() you can use sel.contract(5), sel.grow(255, true)​ so it's going to select all little white pixels inside of main subject also to avoid selection of little dark pixels outside of carpet.
And yes share more pictures, I wonder how that will work on rest of them
Ah, and the procedure is accordingly to that you provided:
- there still must be 3 layers (Threshold set to 255, middle main layer and Color Fill - white - layer)
- you make active middle layer, use Magic Wand on White area (with tolerance of 10)
- after you remove and deselect selected white area you run script (value 2)
Copy link to clipboard
Copied
Perfect.
Copy link to clipboard
Copied
For your file.
Select white background with a magic wand.
Run the script.
You will get selected carpet.
select_max_selection();
alert("Done!");
function select_max_selection()
{
try {
// selection to workpath
var d = new ActionDescriptor();
var r = new ActionReference();
r.putClass(stringIDToTypeID("path"));
d.putReference(stringIDToTypeID("null"), r);
var r1 = new ActionReference();
r1.putProperty(stringIDToTypeID("selectionClass"), stringIDToTypeID("selection"));
d.putReference(stringIDToTypeID("from"), r1);
d.putUnitDouble(stringIDToTypeID("tolerance"), stringIDToTypeID("pixelsUnit"), 0.5);
executeAction(stringIDToTypeID("make"), d, DialogModes.NO);
// leave only one subpath with maximum points;
var d = new ActionDescriptor();
var r = new ActionReference();
r.putEnumerated(stringIDToTypeID("path"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var pth = executeActionGet(r).getObjectValue(stringIDToTypeID("pathContents"));
var lst = pth.getList(stringIDToTypeID("pathComponents"));
var list = new ActionList();
var len = lst.count;
var max;
var max_obj;
for (var i = 0; i < len; i++)
{
var obj = lst.getObjectValue(i);
var count = obj.getList(stringIDToTypeID("subpathListKey")).getObjectValue(0).getList(stringIDToTypeID("points")).count;
if (!max || max < count)
{
max = count;
max_obj = obj;
}
}
max_obj.putEnumerated(stringIDToTypeID("shapeOperation"), stringIDToTypeID("shapeOperation"), stringIDToTypeID("add") );
list.putObject(stringIDToTypeID("pathComponent"), max_obj);
var r = new ActionReference();
r.putProperty( charIDToTypeID( "Path" ), charIDToTypeID( "WrPt" ) );
d.putReference( stringIDToTypeID( "null" ), r );
d.putList(charIDToTypeID("T "), list);
executeAction(charIDToTypeID("setd"), d, DialogModes.NO);
// workpath to selection
var d = new ActionDescriptor();
var r = new ActionReference();
r.putProperty(stringIDToTypeID("channel"), stringIDToTypeID("selection"));
d.putReference(stringIDToTypeID("null"), r);
var r1 = new ActionReference();
r1.putProperty(stringIDToTypeID("path"), stringIDToTypeID("workPath"));
d.putReference(stringIDToTypeID("to"), r1);
d.putBoolean(stringIDToTypeID("antiAlias"), true);
d.putUnitDouble(stringIDToTypeID("feather"), stringIDToTypeID("pixelsUnit"), 0);
executeAction(stringIDToTypeID("set"), d, DialogModes.NO);
// delete workpath
var doc = app.activeDocument;
for (var i = 0; i < doc.pathItems.length; i++)
{
if (doc.pathItems.kind == PathKind.WORKPATH)
{
doc.pathItems.remove();
break;
}
}
}
catch(e) { alert(e); }
}
Copy link to clipboard
Copied
"Select white background with a magic wand."
is there a way to automate it?
in the following picture I've added a relative 300px enlargement in canvas size, so the 300px "frame" is always white (maybe it can help),
maybe automate choosing top left pixel with magic wand? (resolution might change from picture to picture)
UP1: used Color Range, worked like a charm