Closed vnkapoor closed 3 years ago
Hi @vnkapoor,
You can use eg. $image->colourspace('b-w')
to convert an image to black and white.
For more complex colour gradients, convert to black and white, then map through a LUT containing your gradient. For example:
#!/usr/bin/env php
<?php
require __DIR__ . '/vendor/autoload.php';
use Jcupitt\Vips;
// make a lut which is a smooth gradient from start colour to stop colour,
// with start and stop in CIELAB
function gradient($start, $stop)
{
$lut = Vips\Image::identity()->divide(255);
// lut * stop + (1 - lut) * start
$lut = $lut->multiply($stop)
->add($lut->multiply(-1)->add(1)->multiply($start));
$lut = $lut->colourspace('srgb', ['source_space' => 'lab']);
return $lut;
}
// various colours as CIELAB triples
$black = [0, 0, 0];
$red = [53, 80, 67];
$green = [88, -86, 83];
$blue = [32, 79, -108];
$white = [100, 0, 0];
$sepia = [32, 16, 35];
$image = Vips\Image::newFromFile($argv[1]);
$image = $image->colourspace("b-w")->maplut(gradient($sepia, $white));
$image->writeToFile($argv[2]);
Running:
$ ./tint.php ~/pics/Gugg_coloured.jpg x.jpg
Turns this:
Into this:
conv
runs a convolution on an image. You can use it to implement effects like sharpen, blur, emboss, etc.
@jcupitt Thank you for quick reply. I tried your above code for sepia effect.
VIPS Sepia Filter
Imagick Sepia Filter
But i want to same sepia effect on my image like it's in Imagick image. I need to change in CIELAB triples for that?
Maybe $sepia = [0, 5, 50];
? You'd need to experiment.
Okay, got it. One more thing just need to confirm $sepia = [0, 5, 50], What are 0, 5, 50 values are for is it a rgb? So can i get better idea for other effects.
They are CIELAB coordinates. L is black to white 0 to 100, A is red to green -100 to +100, and B is blue to yellow -100 to +100.
Okay, and can i manage brightness, contrast, saturation, hueRotation etc by using the above code which you provided or any other method for that?
Brightness, saturation and hue could be implemented as a modulate operation. It involves a combination of converting an image to the LCH colorspace via vips_colourspace
and through a linear transform via vips_linear
.
For example:
#!/usr/bin/env php
<?php
require __DIR__ . '/vendor/autoload.php';
use Jcupitt\Vips\Image;
use Jcupitt\Vips\Interpretation;
function greyscale(Image $image): Image
{
return $image->colourspace(Interpretation::B_W);
}
function sepia(Image $image): Image
{
$sepia = Image::newFromArray([
[0.3588, 0.7044, 0.1368],
[0.2990, 0.5870, 0.1140],
[0.2392, 0.4696, 0.0912]
]);
if ($image->hasAlpha()) {
// Separate alpha channel
$imageWithoutAlpha = $image->extract_band(0, ['n' => $image->bands - 1]);
$alpha = $image->extract_band($image->bands - 1, ['n' => 1]);
return $imageWithoutAlpha->recomb($sepia)->bandjoin($alpha);
}
return $image->recomb($sepia);
}
function modulate(Image $image, float $brightness = 1.0, float $saturation = 1.0, float $hue = 0.0): Image
{
$oldInterpretation = $image->interpretation;
// Normalize hue rotation to [0, 360]
$hue %= 360;
if ($hue < 0) {
$hue = 360 + $hue;
}
// Modulate brightness, saturation and hue
if ($image->hasAlpha()) {
// Separate alpha channel
$imageWithoutAlpha = $image->extract_band(0, ['n' => $image->bands - 1]);
$alpha = $image->extract_band($image->bands - 1, ['n' => 1]);
return $imageWithoutAlpha
->colourspace(Interpretation::LCH)
->linear([$brightness, $saturation, 1.0], [0.0, 0.0, $hue])
->colourspace($oldInterpretation)
->bandjoin($alpha);
}
return $image
->colourspace(Interpretation::LCH)
->linear([$brightness, $saturation, 1.0], [0.0, 0.0, $hue])
->colourspace($oldInterpretation);
}
$image = Image::newFromFile($argv[1]);
// Sepia filter.
//$image = sepia($image);
// Convert to 8-bit greyscale; 256 shades of grey.
//$image = greyscale($image);
// Decrease brightness and saturation while also hue-rotating by 90 degrees.
$image = modulate($image, 0.5, 0.5, 90);
$image->writeToFile($argv[2]);
(I also added a hard-coded matrix that seems to work for a sepia-like effect)
@kleisauke
I tried your sepia effect function, it works fine for me but it's not perfect as i want. Here below i add my sepia array which i am using for my imagick -color-matrix
command it's using 5*4
matrix, how can i manage below array in above sepia function?
`array( "matrix" => array(0.393, 0.769, 0.189, 0, 0, 0.349, 0.686, 0.168, 0, 0, 0.272, 0.534, 0.131, 0, 0, 0, 0, 0, 1, 0)),
That seems to be the equivalent of CSS's filter: sepia(1)
function. It can be achieved with this matrix:
$sepia = Image::newFromArray([
[0.393, 0.769, 0.189],
[0.349, 0.686, 0.168],
[0.272, 0.534, 0.131]
]);
There is also an online playground available for JavaScript (which has a similar API as the PHP binding) if you want to experiment with this: http://kleisauke.github.io/wasm-vips/playground/#thumbnail-smartcrop-sepia
Okay, Got it. @jcupitt @kleisauke Thank you for the help! and support.
Here's another way of doing contrast adjustment:
#!/usr/bin/env php
<?php
require __DIR__ . '/vendor/autoload.php';
use Jcupitt\Vips;
// make a tone map LUT ... pull shadows down, push highlights up
// there are lots of other params, see the docs
$tone = Vips\Image::tonelut(['S' => -10, 'H' => +10]);
$image = Vips\Image::newFromFile($argv[1], ['access' => 'sequential']);
// just map L of CIELAB so we change lightness but don't boost saturation
// use LABS: LAB encoded as signed short
$lab = $image->colourspace('labs');
$lab[0] = $lab[0]->maplut($tone);
$image = $lab->cast('short')->colourspace('srgb');
$image->writeToFile($argv[2]);
This make an S-shaped curve and maps just L (lightness) through it. This lets you boost contrast without flattening highlights or squashing shadows.
@jcupitt @kleisauke Thank you for your quick support. The sepia effect is working perfectly in my code. But i have some another effects like vintage, kodachrome, Technicolor, polaroid, brownie etc.
But o/p of my image is different with compare to imagick. Here i add my code for Technicolor effects.
function technicolor($image) {
$technicolor = Vips\Image::newFromArray([
[1.91252, -0.85453, -0.09155],
[0.00018133333333333334, -0.30878, 1.76589],
[-0.10601, -0.0010819215686274511, -0.2311]
]);
if ($image->hasAlpha()) {
// Separate alpha channel
$imageWithoutAlpha = $image->extract_band(0, ['n' => $image->bands - 1]);
$alpha = $image->extract_band($image->bands - 1, ['n' => 1]);
return $imageWithoutAlpha->recomb($technicolor)->bandjoin($alpha);
}
return $image->recomb($technicolor);
}
//Below is the actual imgick matrix for technicolor
array(1.91252, -0.85453, -0.09155, 0, 0.00018133333333333334, -0.30878, 1.76589, -0.10601, 0, -0.0010819215686274511, -0.2311, -0.75018, 1.84759, 0, 0.0004759607843137255, 0, 0, 0, 1, 0)),
How can i achieve same Imagick matrix in vips?
When i am trying to below example it gives me error
$technicolor = Vips\Image::newFromArray([
[1.91252, -0.85453, -0.09155, 0, 0.00018133333333333334],
[0.00018133333333333334, -0.30878, 1.76589],
[-0.10601, -0.0010819215686274511, -0.2311]
]);
You have five numbers in the first row of your matrix, not three.
@jcupitt I tried below matrix but it gives me this error recomb: bands in must equal matrix width
$technicolor = Vips\Image::newFromArray([
[1.91252, -0.85453, -0.09155, 0, 0.00018133333333333334],
[-0.30878, 1.76589, -0.10601],
[0, -0.0010819215686274511, 0],
[-0.2311, -0.75018, 1.84759],
[0, 0.0004759607843137255, 0],
[0, 1, 0]
]);
Yes, it needs to be a 3x3 matrix.
@jcupitt Okay, is there any way to achieve same technicolor effect like imagick vips. Because by using 3 * 3 matrix the output image is differ from imagick
You'll need to read the imagick code and reimplement it in libvips.
@jcupitt I achieved this (vintage, kodachrome, Technicolor, polaroid, brownie) effects using vips. Below i add my matrix for anyone who need it.
$brownie = Vips\Image::newFromArray([
[0.59970, 0.34553, -0.27082],
[-0.03770, 0.86095, 0.15059],
[0.24113, -0.07441, 0.44972]
]);
$vintage = Vips\Image::newFromArray([
[0.62793, 0.32021, -0.03965],
[0.02578, 0.64411, 0.03259],
[0.0466, -0.08512, 0.52416]
]);
$kodachrome = Vips\Image::newFromArray([
[1.12855, -0.39673, -0.03992],
[-0.16404, 1.08352, -0.05498],
[-0.16786, -0.56034, 1.60148]
]);
$technicolor = Vips\Image::newFromArray([
[1.91252, -0.85453, -0.09155],
[-0.30878, 1.76589, -0.10601],
[-0.2311, -0.75018, 1.84759]
]);
$polaroid = Vips\Image::newFromArray([
[1.438, -0.062, -0.062],
[-0.122, 1.378, -0.122],
[-0.016, -0.016, 1.483]
]);
Oh hey, that's great! Thank you for sharing, @vnkapoor.
Hello @jcupitt
I want to add sepia, black & white, vintage etc.. effect on my image. Is there any method for apply this filters on my image. I am trying it by using
conv
method is that method is for apply filters?