0

I'm trying to add a new method to the Image class from Python Imaging Library. I want to have a new class called DilateImage which acts exactly as the original Image class, except it also includes a dilate() function which modifies the class instance when it is executed on one. Here's my example code (that isn't working):

import Image

def DilateImage(Image):
   def dilate(self):
      imnew = self.copy()
      sourcepix = imnew.load()
      destpix = self.load()

      for y in range(self.size[1]):
         for x in range(self.size[0]):
            brightest = 255
            for dy in range(-1,2):
               for dx in range(-1,2):
                  try:
                     brightest = min(sourcepix[x+dx,y+dy], brightest)
                  except IndexError:
                     pass
            destpix[x, y] = brightest

When I try to use this new class type to create an instance that uses the base class' "open" function it fails:

>>> test = DilateImage.open("test.jpg")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'function' object has no attribute 'open'
chris Frisina
  • 19,086
  • 22
  • 87
  • 167
runeks
  • 1,745
  • 2
  • 17
  • 26

4 Answers4

9

Use

class DilateImage(Image)

not

def DilateImage(Image)
Waleed Khan
  • 11,426
  • 6
  • 39
  • 70
  • Thanks. Now I'm getting the following error though, at the "class"-line: `Traceback (most recent call last):` `File "piltest.py", line 3, in ` `class DilateImage(Image):` `TypeError: Error when calling the metaclass bases` `module.__init__() takes at most 2 arguments (3 given)` – runeks Sep 02 '12 at 08:45
  • Here, "Image" is not a class, it is a name of a module that you are importing. That module contains a class named "Image". You could try to extend that class by saying `class DilateImage(Image.Image)`, however, the `open()` function is not a method of the `Image.Image` class, but simply a function in the `Image` module, and will return an instance of `Image.Image`. As far as I can tell, the PIL is not really designed to be extended in such OO way. –  Sep 12 '12 at 01:51
  • @JanHlavacek You should post that as an answer. – Waleed Khan Sep 12 '12 at 10:40
  • I suppose you are right. I didn't think first that it answers the question, but now when I read it again, I think I can make it into an answer. –  Sep 12 '12 at 16:50
3

There are two problems with your code. One of them has been already pointed out, when defining a class, you need to use the class keyword, since def keyword defines a function or a method.

The second problem is that the call

import Image

will import the module called Image into the Image namespace, so that Image in your code will refer to the module. It is not an object or class, so

class MyImage(Image)

will attempt to derive a new class from a module, which will fail.

The Image module contains a class called Image. After importing the module into the Image namespace, you would refer to this class as Image.Image. To extend this class, you could do for example this:

import Image

class MyImage(Image.Image)

To make this less confusing, you could also import the Image module into a different namespace:

import Image as Img

class MyImage(Img.Image)

The problem with all that is, the PIL does not seem to be designed to allow this kind of extension to the Image class. Its modules provide bunch of functions that take instances of Image as arguments and return new instances of Image. there are only few methods in the actual Image class. So what you probably want to do is write a function that will take an instance if Image and create a new instance of Image, rather than extending the Image class by a new method. For example, something like this:

import Image

def DilateImage(source):
      dest = source.copy()
      sourcepix = source.load()
      destpix = dest.load()

      for y in range(source.size[1]):
         for x in range(source.size[0]):
            darkest = 255
            for dy in range(-1,2):
               for dx in range(-1,2):
                  try:
                     darkest = min(sourcepix[x+dx,y+dy], darkest)
                  except IndexError:
                     pass
            destpix[x, y] = darkest

      return dest


im1 = Image.open("test.jpg")

img2 = DilateImage(im1)

img2.show()
1

You're defining DilateImage as a function (by using def), when you should be using the class keyword. Hence the AttributeError, since functions don't have an open attribute.

arshajii
  • 127,459
  • 24
  • 238
  • 287
  • Thanks, I'm not sure how I missed that. As I mentioned in the comment to the other answer, now I get another error though, that I don't know how to interpret: `Traceback (most recent call last):` `File "piltest.py", line 3, in ` `class DilateImage(Image):` `TypeError: Error when calling the metaclass bases` `module.__init__() takes at most 2 arguments (3 given)` – runeks Sep 02 '12 at 16:05
0

I don't know if this is a recent change, but in the same style as the previous comments you can actually modify/add to existing classes. For example:

class list(list):
    #Create an Empty List
    def empty(N:int):
        """Create an N-Long Empty List"""
        return [None]*int(N)

This won't change the preexisting functionality of the 'list' class, but it will add a method which does this:

>>> list.empty(5)
[None, None, None, None, None]

You can do this with other classes as well, so to give sample code to answer your question more directly:

#Import Libraries
import Image

#Add Methods to Image
class Image(Image):
    def dilate(*args, **kwargs):
        ...

I'm not sure if any of this is recommended, but it's cool that you can do it!