Closed JuanLuisGarciaBorrego closed 1 year ago
Hi @JuanLuisGarciaBorrego,
Have you seen?
https://libvips.github.io/php-vips/classes/Jcupitt-Vips-Image.html
You can write stuff like:
$image = Vips\Image::tiffload($pathFileTif, ["access" => "sequential"]);
// add 128 to the K band
$image = $image->add([0, 0, 0, 128]);
$image->writeToFile("x.tif");
You should be able to do anything you need, and no looping. It'll stream the image through your system and won't load the whole thing.
Thanks @jcupitt for the help!
Is there a way to make a callback that receives the original pixels and returns the changed pixels? Something like that:
$image = Vips\Image::tiffload($pathFileTif, ["access" => "sequential"]);
$myCustomFilter = function($originalPixel) {
//apply pixel operations
return $updatePixel;
}
$image = $image->update(myCustomFilter);
$image->writeToFile("x.tif");
I have observed that Image::add() calls a callable method but I can't get the original pixel....
Any ideas? Thanks John!!
You can't really do pixel-by-pixel processing in PHP -- it's much too slow.
php-vips has a pretty complete set of operations, so you should be able to achieve the effect you want by just stringing them together. What value do you want to compute?
You can also use C or C++ to add operations to libvips then call them from PHP, if that's any help.
thanks @jcupitt
I just imagined it wasn't possible from PHP. I need to apply certain formulas that alter the cmyk/rgb. It would be something like the Image::add method
I'm going to go over C and try to create a method like the one mentioned above and then call it from PHP. It
Could you briefly tell me the steps to follow?
Image::alterPixel
similar to Image:add()
Would this be feasible John? Thanks!
libvips supports plugins, there's an example here:
https://github.com/jcupitt/vips-gmic
You don't need to change the php binding, it'll appear automatically.
But you almost certainly don't need to do this. libvips has a complete set of arithmetic operations, so any pixel manipulation code you could write in php, you can implement using ->add()
etc. If you tell me roughly what you want to implement I could show you how to do it in php-vips.
Pixel manipulation done with a chained sequence of ->add()
, ->shift()
etc. is around half the speed of hand coded C, but libvips can parallelise it automatically, so as long as you have more than one core available, it should usually be as fast or faster. And you'll save yourself weeks of annoying work and then years of even more annoying maintenance.
The code I need to do for each pixel is similar to (conditions according to the pixel value, sum between value ):
$pixel = $image->getpoint($x, $y);
$c= $pixel[0] ;
$m = $pixel[1];
$y = $pixel[2];
$k = $pixel[3];
if($m === 0) {
$m = 50;
}
if($y + $k > 100) {
$y = 0;
}
return [$c,$m, $y, $k];
Do you think it will be possible to do it with the functions mentioned in the previous comment ->add()
->chift()
?
Sure, try:
#!/usr/bin/php
<?php
require __DIR__ . '/vendor/autoload.php';
use Jcupitt\Vips;
$image = Vips\Image::newFromFile($argv[1], ["access" => "sequential"]);
[$c, $m, $y, $k] = $image->bandsplit();
$m = $m->equal(0)->ifthenelse(50, $m);
$y = $y->add($k)->more(100)->ifthenelse(0, $y);
$image = $c->bandjoin([$m, $y, $k]);
$image->writeToFile($argv[2]);
With this test image:
I can run:
$ ./cmyk.php x.jpg y.jpg
To make:
WoOOuuhh!!
Thanks @jcupitt ! I'm going to try!!
Thanks!!!
I should have added some explanation:
[$c, $m, $y, $k] = $image->bandsplit();
All the $variables
here are images. bandsplit
is splitting the four channel CMYK image up into four one band images, then we use php array destructuring to get those into four variables.
$y = $y->add($k)->more(100)->ifthenelse(0, $y);
It's a shame php doesn't have operator overloading, it would make this much easier to read. You can imagine this as:
$y = (($y + $k) > 100)->ifthenelse(0, $y);
The relational operators (eg. >
here) make a bool image (an 8-bit image with 0 for false and 255 for true). The if-then-else is $condition_image->ifthenelse($true_image, $false_image)
. For each pixel, it'll test the condition for != 0
and pick the corresponding pixel from the then side or the else side.
The docs I linked explain this, and some other stuff too:
https://libvips.github.io/php-vips/classes/Jcupitt-Vips-Image.html
Thanks you very much John
I am looking at the information carefully =)
One question more..
Can I see the original value of the pixel from pointer??
In the next image I'm showing from $c
from
[$c, $m, $y, $k] = $image->bandsplit();
Thanks @jcupitt !
You can use writeToArray
to save an image to a PHP array and then print it, that might be simplest. Maybe:
#!/usr/bin/php
<?php
require __DIR__ . '/vendor/autoload.php';
use Jcupitt\Vips;
$image = Vips\Image::newFromFile($argv[1]);
// just 2x2 pixels for testing
$image = $image->crop(0, 0, 2, 2);
[$c, $m, $y, $k] = $image->bandsplit();
$m = $m->equal(0)->ifthenelse(50, $m);
$y = $y->add($k)->more(100)->ifthenelse(0, $y);
$after = $c->bandjoin([$m, $y, $k]);
echo("before:\n");
print_r($image->writeToArray());
echo("after:\n");
print_r($after->writeToArray());
These things can be annoying to debug. I usually develop complex stuff in nip2, then code up in python/ruby/php/whatever right at the end.
Hi @jcupitt !!
I have a .tiff image with CMYK color mode
$image = Vips\Image::tiffload($path, ["access" => "sequential"])
$image->colourspace(Vips\Interpretation::CMYK);
$image = $image->crop(0, 0, 2, 2);
$image->writeToArray()
The array's values are RGB, not CMYK
165,0,58,0 | 146,0,71,0 173,0,53,0 | 146,0,65,0
If I try to force the image with php $image->colourspace(Vips\Interpretation::RGB);
return the error ibvips error: vips_colourspace: no known route from 'cmyk' to RGB (I understand that error is correct)
With mode Vips\Interpretation::CMYK
should return the data in CMYK, right?
I understand that with concatenation of filter methods like ->add()
or->ifthenelse()
, etc, but I don't know how to pass code like:
[$c, $m, $y, $k] = $pixel;
if($m === 50 || $y > 50) {
return [$c, $m, $y, $k]
}
if($c>0) {
//...
return [$c, $m, $y, $k]
}
$minValueOfPixel = getMinValueFrom($c, $m, $y, $k)
$mediumValueOfPixel = getMinValueFrom($c, $m, $y, $k)
$maxValueOfPixel = getMinValueFrom($c, $m, $y, $k)
....multiples steps...
return [$c, $m, $y, $k]
I think I will try to make the plugin, could you guide me the steps to follow?
Thanks John!
php-vips doesn't have any (or almost no) operations which modify images. Everything will make a new image, and it has some tricks behind the scenes to make this quick.
Try:
$image = Vips\Image::tiffload($path, ["access" => "sequential"])
$image = $image->colourspace("cmyk");
Wait, now I read more carefully, just do:
$image = Vips\Image::tiffload($path, ["access" => "sequential"])
$image = $image->crop(0, 0, 2, 2);
$image->writeToArray();
And you'll get CMYK.
The array's values are RGB, not CMYK
No, I think those are CMYK. What image are you testing with?
With that test image I used above ^^^^ I see:
$ vips getpoint cmyk6.jpg 0 0
23 13 11 0
ie. low ink density, so a light grey (as you'd expect).
For this:
$minValueOfPixel = getMinValueFrom($c, $m, $y, $k)
You need bandrank
:
https://www.libvips.org/API/current/libvips-conversion.html#vips-bandrank
eg.:
$min = Vips\Image::bandrank([$c, $m, $y, $k], 0);
Now $min
will be a one-band image containing the mimimum of c, m, y, k at each point
I think I will try to make the plugin, could you guide me the steps to follow?
Just have a look at that gmic example. This file is the plugin source:
https://github.com/jcupitt/vips-gmic/blob/master/vips_gmic.cpp
And this is how you build it:
https://github.com/jcupitt/vips-gmic/blob/master/Makefile
But you'll need to be a pretty good C/C++ dev, and you'll need to do quite a bit of reading.
Hello and thanks you in advance!
I am trying to apply an operation to each pixel of the file .tif
How do I generate an image of the same format-dimensions but with the new pixels?
Is it possible to save the image little by little, without having to store the array of pixels in memory?
Thanks