views:

513

answers:

3

I am trying to use PythonMagickWand to use a Shepards distortion on an image. You can also see the source of distort.c that is used by ImageMagick.

PythonMagickWand does not by default support Shepards distortion. To fix this, I added in:

ShepardsDistortion = DistortImageMethod(15)

to line 544 of PythonMagickWand (See here for my modified PythonMagicWand). The 15 pointer is in reference to distort.h (line 51) of the MagickWand source in which ShepardsDistortion is the 15th item on the list. This fits with all of the other supported distortion methods.

Now, something that I may be doing wrong is presuming that the existing distortion methods that are supported by PythonMagickWand use the same type of arguments as the Shepards. They might not but I do not know how I can tell. I know that distort.c is doing the work, but I can't work out if the arguments it takes in are the same or different.

I have the following code (snippet):

from PythonMagickWand import *
from ctypes import *

arrayType = c_double * 8  
pointsNew = arrayType()
pointsNew[0] = c_double(eyeLeft[0])
pointsNew[1] = c_double(eyeLeft[1])
pointsNew[2] = c_double(eyeLeftDest[0])
pointsNew[3] = c_double(eyeLeftDest[1])
pointsNew[4] = c_double(eyeRight[0])
pointsNew[5] = c_double(eyeRight[1])
pointsNew[6] = c_double(eyeRightDest[0])
pointsNew[7] = c_double(eyeRightDest[1])

MagickWandGenesis()
wand = NewMagickWand()
MagickReadImage(wand,path_to_image+'image_mod.jpg')
MagickDistortImage(wand,ShepardsDistortion, 8, pointsNew, False)
MagickWriteImage(wand,path_to_image+'image_mod22.jpg')

I get the following error:

MagickDistortImage(wand,ShepardsDistortion, 8, pointsNew, False) ctypes.ArgumentError: argument 4: <type 'exceptions.TypeError'>: expected LP_c_double instance instead of list

I am aware that pointsNew is the wrong way of providing the arguments.. But I just don't know what is the right format. This is an example distort command that works when run in Terminal:

convert image.jpg -virtual-pixel Black -distort Shepards 121.523809524,317.79638009 141,275 346.158730159,312.628959276 319,275 239.365079365,421.14479638 232,376 158.349206349,483.153846154 165,455 313.015873016,483.153846154 300,455 0,0 0,0 0,571.0 0,571.0 464.0,571.0 464.0,571.0 0,571.0 0,571.0 image_out.jpg

So I guess the question is: How do I create a list of c_doubles that will be accepted by PythonMagickWand? Or is my hack to add Shepards Distortion into PythonMagickWand completely wrong?

I basically need to re-create the terminal command. I have got it working by using subprocess to run the command from Python but that is not how I want to do it.

A: 

As the error message indicates, the function is expecting a pointer (LP_c_double), but all you have is an array.

You'll need to explicitly cast your array to a pointer, for the purposes of passing it as a pointer to the external function:

>>> arr = (c_double * 8)()
>>> arr # just an array...
<__main__.c_double_Array_8 object at 0x1004ad050>
>>> arr[0] = 5
# ...
>>> cast(arr, POINTER(c_double)) # now it's the right type
<__main__.LP_c_double object at 0x1004ad0e0>
>>> cast(arr, POINTER(c_double))[0]
5.0
Mark Rushakoff
Sorry, I was. I just wrote out a simplified snippet and forgot to add that import in. I've edited my post to fit that now!
betamax
Thanks, I really appreciate your help. The function *does* accept this as input.. *However*, it doesn't do anything. I failed to mention my modification of PythonMagickWand before which is undoubtedly an important hint to why this isn't working. I've modified my post to reflect in more detail what I am trying to do.
betamax
A: 

This is OT, but:

I really liked python magick wand, but when I used it on 600+ images there was a memory leak somewhere, which ate all the memory in the (32 bit) machine. I was inclined to think possibly in ImageMagick itself, but I might've been wrong.

In the end I found out that:

GraphicsMagick is a port of an earlier version of ImageMagick; but because ImageMagick changes their API a lot, PythonMagickWant won't work with GraphicsMagick.

GraphicsMagick, also seems to be faster than ImageMagick (using better multitasking).

In order to get my script working quickly, in a few days I changed it so that instead of using ImageMagick, the script loaded the gimp, which then ran my script using python-scriptfu. Everything seemed to work OK.

If it works for you, then use it; also the PythonMagickWand guy is really helpful + the bindings are nice.

Stuart Axon
A: 

From NeedMoreBeer on Reddit.com:

from PythonMagickWand import *
from ctypes import *

arrayType = c_double * 8  
pointsNew = arrayType()
pointsNew[0] = c_double(121.523809524)
pointsNew[1] = c_double(317.79638009)
pointsNew[2] = c_double(141)
pointsNew[3] = c_double(275) 
pointsNew[4] = c_double(346.158730159)
pointsNew[5] = c_double(312.628959276)
pointsNew[6] = c_double(319)
pointsNew[7] = c_double(275)

ShepardsDistortion = DistortImageMethod(14)

MagickWandGenesis()
wand = NewMagickWand()
MagickReadImage(wand,'/home/user/image.png')
MagickDistortImage(wand,ShepardsDistortion, 8, pointsNew, False)
MagickWriteImage(wand,'/home/user/image_mod22.jpg')

More specifically for me, it was the following line:

ShepardsDistortion = DistortImageMethod(14)

That fixed it for me! Thanks again to NeedMoreBeer from Reddit.

betamax