photoshop - 如何根据一个特定调整大量图像的颜色?
问题描述
我有大量照片,我想将它们带到相同的“水平”——相同的颜色/亮度/对比度等。为此,我有一个带有黑白颜色检查器的初始/指南(基本上是带颜色的正方形) ,我将其添加到所有其他照片中。
这是初始/指南https://imgur.com/a/Jlozy1e这些是一些照片https://imgur.com/JUsKMt2、https://imgur.com/PvqsleR、https://imgur。 com/tcMROU9
正如我所看到的那样,所有照片中带有小方块颜色(颜色控制方块)的区域必须是相同的颜色(十六进制值),以便它们处于同一水平 - 所以我可以从下面的条带中获得有意义的数据。
有没有办法在 Photoshop 或其他工具中使用自动/批处理方式?
编辑:请注意,可能比我想保留它们的控制方块中的区域更暗/更亮(只是相应地变亮/变暗,但不能完全用阈值颜色替换它们)
解决方案
我不知道这是否可以使用任何高级工具,但这是我对 Photoshop 的看法。这个想法很简单——使用渐变映射将目标颜色重新映射到源值(因此这不适用于 32 位 tiff):
- 来自活动文档(源文档)的样本源颜色;
- 要求打开其他文件的路径,开始一一打开;
- 对目标颜色进行采样并获取它们在渐变映射中的位置
- 使用源颜色和目标位置创建渐变图
这是我得到的结果:左行是原始文档,上面有一块源方块供参考,右行是应用了渐变图的结果文档,顶部是源文档的相同切片(几乎不可见) :
这是我制作的脚本。
请注意,我使用的是您的 png 文件,因此如果您的文件大小不同,您可能需要调整颜色采样器的坐标。
var sampler, sampledColors, sourceCoords, targetCoords;
// defining coordinates to sample 6 colors from the active source-document
sourceCoords = [
[55, 318],
[190, 318],
[310, 318],
[420, 318],
[560, 318],
[690, 318],
];
// defining coordinates to sample target colors from target documents
targetCoords = [
[78, 120],
[206, 120],
[328, 120],
[453, 120],
[577, 120],
[709, 120],
]
// a library
var Utils = Utils ||
{
// will add photoshop Color Sampler to document
addSample: function(coord)
{
return app.activeDocument.colorSamplers.add(coord);
},
// reads color from a Color Sampler
readSample: function(sample)
{
return sample.color;
},
// gets a collection of Color Samplers
getSamplers: function()
{
return app.activeDocument.colorSamplers;
},
// deletes a Color Sampler
deleteSample: function(sample)
{
sample.remove();
},
// RGB > YUV color translation
rgb2yuv: function(rgb)
{
var r = rgb[0] / 255,
g = rgb[1] / 255,
b = rgb[2] / 255;
var y = (r * 0.299) + (g * 0.587) + (b * 0.114);
var u = (r * -0.14713) + (g * -0.28886) + (b * 0.436);
var v = (r * 0.615) + (g * -0.51499) + (b * -0.10001);
return [y, u, v];
},
// Linear transformation
linear: function(X, A, B, C, D, _cut)
{
var _cut = _cut !== undefined ? _cut : false;
var Y = (X - A) / (B - A) * (D - C) + C
if (_cut)
{
if (Y > D) Y = D;
if (Y < C) Y = C;
}
return Y;
},
// changes active document color space to RGB
docToRgb: function()
{
var desc16 = new ActionDescriptor();
desc16.putClass(charIDToTypeID('T '), charIDToTypeID('RGBM'));
desc16.putBoolean(charIDToTypeID('Fltt'), false);
desc16.putBoolean(charIDToTypeID('Rstr'), false);
executeAction(charIDToTypeID('CnvM'), desc16, DialogModes.NO);
},
/**
* @description Creates a rectangle selection in a specific coordinates with a predefined delta: -7 / +7 to 'coord' values
* @param {array} - [0] is X, [1] is Y coordinates
*
* @return nothing
*/
rectangleSelection: function(coord)
{
var delta = 7;
var descRectangleSelection = new ActionDescriptor();
var rectSelectionRef = new ActionReference();
rectSelectionRef.putProperty(charIDToTypeID('Chnl'), charIDToTypeID('fsel'));
descRectangleSelection.putReference(charIDToTypeID('null'), rectSelectionRef);
var descCoords = new ActionDescriptor();
descCoords.putUnitDouble(charIDToTypeID('Top '), charIDToTypeID('#Pxl'), coord[1] - delta);
descCoords.putUnitDouble(charIDToTypeID('Left'), charIDToTypeID('#Pxl'), coord[0] - delta);
descCoords.putUnitDouble(charIDToTypeID('Btom'), charIDToTypeID('#Pxl'), coord[1] + delta);
descCoords.putUnitDouble(charIDToTypeID('Rght'), charIDToTypeID('#Pxl'), coord[0] + delta);
descRectangleSelection.putObject(charIDToTypeID('T '), charIDToTypeID('Rctn'), descCoords);
executeAction(charIDToTypeID('setd'), descRectangleSelection, DialogModes.NO);
},
/**
* @description saves an active document as a TIF file
* @param {object} data - .name (without extension) for a name and data.path for a path
*
* @return nothing
*/
saveTIF: function(data)
{
if (!new Folder(data.path).exists) new Folder(data.path).create();
var desc = new ActionDescriptor();
var descOptions = new ActionDescriptor();
descOptions.putEnumerated(charIDToTypeID('BytO'), charIDToTypeID('Pltf'), charIDToTypeID('Mcnt'));
descOptions.putEnumerated(stringIDToTypeID('layerCompression'), charIDToTypeID('Encd'), stringIDToTypeID('RLE'));
desc.putObject(charIDToTypeID('As '), charIDToTypeID('TIFF'), descOptions);
desc.putPath(charIDToTypeID('In '), new File(data.path + "/" + data.name + ".tif"));
executeAction(charIDToTypeID('save'), desc, DialogModes.NO);
},
};
// this will get colors from the source document
var getSamplersData = function(coordinates)
{
var colors = [];
var color, sampler;
// makes sure the doc is in rgb
Utils.docToRgb();
// for all coordinates..
for (var i = 0; i < coordinates.length; i++)
{
// create a rectangular selection of 14x14 pixels in the coordinate
Utils.rectangleSelection(coordinates[i]);
// average blur it to make sure color sampler samples an average color from noisy square because there's no option for color sample size for Color Samplers
activeDocument.activeLayer.applyAverage();
activeDocument.selection.deselect();
// ads a color sample
sampler = Utils.addSample(coordinates[i]);
// reads a color sample
color = Utils.readSample(sampler);
// color is added to [colors]
colors.push(color);
Utils.deleteSample(sampler);
}
return colors;
};
// creates gradient maps for new documents
var setSamplerData = function()
{
var workFolder;
var controller = function(originalColors)
{
var docs, doc, docSampler, sampledColors, gradientColors;
try
{
docs = getDocs(); // asks for a folder to work with
}
catch (e)
{
return false;
}
// for all found documents...
for (var i = 0; i < docs.length; i++)
{
try
{
// opening it and makes sure it's in rgb mode
doc = openDocument(docs[i]);
}
catch (e)
{
return false;
}
// getting current colors in the color boxes
sampledColors = getSamplersData(targetCoords);
// create an array of color for a gradient map using current colors positions and original colors
gradientColors = createGradientDataFromColors(originalColors, sampledColors);
// creates a gradient map
createGradient(gradientColors);
// saves a file
Utils.saveTIF(
{
path: workFolder + "/export",
name: activeDocument.name
});
}
};
/////////////////////////////////////////////////////////////////////////////////////
// this will as for a folder and will return found docs
var getDocs = function()
{
var docs;
workFolder = Folder.selectDialog();
if (workFolder == null) throw 'cancelled';
docs = workFolder.getFiles('*');
for (var i = docs.length - 1; i >= 0; i--)
{
if (docs[i] instanceof Folder) docs.splice(i, 1);
}
if (docs.length == 0) throw 'no files in the folder';
return docs;
}; // end of getDocs()
// opens a doc and makes sure it's in rgb color mode
var openDocument = function(path)
{
var doc;
try
{
doc = app.open(new File(path));
Utils.docToRgb();
return doc;
}
catch (e)
{
alert("can't open " + path + "\nAborting");
throw e;
}
};
// this will create a gradient map
var createGradientDataFromColors = function(original, sampled)
{
var colors = [];
var rgbOriginal, rgbSampled, positionSampled;
for (var i = 0; i < original.length; i++)
{
rgbOriginal = getRGB(original[i]); // get an array of [r,g,b] from SolidColor object
rgbSampled = getRGB(sampled[i]); // get an array of [r,g,b] from SolidColor object
positionSampled = Math.round(Utils.rgb2yuv(rgbSampled)[0] * 10000) / 100; // getting positions from the current document colors
colors.push(
{
color: rgbOriginal,
pos: positionSampled
});
}
return colors;
}; // end of createGradientDataFromColors()
// this will convert an rgb from Solid Color to an array of [r, g and b]
var getRGB = function(color)
{
return [color.rgb.red, color.rgb.green, color.rgb.blue];
}; // end of getRGB()
// creates a gradient map
// colors are from the original doc, positions are from the target docs
var createGradient = function(data)
{
var descGradMap = new ActionDescriptor();
var referenceMap = new ActionReference();
referenceMap.putClass(charIDToTypeID('AdjL'));
descGradMap.putReference(charIDToTypeID('null'), referenceMap);
var desc5 = new ActionDescriptor();
var desc6 = new ActionDescriptor();
var desc7 = new ActionDescriptor();
desc7.putEnumerated(charIDToTypeID('GrdF'), charIDToTypeID('GrdF'), charIDToTypeID('CstS'));
desc7.putDouble(charIDToTypeID('Intr'), 4096.000000);
var list1 = new ActionList();
var el;
for (var i = 0; i < data.length; i++)
{
el = data[i];
var descTemp = new ActionDescriptor();
var descColor = new ActionDescriptor();
descColor.putDouble(charIDToTypeID('Rd '), el.color[0]);
descColor.putDouble(charIDToTypeID('Grn '), el.color[1]);
descColor.putDouble(charIDToTypeID('Bl '), el.color[2]);
descTemp.putObject(charIDToTypeID('Clr '), charIDToTypeID('RGBC'), descColor);
descTemp.putEnumerated(charIDToTypeID('Type'), charIDToTypeID('Clry'), charIDToTypeID('UsrS'));
descTemp.putInteger(charIDToTypeID('Lctn'), Utils.linear(el.pos, 0, 100, 0, 4096));
descTemp.putInteger(charIDToTypeID('Mdpn'), 50);
list1.putObject(charIDToTypeID('Clrt'), descTemp);
}
desc7.putList(charIDToTypeID('Clrs'), list1);
var list2 = new ActionList();
var desc12 = new ActionDescriptor();
desc12.putUnitDouble(charIDToTypeID('Opct'), charIDToTypeID('#Prc'), 100.000000);
desc12.putInteger(charIDToTypeID('Lctn'), 0);
desc12.putInteger(charIDToTypeID('Mdpn'), 50);
list2.putObject(charIDToTypeID('TrnS'), desc12);
var desc13 = new ActionDescriptor();
desc13.putUnitDouble(charIDToTypeID('Opct'), charIDToTypeID('#Prc'), 100.000000);
desc13.putInteger(charIDToTypeID('Lctn'), 4096);
desc13.putInteger(charIDToTypeID('Mdpn'), 50);
list2.putObject(charIDToTypeID('TrnS'), desc13);
desc7.putList(charIDToTypeID('Trns'), list2);
desc6.putObject(charIDToTypeID('Grad'), charIDToTypeID('Grdn'), desc7);
desc5.putObject(charIDToTypeID('Type'), charIDToTypeID('GdMp'), desc6);
descGradMap.putObject(charIDToTypeID('Usng'), charIDToTypeID('AdjL'), desc5);
executeAction(charIDToTypeID('Mk '), descGradMap, DialogModes.NO);
};
return controller;
};
sampledColors = getSamplersData(sourceCoords);
sampler = setSamplerData();
sampler(sampledColors);
推荐阅读
- javascript - 方法在单元测试中不可用
- r - 在 R 中使用 grepl() 匹配一个句子中的两个连续单词(或:如何在 grepl() 中使用通配符)?
- android - 找不到 com.android.tools.build:gradle:3.0.1。来自 Github 的项目
- r - 我无法在 ggplot 中用 x 轴中的因子变量和 y 轴中的数字绘制一条线
- python - 对 np.array 进行切片时,np.nonzero 的功能是什么?
- java - 带有 RequestBody 的 POST 请求不起作用
- asp.net - 为主页使用不同的标题
- python - 为什么此 Visual Studio 代码会引发 SyntaxError?
- sql - SSMS 脚本选项
- javascript - 小于 200 万的所有素数的总和