3D Landscape Effect

IMagick is a native PHP extension to create and modify images using the ImageMagick API. ImageMagick Studio LLC did not write nor does it maintain the IMagick extension, however, IMagick users are welcome to discuss the extension here.
Post Reply
DJ Mike
Posts: 33
Joined: 2010-06-29T19:07:53-07:00
Authentication code: 8675308

3D Landscape Effect

Post by DJ Mike »

Turn an image into a 3D landscape. Each pixel is turned into a line with it's height proportional to it's grayscale value.

The ImagickPixelIterator class Example #2: 3D Landscape
http://eclecticdjs.com/mike/tutorials/p ... dscape.php
DJ Mike's Tutorials: PHP
ImageMagick Functions
http://eclecticdjs.com/mike/tutorials/p ... /index.php
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: 3D Landscape Effect

Post by fmw42 »

Nice to be able to do something like that in IM.

For reference, see my publications on my web site at http://www.fmwconcepts.com/fmw/fmw.html

and particular my survey paper F.M. Weinhaus and V. Devarajan, Texture Mapping 3D Models of Real-World Scenes, ACM Computing Surveys, Vol. 29, No. 4, 325-365, December 1997.
el_supremo
Posts: 1015
Joined: 2005-03-21T21:16:57-07:00

Re: 3D Landscape Effect

Post by el_supremo »

Mike,
I think the reason that this script uses so much ram and takes a long time is because you don't need to use pixel iterators at all because you aren't modifying the source image like you do in the ripple example. In fact, you don't actually use the iterators other than to find which row you are currently working on and there's a much easier way to do that by using a for loop.

Pete
Sorry, my ISP shutdown all personal webspace so my MagickWand Examples in C is offline.
See my message in this topic for a link to a zip of all the files.
DJ Mike
Posts: 33
Joined: 2010-06-29T19:07:53-07:00
Authentication code: 8675308

Re: 3D Landscape Effect

Post by DJ Mike »

el_supremo wrote:Mike,
I think the reason that this script uses so much ram and takes a long time is because you don't need to use pixel iterators at all because you aren't modifying the source image like you do in the ripple example. In fact, you don't actually use the iterators other than to find which row you are currently working on and there's a much easier way to do that by using a for loop.

Pete
Thanks. As obvious as that is now I missed it until you pointed it out. I tried running the avatar example again today and it ran for 8 minutes then gave me a 500 error. I changed it to the nested while loops that are posted below and it "only" took 1:26 the first time and 0:28 the second run. Now that I see that it isn't a good example of pixel iteration I'll have to think of somewhere else to put it.

Code: Select all

<?php
//set php script timeout, 0 to disable
set_time_limit(0);

# starting image
$url = "http://eclecticdjs.com/mike/images/avatar.jpg";

$file = "3d_avatar.jpg"; # name of finished image

# Read image as blob
$blob = file_get_contents("$url");
# make new imagick object from blob
$image = new imagick();
$image->readImageBlob("$blob");

# scale it down
$image->scaleimage(150, 0);
$image->shearImage("transparent", 45,0);

# scale it to make it look like it is laying down
$w = $image->getimagewidth();
$h = $image->getimageheight();
$image->scaleimage($w, $h/2);

# Get image stats
$w = $image->getimagewidth();
$h = $image->getimageheight();
$format = $image->getimageformat(); 

#### Make a pallet to draw on
$pallete = new Imagick;
$pallete->newimage($w,$h*2, "blue");
$p_w = $image->getimagewidth();
$p_h = $image->getimageheight();
$dif = $p_h-$h;

$pallete->setimageformat("$format");
####

$row = new ImagickPixelIterator($image);
$x = 1;
$y = 1;
#############################
# loop through all points
# while ( $row->getNextIteratorRow() )
while ( $y <= $h )
#############################
{
while ( $x <= $w)
{
# get (r,g,b) and grey value
$point = $image->getImagePixelColor( $x, $y );
$color = $point->getColor();
$r = $color[r];
$g = $color[g];
$b = $color[b];

# Calculate grayscale
$grey = ($r+$g+$b)/25;
$grey =(int)$grey;

# Make line with height proportional to grayscale 
$line = new ImagickDraw;
$line->setfillcolor("rgb($r,$g,$b)");
$line->setstrokecolor("rgb($r,$g,$b)");
#$line->setstrokewidth(1);
$line_height = $y-$grey;
$offset = 75;

#############################
#$y = $row->getIteratorRow();
#$y++;
#############################

$start_y = $y+$offset;
$end_y = $y-$grey+$offset;
$line->line( $x, $start_y, $x, $end_y);

# draw the line
$pallete->drawimage($line);

# Free up memory
$point->destroy();
$line->destroy();
unset($color);
$x++;
}
$x = 1;
$y++;
}

$pallete->scaleimage(250, 150);
# write pallet
$pallete->writeimage( "$file");

#header("content-type:image/$format");
header("Location:$file");echo $pallete;
exit;

?>
DJ Mike's Tutorials: PHP
ImageMagick Functions
http://eclecticdjs.com/mike/tutorials/p ... /index.php
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: 3D Landscape Effect

Post by fmw42 »

In general, I think for loops are faster than while loops. At least that has been my experience on my Mac when scripting in bash.
el_supremo
Posts: 1015
Joined: 2005-03-21T21:16:57-07:00

Re: 3D Landscape Effect

Post by el_supremo »

Hi Mike,
A few comments on your new code:
1. You still instantiate an ImagickPixelIterator but don't use it - probably forgot to comment it out

Code: Select all

	$row = new ImagickPixelIterator($image);
2. The while loops would be easier to read as for loops and when indexing
into an image with ImageMagick the indices start at zero so either use

Code: Select all

	$x = 0;
	$y = 0;
	while ( $y < $h )
		{
		while ( $x < $w)

OR use

Code: Select all

	for($y=0;$y<$h;$y++)
		{
		for($x=0;$x<$w;$x++)
and remove $x++; and $x=1;$y++; from the bottom of the loops.

3. I converted your example to C and I'm using it as a MagickWand Example in C (see my sig).
While doing this I found that it is about 25% faster to create, draw and destroy
the "line" drawingwand outside the inner loop. Your code is similar to this:

Code: Select all

	for($y=0;$y<$h;$y++)
		{
		for($x=0;$x<$w;$x++)
		{
			.
			.
			.
			$line = new ImagickDraw;
			.
			.
			$line->line( $x, $start_y, $x, $end_y);
			
			# draw the line
			$pallete->drawimage($line);
			$line->destroy();
		
		}

It will execute faster arranged like this:

Code: Select all

	for($y=0;$y<$h;$y++)
		{
		$line = new ImagickDraw;
		for($x=0;$x<$w;$x++)
		{
			.
			.
			$line->line( $x, $start_y, $x, $end_y);
			
		}	
		# draw the line
		$pallete->drawimage($line);
		$line->destroy();
I also found that drawing the image from top to bottom, while it is easy to do, requires drawing a lot of lines which will only be overwritten by a later line that is in "front" of them and so covers them up. I modified my C version so that it starts at the bottom of the image and goes up each column, keeping track of the length of the most recently drawn line and only drawing a new one if it is longer. This can speed up the process by a factor of four or more. If you're interested, have a look at my code at http://members.shaw.ca/el.supremo/Magic ... ape_3d.htm

Pete
Sorry, my ISP shutdown all personal webspace so my MagickWand Examples in C is offline.
See my message in this topic for a link to a zip of all the files.
DJ Mike
Posts: 33
Joined: 2010-06-29T19:07:53-07:00
Authentication code: 8675308

Re: 3D Landscape Effect

Post by DJ Mike »

Thanks for the tips. I don't know C but I can follow almost all of it and I copied to study later.
DJ Mike's Tutorials: PHP
ImageMagick Functions
http://eclecticdjs.com/mike/tutorials/p ... /index.php
DJ Mike
Posts: 33
Joined: 2010-06-29T19:07:53-07:00
Authentication code: 8675308

Re: 3D Landscape Effect

Post by DJ Mike »

I have not modified the scripts yet but I thought this other example was nice. I knew that my multi-color shirt wouldn't make a good 3D effect but the illusion of my hand standing out of the rest of the image is pretty convening. I changed the $gray divisor to 100 to make the hand less exaggerated and more lifelike.

Before
http://eclecticdjs.com/mike/tutorials/p ... possum.jpg

After
http://eclecticdjs.com/mike/tutorials/p ... possum.jpg
DJ Mike's Tutorials: PHP
ImageMagick Functions
http://eclecticdjs.com/mike/tutorials/p ... /index.php
Post Reply