PHP - JPEG Image to RGB value Array - php

I am wanting to get an array of RGB values from an image. E.g. (2 X 2 pix example.)
[[[R, G, B], [R, G, B]], [[R, G, B], [R, G, B]]]
The code I have now:
<?php
// open an image
$image = imagecreatefromjpeg('image.jpg'); // imagecreatefromjpeg/png/
// get image dimension, define colour array
$width = imagesx($image);
$height = imagesy($image);
$colors = [];
for ($y = 0; $y < $height; $y++)
{
for ($x = 0; $x < $width; $x++)
{
$rgb = imagecolorat($image, $x, $y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
}
}
print_r($colors);
?>
The above is not working.
My image is now just a 2 X 2 pix jpeg which should output:
[[[0, 255, 0], [255, 0, 0]], [[0, 0, 255], [255, 255, 255]]]
Any help greatly appreciated!

OK, nailed it. Thanks to all.
<?php
$image = imagecreatefromjpeg('image.jpg'); // imagecreatefromjpeg/png/
$width = imagesx($image);
$height = imagesy($image);
$colors = array();
for ($y = 0; $y < $height; $y++) {
$y_array = array() ;
for ($x = 0; $x < $width; $x++) {
$rgb = imagecolorat($image, $x, $y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
$x_array = array($r, $g, $b) ;
$y_array[] = $x_array ;
}
$colors[] = $y_array ;
}
print_r($colors);
?>
Comments correct, added $r, $g, $b. Restructured #jari answer and now getting a good output.
Cheers!

function getArrayOfPixelsFromFile($source) {
$image = imagecreatefromjpeg($source); // imagecreatefromjpeg/png/
$width = imagesx($image);
$height = imagesy($image);
$colors = array();
for ($y = 0; $y < $height; $y++) {
$y_array = array();
for ($x = 0; $x < $width; $x++) {
//Seleciona a cor localizada em ($x, $y)
$rgb = imagecolorat($image, $x, $y);
//echo $rgb." = ".decbin($rgb),"<br>";
//Seleciona os primeiros dois bytes que representam vermelho
$r = ($rgb >> 16) & 0xFF;
//Seleciona os dois bytes do meio que representam o verde
$g = ($rgb >> 8) & 0xFF;
//Seleciona os dois últimos bytes que representam o azul
$b = $rgb & 0xFF;
$x_array = array($r, $g, $b);
$y_array[] = $x_array;
}
$colors[] = $y_array;
}
return $colors;
}

I fixed your code by creating subarrays and adding elements to it as it should be.
for ($y = 0; $y < $height; $y++)
{
$height_arr = array() ;
for ($x = 0; $x < $width; $x++)
{
$rgb = imagecolorat($image, $x, $y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
$width_arr = array($r, $g, $b) ;
$height_array[] = $width_arr ;
}
$colors[] = $height_arr ;
}

How about this?
[...]
$colors = [];
for ($y = 0; $y < $height; $y++) {
for ($x = 0; $x < $width; $x++) {
$rgb = imagecolorat($image, $x, $y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
$colors[$y][$x] = array($r,$g,$b); // or, $colors[$x][$y] = array($r,$g,$b);
}
}
print_r($colors);

Related

PHP keeps skipping to 144, but when echoed, is correct value

I'm currently trying to get all pixel data inside of an image, and return it in JSON after encoding an Array. However, when I try to insert the $y data into the array, it always inserts 144. No in-between, always 144. When I echo $y, however, I get "0, 1, 2, etc."
$x, $r, $g, and $b are correct.
Any ideas? Here's my code:
<?php
header('Content-Type: application/json');
class PixelData {
private $ar = array(
"pixeldata" => [
]
);
public function getPixel($x, $y, $im) {
echo $y; // echoes "0, 1, 2, 3, etc."
global $ar;
$ar["pixeldata"][$x]["x"] = $x;
$ar["pixeldata"][$x]["y"] = $y;
$rgb = imagecolorat($im, $x, $y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
$ar["pixeldata"][$x]["r"] = $r;
$ar["pixeldata"][$x]["g"] = $g;
$ar["pixeldata"][$x]["b"] = $b;
}
}
$src = "D:\Pictures\Test.png";
$im = imagecreatefrompng($src);
$size = getimagesize($src);
$width = imagesx($im);
$height = imagesy($im);
for($x = 0; $x < $width; $x++)
{
for($y = 0; $y < $height; $y++)
{
$pd = new PixelData();
$pd->getPixel($x, $y, $im);
}
}
$js = json_encode($ar);
echo $js;
?>
To elaborate further on my comment:
Your array is basically one-dimensional, because the only variable aspect is $ar['pixeldata'][$x]; you're never adding $y as another dimension. So, every time you increment $y in the inner-most for loop to go to the next level of $height you're overwriting the previous $x values. Basically, by the time your script is done, pixeldata will only contain the data of the top-most row of pixels, therefore they're always 144.
I also didn't notice until now, but if you wanted to store the data within the PixelData private array, you can't create a new instance within the for loops, you'd need to do that outside of the for loops.
This is probably what you want. As you can see, I've added an extra dimension to you pixeldata array, so as to include both $x and $y dimensions.
<?php
header('Content-Type: application/json');
class PixelData {
private $ar = array(
"pixeldata" => [
]
);
public function getPixel($x, $y, $im) {
echo $y; // echoes "0, 1, 2, 3, etc."
// Instantiate an array for this pixel
$this->ar["pixeldata"][$x][$y] = [];
$this->ar["pixeldata"][$x][$y]["x"] = $x;
$this->ar["pixeldata"][$x][$y]["y"] = $y;
$rgb = imagecolorat($im, $x, $y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
$this->ar["pixeldata"][$x][$y]["r"] = $r;
$this->ar["pixeldata"][$x][$y]["g"] = $g;
$this->ar["pixeldata"][$x][$y]["b"] = $b;
}
public function getAr() {
return $this->ar;
}
}
$src = "D:\Pictures\Test.png";
$im = imagecreatefrompng($src);
$size = getimagesize($src);
$width = imagesx($im);
$height = imagesy($im);
$pd = new PixelData();
for($x = 0; $x < $width; $x++)
{
for($y = 0; $y < $height; $y++)
{
$pd->getPixel($x, $y, $im);
}
}
$js = json_encode($pd->getAr());
echo $js;
?>

What is wrong with my bilinear interpolation algorithm?

I am using PHP to test out my bilinear algorithm. The code is un-optimized for clarity.
Here is what the code below is doing:
Plot the original pixels from the 2x2 image to the 10x10 destination
image. These will leave blank pixels.
Note: The images here are resized from 10x10 to 100x100 for better viewing.
Interpolate the row of pixels.
Interpolate the remaining pixels going from left to right, top to bottom using the row of pixels in step 2:
However, it does not match the result I get in Photoshop using bilinear resampling:
Full source code:
<?php
$image1 = imagecreatefrompng( 'test.png' );
$w1 = imagesx( $image1 );
$h1 = imagesy( $image1 );
$w2 = 10;
$h2 = 10;
$image2 = imagecreatetruecolor( $w2, $h2 );
imagefill($image2, 0, 0, imagecolorallocate($image2, 0x4c, 0x4c, 0x8e)); // added bg for pixels to stand-out
function lerp($v0, $v1, $t) {
return $v0 + $t*($v1-$v0);
}
function getPixel($image, $x, $y){
$rgb = imagecolorat( $image, $x, $y );
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
return array($r,$g,$b);
}
$maxY1 = $h1 - 1;
$maxX1 = $w1 - 1;
$maxY2 = $h2 - 1;
$maxX2 = $w2 - 1;
// plot original pixels from source to destination
for($y = 0; $y <= $maxY1; $y++) { // loop thru src height
$newY = floor(($y/$maxY1) * $maxY2);
for ($x = 0; $x <= $maxX1; $x++) { // loop thru src width
$newX = floor(($x/$maxX1) * $maxX2);
$rgb = imagecolorat( $image1, $x, $y );
$r1 = ($rgb >> 16) & 0xFF;
$g1 = ($rgb >> 8) & 0xFF;
$b1 = $rgb & 0xFF;
imagesetpixel( $image2, $newX, $newY, imagecolorallocate( $image2, $r1, $g1, $b1 ) );
}
}
imagepng( $image2, 'out1.png' );
// interpolate pixels from pixel[1,0] to pixel[8,0]
$y = 0;
$rgb = imagecolorat( $image2, 0, $y );
$r0 = ($rgb >> 16) & 0xFF;
$g0 = ($rgb >> 8) & 0xFF;
$b0 = $rgb & 0xFF;
$rgb = imagecolorat( $image2, 9, $y );
$r1 = ($rgb >> 16) & 0xFF;
$g1 = ($rgb >> 8) & 0xFF;
$b1 = $rgb & 0xFF;
for($x=1; $x <= 8; $x++){
$t = $x / 9;
$r = lerp($r0, $r1, $t);
$g = lerp($g0, $g1, $t);
$b = lerp($b0, $b1, $t);
imagesetpixel( $image2, $x, $y, imagecolorallocate( $image2, $r, $g, $b ) );
}
imagepng( $image2, 'out2.png' );
// interpolate pixels from pixel[1,9] to pixel[8,9]
$y = 9;
$rgb = imagecolorat( $image2, 0, $y );
$r0 = ($rgb >> 16) & 0xFF;
$g0 = ($rgb >> 8) & 0xFF;
$b0 = $rgb & 0xFF;
$rgb = imagecolorat( $image2, 9, $y );
$r1 = ($rgb >> 16) & 0xFF;
$g1 = ($rgb >> 8) & 0xFF;
$b1 = $rgb & 0xFF;
for($x=1; $x <= 8; $x++){
$t = $x / 9;
$r = lerp($r0, $r1, $t);
$g = lerp($g0, $g1, $t);
$b = lerp($b0, $b1, $t);
imagesetpixel( $image2, $x, $y, imagecolorallocate( $image2, $r, $g, $b ) );
}
imagepng( $image2, 'out3.png' );
// interpolate remaining pixels
for($x=0; $x <= 9; $x++){
$rgb = imagecolorat( $image2, $x, 0 );
$r0 = ($rgb >> 16) & 0xFF;
$g0 = ($rgb >> 8) & 0xFF;
$b0 = $rgb & 0xFF;
$rgb = imagecolorat( $image2, $x, 9 );
$r1 = ($rgb >> 16) & 0xFF;
$g1 = ($rgb >> 8) & 0xFF;
$b1 = $rgb & 0xFF;
for($y = 1; $y <= 8; $y++){
$t = $y / 9;
$r = lerp($r0, $r1, $t);
$g = lerp($g0, $g1, $t);
$b = lerp($b0, $b1, $t);
imagesetpixel( $image2, $x, $y, imagecolorallocate( $image2, $r, $g, $b ) );
}
}
imagepng( $image2, 'out4.png' );
header('Content-type: image/png');
imagepng( $image2);
imagedestroy( $image1 );
What am I missing?
Photoshop is correct. In your version the original 4 pixel values end up in the extreme corners of the new image but in the correct bilinear interpolation they end up in the centers of 4 quadrants of the new image. There is no information beyond the edge of the original image so photoshop does constant extrapolation at the edge:
2x2:
10x10 before interpolation:
If you started with a 3x3 image instead of 2x2, your method would cause the original edge pixels to have a diminished contribution to the final image relative to the center pixels, biasing the result.
If you look at the PS result closely, you will notice that before the interpolation corner pixels have been resized 9-fold (they take up 3x3 in the corners of the image). This is obviously done to get a more sharp edges, for better or worse.
If you add logic for generating an intermediate image before the interpolation:
...and modify your interpolation algorythm to omit the corner pixel blocks, then you should get the same result.

Change “Saturation” of an image with PHP GD Library?

There is an excellent answer on how to change the HUE of an image using PHP-GD library. But I need to know how to change the SATURATION of an image using PHP-GD. Here is a copy of the code from the answer which successfully changes the HUE of the image.
function imagehue(&$image, $angle) {
if($angle % 360 == 0) return;
$width = imagesx($image);
$height = imagesy($image);
for($x = 0; $x < $width; $x++) {
for($y = 0; $y < $height; $y++) {
$rgb = imagecolorat($image, $x, $y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
$alpha = ($rgb & 0x7F000000) >> 24;
list($h, $s, $l) = rgb2hsl($r, $g, $b);
$h += $angle / 360;
if($h > 1) $h--;
list($r, $g, $b) = hsl2rgb($h, $s, $l);
imagesetpixel($image, $x, $y, imagecolorallocatealpha($image, $r, $g, $b, $alpha));
}
}
}
If you need to take a look at the code of helper functions rgb2hsl and hsl2rgb please check the original answer. Since Hue is one of the parameters of HSL, I thought I could modify the function somehow to get a working solution for Saturation. Despite of limited php skills I had to try but it did not work and produced bizarre results. Here is the modification that I am trying.
MODIFIED CODE: UPDATED as suggested by #mark
function imageSaturation(&$image, $saturationPercentage) {
$width = imagesx($image);
$height = imagesy($image);
for($x = 0; $x < $width; $x++) {
for($y = 0; $y < $height; $y++) {
$rgb = imagecolorat($image, $x, $y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
$alpha = ($rgb & 0x7F000000) >> 24;
list($h, $s, $l) = rgb2hsl($r, $g, $b);
$s = $s * (100 + $saturationPercentage ) /100;
if($s > 1) $s = 1;
list($r, $g, $b) = hsl2rgb($h, $s, $l);
imagesetpixel($image, $x, $y, imagecolorallocatealpha($image, $r, $g, $b, $alpha));
}
}
}
header('Content-type: image/png');
$image = imagecreatefrompng('rgb.png');
imageSaturation($image, -80);//bring down current image saturation to 80%
imagepng($image);
EFFORTS UPDATE :
It has been pointed out to me by #Dai that these lines help construct a color code of an individual RGB pixel. So I guess this part can remained unchanged ?
$rgb = imagecolorat($image, $x, $y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
$alpha = ($rgb & 0x7F000000) >> 24;
In the next line we are simply converting the RGB values to HSL with rgb2hsl($r, $g, $b); and assigning it to list($h, $s, $l). The point I am stuck at the moment are these lines.
$s += $saturationPercentage / 100;
if($s > 1) $s--;
I understand the syntax, but not sure how I handle these or if they are even required. If not an answer helpful hints / suggestions would be great. I am trying the code on this image to bring down the saturation from 100% to 80%, but I am getting this image as result.
I think you need something like
$s=$s * (100+$saturationPercentage)/100
else you are just adding a constant to each value rather than a percentage of the existing value.
Also, where you decrement 1 if your new saturation exceeds 1, you probaly would be better just setting it to 1.0, i.e. fully saturated like this:
if($s>1)$s=1
otherwise, say the resulting saturation is 1.3 (i.e. very, very saturated) you will make that into 0.3, i.e. very undersaturated, instead of 1.0 (fully saturated).
So, if $s is 0.7, and you add 10%, you will get
$s = 0.7 * (100 + 10)/100
$s = 0.7 * 1.1
$s = 0.77

Change hue of an image (Transparent PNG) using PHP GD

I referred to answers on this question.
And I am currently using following code for hue overlay:
function imagehue(&$image, $angle) {
if($angle % 360 == 0) return;
$width = imagesx($image);
$height = imagesy($image);
for($x = 0; $x < $width; $x++) {
for($y = 0; $y < $height; $y++) {
$rgb = imagecolorat($image, $x, $y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
$alpha = ($rgb & 0x7F000000) >> 24;
list($h, $s, $l) = rgb2hsl($r, $g, $b);
$h += $angle / 360;
if($h > 1) $h--;
list($r, $g, $b) = hsl2rgb($h, $s, $l);
imagesetpixel($image, $x, $y, imagecolorallocatealpha($image, $r, $g, $b, $alpha));
}
}
}
It works good with JPG. But this code doesn't work with transparent PNG images.
This is how I call this function for PNG images:
header('Content-type: image/png');
**$image = imagecreatefrompng('image.png');**
imagehue($image, 180);
imagejpeg($image);
Does anyone know what changes I should make?
It's because you use the imagejpeg function, use imagepng instead.
And if you also want it to work with alpha transparency, add this to your code:
imagealphablending($image, false);
imagesavealpha($image, true);

PHP Load image into array, 2 bit

I want to load an entire image (PNG) into a 2-dimensional array where a black pixel is true and a white pixel is false.
What's the most efficient way of doing this?
Should I convert the image into bitmap and attempt to read that in, or is there a more efficient method?
This should do:
$image = imagecreatefrompng("input.png");
$width = imagesx($image);
$height = imagesy($image);
$colors = array();
for ($y = 0; $y < $height; $y++)
{
for ($x = 0; $x < $width; $x++)
{
$rgb = imagecolorat($image, $x, $y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
$black = ($r == 0 && $g == 0 && $b == 0);
$colors[$x][$y] = $black;
}
}
A probably more efficient way would be using Imagick::exportImagePixels().

Categories