Closed axkirillov closed 1 year ago
Figured it out, I was using ::sum incorrectly
the correct usage is as static function:
$sum = Vips\Image::sum([$r, $g, $b]);
Hi @axkirillov,
You could also write this as (untested):
$brightness = 0.7;
$image = Vips\Image::newFromFile("xxx");
// scrgb is linear 0-1 pixels, bandmean makes a one-band image by averaging bandwise
$factor = $image->colourspace("scrgb")->bandmean()->linear(-1 * $brightness, 1 + $brightness);
$image = $image * factor;
// back to standard 8 bit rgb
$image = $image->colourspace("srgb");
I'd expect working in linear space to give more pleasing results as well.
I wish php had operator overloads :(
Thank you for the advice!
The first part of your suggestion works great
$factor = $image->colourspace("scrgb")->bandmean()->linear(-1 * $brightness, 1 + $brightness);
doing this however results in a different image than expected
$image = $image->multiply($factor);
$image = $image->colourspace("srgb");
expected (brightness -1)
result
Another thing that probably stems from me not understanding colorspaces and such is that when the original image is png, the following implementation also produces not quite expected result. I'll paste the entire code here since there might be smth relevant I am missing.
$start = microtime(true);
$hasAlpha = $image->hasAlpha();
// remove alpha, if any
if ($hasAlpha) {
$alpha = $image->extract_band($image->bands - 1, ['n' => 1]);
$image = $image->extract_band(0, ['n' => $image->bands - 1]);
}
/**
* @var Vips\Image $r
* @var Vips\Image $g
* @var Vips\Image $b
* */
[$r, $g, $b] = $image->bandsplit();
$brightness = $this->brightness / 100;
// equivalent javascript
//for (let i = 0; i < length; i += 4) {
// const avg = (data[i] + data[i + 1] + data[i + 2]) / 765;
//
// const factor = 1 + (valueToUse * (1 - avg));
//
// data[i] *= factor;
// data[i + 1] *= factor;
// data[i + 2] *= factor;
//
// scrgb is linear 0-1 pixels, bandmean makes a one-band image by averaging bandwise
$factor = $image->colourspace("scrgb")->bandmean()->linear(-1 * $brightness, 1 + $brightness); //}
$r = $r->multiply($factor);
$g = $g->multiply($factor);
$b = $b->multiply($factor);
$image = $r->bandjoin([$g, $b]);
// add alpha back
if ($hasAlpha) {
$image = $image->bandjoin($alpha);
}
$blob = $image->writeToBuffer($hasAlpha ? '.png' : '.jpg');
$imagick = new \Imagick();
$imagick->readImageBlob($blob);
Prior to this the image is simply loaded like this:
Vips\Image::newFromBuffer($this->getRawContent($url));
expected (brightness is 1)
result
doing this however results in a different image than expected
Yes, it'll look a bit different.
sRGB images have a gamma, meaning that numeric values in the file have a power law relationship with brightness (usually 2.2). Converting to scrgb
(note the c
) makes an image with pixels in 0-1 and a linear relationship with light. Lightness adjustments made in the space should look more natural (ie. better).
If you prefer the gamma look, you can just do:
$image = $image->divide(255);
instead.
You don't need to bandsplit and bandjoin. You can just do:
$image = $image->linear([1, 2, 3], [4, 5, 6]);
To scale each band by a different amount (if that's what you want to do).
So just write:
$brightness = $this->brightness / 100;
// equivalent javascript
//for (let i = 0; i < length; i += 4) {
// const avg = (data[i] + data[i + 1] + data[i + 2]) / 765;
//
// const factor = 1 + (valueToUse * (1 - avg));
//
// data[i] *= factor;
// data[i + 1] *= factor;
// data[i + 2] *= factor;
//
// scrgb is linear 0-1 pixels, bandmean makes a one-band image by averaging bandwise
$factor = $image->colourspace("scrgb")->bandmean()->linear(-1 * $brightness, 1 + $brightness);
$image = $image->multiply($factor);
Thank you for the suggestions!
Indeed, divide(255)
works as expected for both png and jpg
$image = $image->multiply($factor);
also works, I might have confused the two problems at first.
Hi!
I am trying to implement the following javascript algorithm in php-vips. It seems to me that the calculations are identical. But the result differs. Here is the javascript
here is the php-vips version
Result fot -1 brightness: js php-vips