PHP Convert Image To 16 Level Grayscale, Then Read Each Pixel

I have a client in need of a solution... preferable in PHP as I am not that skilled in ASP.net - yet.

Client is an artist mainly working in acrylic and works in a cross between expressionism and abstract. One of his experimental efforts requires an application to be built so that he can break down tonal information.

Basically, he needs a web based application that will allow him to upload/import a color image or black and white image, have it converted to 16 level gray scale and then identify each pixel value to display/print in line order:

Example Output:
1 3 5 2 0    C D F 2 4   4 3 5 6 4   3 4 6 7 3   1 3 4 5 6
2 3 4 5 5    3  6 8 5 6   3 4 5 6 1   2 4 6 8 9   1 2 4 5 8
1 3 5 2 0    C D F 2 4   4 3 5 6 4   3 4 6 7 3   1 3 4 5 6
2 3 4 5 5    3  6 8 5 6   3 4 5 6 1   2 4 6 8 9   1 2 4 5 8
2 3 4 5 5    3  6 8 5 6   3 4 5 6 1   2 4 6 8 9   1 2 4 5 8

Where EACH NUMBER/LETTER would identify the gray level of each pixel, as follows:

1= Level 1 Gray
2= Level 2 Gray
3= Level 3 Gray
4= Level 4 Gray
5= Level 5 Gray
6= Level 6 Gray
7= Level 7 Gray
8= Level 8 Gray
9= Level 9 Gray
0= Level 10 Gray
A= Level 11 Gray
B= Level 12 Gray
C= Level 13 Gray
D= Level 14 Gray
E= Level 15 Gray
F= Level 16 Gray

In the above example, Image would be 25 pixels wide, 20 pixels tall  - but the function needs to accommodate images of varying widths and heights.

What I need help with is a PHP5 Function to convert the image to 16 Level/Bit Grayscale, and then a separate function to read the pixel of each image.  I do know the GD Library is compiled into PHP, but I do not believe ImageMagik is.  I checked using PhpInfo() and it isn't in the list.

From the hours of reading I have done, I am pretty sure it is possible - I am just not sure how exactly.

Any help someone can provide with be very much appreciated!

Thanks!
nyxanoAsked:
Who is Participating?

Improve company productivity with a Business Account.Sign Up

x
 
Slick812Connect With a Mentor Commented:
I have reworked this php app to the new design specs you have given, however, I had to change the "200x200 (while maintaining aspect ratio" down to "100x100", I did this in order to have the display of an image pixel ROW in the image not to wrap into 2 lines on the screen in the output display, But you can change the $dimention variable to whatever max small size you decide to use. I also had to not use the "spaces" between the HEX letters and numbers, for the same reason, to reduce the horizontal size of a display row.
<html><head><title>Greyscale PNG test</title></head><body bgcolor="#E3F7FF">
<h2>GD color PNG to greyscale Image test</h2>
<?php
$img = imagecreatefrompng('images3/bigcolor.png');

$hex1 = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');

// the $dimention below sets the smaller resized image MAX dimention
$dimention = 100; // 200
	// I tried this with the dimention as 200, BUT I have a real wide monitor, and 
	//the "rows" of display ran more than the width of my screen, so changed to 100

$wid = imagesx($img);
$hgt = imagesy($img);
echo  'old width- '.$wid.' old height- '.$hgt.'<br />';

if(($wid>$dimention)|($hgt>$dimention)){
	if ($wid>$hgt) {$wid2=$dimention;
		$hgt2=ceil(($hgt/$wid)*$dimention);}
		elseif ($hgt>$wid) {$hgt2=$dimention;
		$wid2=ceil(($wid/$hgt)*$dimention);}
		else {$hgt2=$dimention; $wid2=$dimention;}
	if ($hgt2 < 3) $hgt2 = 3;
	if ($wid2 < 3) $wid2 = 3;
	$resize = imagecreatetruecolor($wid2, $hgt2);
	// I had to use the less quality resize of imagecopyresized() instaed of imagecopyresampled().
	imagecopyresized($resize, $img, 0, 0, 0, 0, $wid2, $hgt2, $wid, $hgt);
	//the imagecopyresampled() really alterd the colors to crap values for a 16 color greyscale image
	imagedestroy($img);
	$img = $resize;
	$hgt = $hgt2;
	$wid = $wid2;
	echo  'new width- '.$wid.' new height- '.$hgt.'<br />';
	imagepng($img, 'images3/resize1.png');
	// the save file above needs your file path and file name
	}


imagefilter($img, IMG_FILTER_GRAYSCALE);
for($y = 0; $y < $hgt; ++$y){
	for($x = 0; $x < $wid; ++$x){
		$color = imagecolorat($img, $x, $y);
		$color &= 255;
// I had to eliminate the extra spaces inorder to get each pixel row NOT to wrap around on my screen
		echo $hex1[floor($color/16)];//.' '
		if ($x%5 == 4) echo ' ';
		}
	echo '<br />';
	}
imagedestroy($img);

?>
<p><img src="images3/resize1.png"></p>
</body></html>

Open in new window

0
 
Scott MadeiraCommented:
Try this.  I think it does what you want.  I have echo statements in there to show color values. You could save to an array or do whatever you want with the data.

 
<?php 

	// Read your image file
	$im = imagecreatefromjpeg('5docs.jpg');
	
	// Convert to 16 level Grayscale
	imagetograyscale($im);
	
	// Get color values
	imagegetcolors($im);
	
	
	// Save new image
	imagejpeg($im, '5docs16.jpg');
	
	
	
	
	function imagetograyscale($im)
		{
			// Convert to Grayscale
			imagefilter($im, IMG_FILTER_GRAYSCALE);
			
			// Convert grayscale image to pallette image
		    if (imageistruecolor($im)) {		    
		        imagetruecolortopalette($im, false, 256);
		    }
		
		    for ($c = 0; $c < imagecolorstotal($im); $c++) {
		        $col = imagecolorsforindex($im, $c);
		        
		        // Get value for red (which should be the same for blue and green becuase it is grayscale
		        // Convert from 256 level to 16 level by using the higer 4 bits (00 - 0F woudl be 00, 80-8F would be 88, etc.)
		        $gray = $col['red'] >> 4 & 0xF;
        		$gray = $gray*16;        
        		imagecolorset($im, $c, $gray, $gray, $gray);
		        		        
		        imagecolorset($im, $c, $gray, $gray, $gray);
		    }
		}
	
	
	function imagegetcolors($im){
			
			$imgw = imagesx($im);
			$imgh = imagesy($im);
			
			echo 'height = '.$imgh;
			
			// If image is not truecolr then convert to truecolor
			if (! imageistruecolor($im)) {		    
		        $imgTC = imagecreatetruecolor($imgw, $imgh);
				imagecopy($imgTC, $im, 0, 0, 0, 0, $imgw, $imgh);
				$im = $imgTC;
		    }
	
			for ($x = 0 ; $x < $imgw; $x++){
				for ($y = 0 ; $y < $imgh; $y++){	
					// Get pixel color				
					$rgb = imagecolorat($im, $x, $y);
					//get top 4 bits - upper half of red color
					$r = ($rgb >> 20) & 0xFF;
					echo 'Values: R='.$r ."\n";
					
				
				}
			}		
	}
	

	imagedestroy($im);	
	
?>

Open in new window

0
 
Slick812Commented:
greetings nyxano,  Below is my php code to get the output you have listed above, but I have a - instead of many spaces
1 3 5 2 0 - C D F 2 4 - 4 3 5 6 4 - 3 4 6 7 3 - 1 3 4 5 6

but I have no idea why you are using groups of 5? ?

also I use a more correct "HEX" as you have your ZERO above the 9 instead of where it should be , below the 1

Ask questions if you need more info or corrections. .
<html><head><title>Greyscale PNG test</title></head><body bgcolor="#E3F7FF"><h2>GD color PNG to greyscale Image test</h2>
<?php
$img = imagecreatefrompng('images3/color.png');
imagefilter($img, IMG_FILTER_GRAYSCALE);
// if your version of GD does not have imagefilter( ), there are other ways
$hex1 = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
$pixelOut = array();
$wid = imagesx($img);
$hgt = imagesy($img);
for($x = 0; $x < $wid; ++$x){$pixelOut[x] = array();
	for($y = 0; $y < $hgt; ++$y){//if($x==1)echo $y;
		//$pixelOut[$x][$y]= $y;
		$index = imagecolorat($img, $x, $y);
		//$rgb = imagecolorsforindex($img,$index);
		$index &= 255;
		$pixelOut[$x][$y]= $hex1[floor($index/16)];//$index;//$rgb['red'];//; $rgb['red']
		//$color = imagecolorallocate($im, 255 - $rgb['red'], 255 - $rgb['green'], 255 - $rgb['blue']);
		//imagesetpixel($img, $x, $y, $color);
		}
	}
// you can change the output formatting below
for($y = 0; $y < $hgt; ++$y){
	for($x = 0; $x < $wid; ++$x){
		echo $pixelOut[$x][$y].' ';
		if ($x%5 == 4) echo '- ';
		}
	echo '<br />';
	}
?>
<p>More Text here</p>
</body></html>

Open in new window

0
The 14th Annual Expert Award Winners

The results are in! Meet the top members of our 2017 Expert Awards. Congratulations to all who qualified!

 
nyxanoAuthor Commented:
@smadeira
Thank you for the solution.  I have not had a chance to try it yet but will do so this weekend.

@Slick812
Your solution seems similar to that of smadeira but I do like that you took the time to also add the output code in as well.  As for why groups of 5?  I honestly do not have an answer except to say that I think it simply allows the output to be easier to read.  I will double check with the client to see if there is any other reason but I suspect that will be the reasoning.  I will try your solution this weekend as well and see which one best produces the results required.

Thank you to the both of you. Excellent work and I greatly appreciate the quick response.
0
 
nyxanoAuthor Commented:
@smadeira
Sorry, I didn't see before I posted my last comment that you also echoed the output.  I will be testing both solutions soon and we'll take it from there.
0
 
Slick812Commented:
I was in a hurry when I did it before, I looked at my code and could see that I do not need to loop through the pixels twice, and can do the operation in a single loop, which should be much more efficient, and fast, with alot less code to maintain.
try this out -
<html><head><title>Greyscale PNG test</title></head><body bgcolor="#E3F7FF"><h2>GD color PNG to greyscale Image test</h2>
<?php
$img = imagecreatefrompng('images3/color.png');
imagefilter($img, IMG_FILTER_GRAYSCALE);
$hex1 = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
	
for($y = 0; $y < imagesy($img); ++$y){
	for($x = 0; $x < imagesx($img); ++$x){
		$color = imagecolorat($img, $x, $y);
		$color &= 255;
		echo $hex1[floor($color/16)].' ';
		if ($x%5 == 4) echo '- ';
		}
	echo '<br />';
	}

imagedestroy($img);

?>
<p>More Text here</p>
</body></html>

Open in new window

0
 
nyxanoAuthor Commented:
@Slick812
The new code you've provided is definitely optimized.  I think that should run a lot faster.

I just got word from the client, and the scope of the project has changed slightly.  I think I should be able to take your code and amend it - but just to list the changes.

1.  If image is larger than 200x200, it needs to be resized down to 200x200 (while maintaining aspect ratio).

2.  The resized image from # 1 needs to be saved on the server so that it can be downloaded.

I already know how to do both of those tasks already so I am assuming that after I resize the image, I just load the image name/location into your $img= variable?

I still haven't tested the code yet but from what I see, it should work.  If you want to add code in for the extra options, that would be great - but if not, that's okay too.  Once I test the code, I'll be able to let you know how it all works out.
0
 
Slick812Commented:
It is late here now, I may can do something tomorrow, please run my code to see if your PHP has problems with it, it works on mine.
0
 
nyxanoAuthor Commented:
@Slick812
Just want to say I haven't forgotten about this. Right now, client is away and difficult to reach. From what I see, everything looks great and I should be able to take it from there and fill in the rest of the requirements. I just want to make sure there are no other major changes needed. I shoul be able to clue up this on the weekend.
0
 
Slick812Commented:
OK, there's not much I could do anyway, if you are hired by your client, you should do any additional work, since I don't get paid.
0
 
nyxanoAuthor Commented:
Solution was spot on for what I needed.  I was then able to take the code and adapt it to meet specific needs.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.