gpt4 book ai didi

imagemagick - 在 ImageMagick 中复制 Photoshop 的 "Color"混合模式

转载 作者:行者123 更新时间:2023-12-05 01:23:17 28 4
gpt4 key购买 nike

我需要在 ImageMagick 中创建一个模仿 Adob​​e Photoshop 的“颜色”混合模式的命令,以便为图像着色。为了做到这一点,我试图合成原始图像和另一个由全彩色层组成的图像,不透明度为 35%。这应该与原始图像融合并创建彩色结果图像。

这是预期的结果:
the expected result

Adobe 网站上正在定义“颜色”混合模式,如下所示:“使用基色的亮度以及混合色的色调和饱和度创建结果颜色。这会保留图像中的灰度级,并且可用于为单色图像着色和为彩色图像着色。”

ImageMagick 中定义了一个 compose 方法,它似乎做同样的事情(Luminize),但结果远非预期的那样。

在 Imagemagick 中提供最接近结果的似乎是默认的混合 compose 方法,使用如下:

convert image.jpg color_layer.png -compose blend -composite result.jpg

我还尝试使用 -fx 运算符创建一个包含第一张图像的亮度和第二张图像的色相和饱和度的图像,但结果仍然远不及我所需要的。

最佳答案

基于 CaSTLes 有值(value)的答案,我试图找到在 PHP 中执行此操作的最佳解决方案。他引用的实现有两个主要缺陷:一个是它没有考虑不透明度(如果有的话),第二个是非常缓慢且耗费资源。在 PHP 中处理 500x500 像素的图像大约需要 15 秒,其中 Apache 将保持处理器高达 95%。

我发现最快和最少的资源消耗实际上是在 HTML5 中使用 Canvas 处理图像。结果令人惊叹,图像正在现场处理。

我将在最后的代码块下方发布,一个用于 PHP,一个用于 HTML。如果您需要使用此服务器端,您可以将 HTML 代码复制粘贴到 Node.js 和 NodeCanvas 中:https://github.com/LearnBoost/node-canvas

PHP(不透明):

<?php

function Lum($colour) {
return ($colour['r'] * 0.3) + ($colour['g'] * 0.59) + ($colour['b'] * 0.11);
}

function ClipColour($colour) {
$result = $colour;
$luminance = Lum($colour);

$cMin = min($colour['r'], $colour['g'], $colour['b']);
$cMax = max($colour['r'], $colour['g'], $colour['b']);

if ($cMin < 0.0) {
$result['r'] = $luminance + ((($colour['r'] - $luminance) * $luminance) / ($luminance - $cMin));
$result['g'] = $luminance + ((($colour['g'] - $luminance) * $luminance) / ($luminance - $cMin));
$result['b'] = $luminance + ((($colour['b'] - $luminance) * $luminance) / ($luminance - $cMin));
}

if ($cMax > 255) {
$result['r'] = $luminance + ((($colour['r'] - $luminance) * (255 - $luminance)) / ($cMax - $luminance));
$result['g'] = $luminance + ((($colour['g'] - $luminance) * (255 - $luminance)) / ($cMax - $luminance));
$result['b'] = $luminance + ((($colour['b'] - $luminance) * (255 - $luminance)) / ($cMax - $luminance));
}

return $result;
}

function SetLum($colour, $luminance) {

$result = array();

$diff = $luminance - Lum($colour);

$result['r'] = $colour['r'] + $diff;
$result['g'] = $colour['g'] + $diff;
$result['b'] = $colour['b'] + $diff;

return ClipColour($result);

}

function normalizeColor( $color ) {
$color['r'] = $color['r'] / 255;
$color['g'] = $color['g'] / 255;
$color['b'] = $color['b'] / 255;

return $color;
}

function denormalizeColor( $color ) {
$color['r'] = round($color['r'] * 255);
$color['g'] = round($color['g'] * 255);
$color['b'] = round($color['b'] * 255);

return $color;
}

$overlay_color = array('r'=>180,'g'=>22,'b'=>1, 'a' => 0.35);

$img = new Imagick();

if( !isset($_GET['case']) ) {
$_GET['case'] = '';
}

//unmodified version
$original = new Imagick('girl.jpg');

//photoshop image to compare
$ps = new Imagick('original.jpg');

$img->addImage($original);
$it = $original->getPixelIterator();

foreach( $it as $row => $pixels ) {
foreach ( $pixels as $column => $pixel ) {
$rgbIni = $pixel->getColor();

$rgb = SetLum($overlay_color, Lum($rgbIni));
$overlay_color = normalizeColor($overlay_color);
$rgb = normalizeColor($rgb);

$rgbIni = normalizeColor($rgbIni);

$rgb['r'] = ((1 - $overlay_color['a']) * $rgbIni['r']) + ($overlay_color['a'] * $rgb['r']);
$rgb['g'] = ((1 - $overlay_color['a']) * $rgbIni['g']) + ($overlay_color['a'] * $rgb['g']);
$rgb['b'] = ((1 - $overlay_color['a']) * $rgbIni['b']) + ($overlay_color['a'] * $rgb['b']);

$test = denormalizeColor($test);
$rgb = denormalizeColor($rgb);
$overlay_color = denormalizeColor($overlay_color);

$pixel->setColor('rgb('.round($rgb['r']).','. round($rgb['g']).','.round($rgb['b']).')');

}

$it->syncIterator();
}

//add modified version
$img->addImage($original);
$img->addImage($ps);

$img->resetIterator();
$combined = $img->appendImages(true); //stack images

header('content-type: image/jpeg');

$combined->setImageFormat("jpeg");

echo $combined;

?>

HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<script>
var RGBA = function(r, g, b, a) {
this.R = r || 0;
this.G = g || 0;
this.B = b || 0;
this.A = a || 0.5;
}

function SetLum(initialColor, pixelColor) {

var initalColorLuminance = initialColor.R * 0.3 + initialColor.G * 0.59 + initialColor.B * 0.11;
var pixelColorLuminance = pixelColor.R * 0.3 + pixelColor.G * 0.59 + pixelColor.B * 0.11;

var diff = pixelColorLuminance - initalColorLuminance;

var response = new Array;
response[0] = initialColor.R + diff;
response[1] = initialColor.G + diff;
response[2] = initialColor.B + diff;

//console.log(response[0]);

return ClipColour(response);

}

function alphaComposite(mv, ov, a) {
return (mv * a) + (ov * (1 - a));
}

function ClipColour(color) { //function to prevent underexposure or overexposure on some pixels

var result = color;
var luminance = color[0] * 0.3 + color[1] * 0.59 + color[1] * 0.11;

var cMin = Math.min(color[0], color[1], color[2]);
var cMax = Math.max(color[0], color[1], color[2]);

if (cMin < 0.0) {
color[0] = luminance + (((color[0] - luminance) * luminance) / (luminance - cMin));
color[1] = luminance + (((color[1] - luminance) * luminance) / (luminance - cMin));
color[2] = luminance + (((color[2] - luminance) * luminance) / (luminance - cMin));
}

if (cMax > 255) {
color[0] = luminance + (((color[0] - luminance) * (255 - luminance)) / (cMax - luminance));
color[1] = luminance + (((color[1] - luminance) * (255 - luminance)) / (cMax - luminance));
color[2] = luminance + (((color[2] - luminance) * (255 - luminance)) / (cMax - luminance));
}

return color;
}

function processImage(image, targetColour) {
var canvas = document.createElement('canvas');
c = canvas.getContext('2d');

canvas.width = image.width;
canvas.height = image.height;

// Draw the building on the original canvas
c.drawImage(image, 0, 0, canvas.width, canvas.height);

// There's a (much) faster way to cycle through all the pixels using typed arrays,
// but I'm playing it safe so that the example works in all browsers.
var imageData = c.getImageData(0, 0, canvas.width, canvas.height),
imageDataPixels = imageData.data;

for (var i = 0, len = imageDataPixels.length; i < len; i += 4) {
var pixelColor = new RGBA(imageDataPixels[i], imageDataPixels[i+1], imageDataPixels[i+2], 1);
var test = SetLum(targetColour, pixelColor);

var r = Math.round(test[0]);
var g = Math.round(test[1]);
var b = Math.round(test[2]);

imageDataPixels[i] = alphaComposite(r, imageDataPixels[i], targetColour.A);
imageDataPixels[i + 1] = alphaComposite(g, imageDataPixels[i + 1], targetColour.A);
imageDataPixels[i + 2] = alphaComposite(b, imageDataPixels[i + 2], targetColour.A);
}

c.putImageData(imageData, 0, 0);

return canvas;
}

document.addEventListener('DOMContentLoaded', function() {
var image = new Image(),
processImageFile = null;

image.src = "girl.jpg";

image.addEventListener('load', function() {
var canvas = document.getElementById('canvas'),
c = canvas.getContext('2d'),
imageRGBA = new RGBA(180, 22, 1, 0.35);

canvas.width = image.width;
canvas.height = image.height;

c.drawImage(image, 0, 0);

processImageFile = processImage(image, imageRGBA);
c.drawImage(processImageFile, 0, 0);
});
});
</script>
</head>
<body>

<img src="girl.jpg" />
<br />

<canvas id="canvas"></canvas>

<br />
<img src="original.jpg" />
</body>

关于imagemagick - 在 ImageMagick 中复制 Photoshop 的 "Color"混合模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11973086/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com