Difference between revisions of "PIL patches"

From Noah.org
Jump to navigationJump to search
 
 
(29 intermediate revisions by the same user not shown)
Line 1: Line 1:
 
[[Category:Engineering]]
 
[[Category:Engineering]]
This is a patch against the Python Imaging Library Imaging-1.1.6.
+
[[Category:Python]]
This add the method ImageChops.difference_rms(im1, im2) which returns
+
[[Category:Free_Software]]
a float giving the RMS difference between the two given images.
+
== Note ==
This is about 10 times faster than doing it in Python. This can be
+
?isn't this equivalent to:
used to detect changes in images (motion) or to compare the effect
+
 
of different image operations. If the two images are exactly equal then
+
    ImageStat.Stat(ImageChops.difference(i, im)).rms
differnce_rms() will return 0.0. As the images diverge the value returned will increase. It will always be a positive number. In general, the greater the difference between the two images then the greater the RMS difference will be.
+
 
 +
-- Fredrik Lundh fredrik at pythonware.com
 +
 
 +
== Add "difference_rms" method to the PIL ==
 +
 
 +
I originally wrote this to help implement a video stabilization filter. In video stabilization I take two frames of a video and shift one of them around until the RMS Difference is minimized. You could also use this to quantify how much a lossy compression algorithm distorts an image relative to some other compression algorithm.
 +
 
 +
This is a patch against the [http://www.pythonware.com/products/pil/ Python Imaging Library Imaging-1.1.6].
 +
This adds the method <em>ImageChops.difference_rms(im1, im2)</em> which returns a float of the RMS difference between the two given images, im1 and im2. This is about 10 times faster than doing it in Python. This can be used to detect changes in images (say, for motion detection) or to compare the effect of different image operations. If the two images are exactly equal then difference_rms() will return 0.0. As the images diverge the value returned will increase. It will always be a positive number. In general, the greater the difference between the two images then the greater the RMS difference will be.
 +
 
 +
To apply the patch and build PIL execute the following commands. This assumes that Imaging-1.1.6.tar.gz and Imaging-1.1.6.patch are in the same directory.
  
 
<pre>
 
<pre>
diff -r -C 6 -x.svn -x'*.jpg' -x'*.png' -x'*.gif' -x'*.swp' -x'*.a' -x'*.so' -x'*.o' -x'*.pyc' -x'*.exe' -x'*.class' -xCVS -xcore -xa.out /home/noah/Imaging-1.1.6/_imaging.c ./_imaging.c
+
tar xzf Imaging-1.1.6.tar.gz
*** /home/noah/Imaging-1.1.6/_imaging.c 2006-12-03 04:20:39.000000000 -0800
+
cd Imaging-1.1.6
--- ./_imaging.c        2007-05-29 10:21:15.000000000 -0700
+
patch -p 1 < Imaging-1.1.6.patch
***************
+
python setup.py install
*** 1848,1859 ****
 
--- 1848,1879 ----
 
      if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep))
 
        return NULL;
 
 
 
      return PyImagingNew(ImagingChopDifference(self->image, imagep->image));
 
  }
 
 
 
+ static PyObject*
 
+ _chop_difference_rms(ImagingObject* self, PyObject* args)
 
+ {
 
+    double rms;
 
+    ImagingObject* imagep;
 
+
 
+    if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep))
 
+        return Py_BuildValue("d", (double)0.0);
 
+
 
+    rms = ImagingChopDifferenceRMS(self->image, imagep->image);
 
+    if (rms == -1.0) {
 
+        return ImagingError_ModeError();
 
+    }
 
+    if (rms == -2.0) {
 
+        return ImagingError_Mismatch();
 
+    }
 
+
 
+    return Py_BuildValue("d", rms);
 
+ }
 
+
 
  static PyObject*
 
  _chop_multiply(ImagingObject* self, PyObject* args)
 
  {
 
      ImagingObject* imagep;
 
 
 
      if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep))
 
***************
 
*** 2821,2832 ****
 
--- 2841,2853 ----
 
  #ifdef WITH_IMAGECHOPS
 
      /* Channel operations (ImageChops) */
 
      {"chop_invert", (PyCFunction)_chop_invert, 1},
 
      {"chop_lighter", (PyCFunction)_chop_lighter, 1},
 
      {"chop_darker", (PyCFunction)_chop_darker, 1},
 
      {"chop_difference", (PyCFunction)_chop_difference, 1},
 
+    {"chop_difference_rms", (PyCFunction)_chop_difference_rms, 1},
 
      {"chop_multiply", (PyCFunction)_chop_multiply, 1},
 
      {"chop_screen", (PyCFunction)_chop_screen, 1},
 
      {"chop_add", (PyCFunction)_chop_add, 1},
 
      {"chop_subtract", (PyCFunction)_chop_subtract, 1},
 
      {"chop_add_modulo", (PyCFunction)_chop_add_modulo, 1},
 
      {"chop_subtract_modulo", (PyCFunction)_chop_subtract_modulo, 1},
 
diff -r -C 6 -x.svn -x'*.jpg' -x'*.png' -x'*.gif' -x'*.swp' -x'*.a' -x'*.so' -x'*.o' -x'*.pyc' -x'*.exe' -x'*.class' -xCVS -xcore -xa.out /home/noah/Imaging-1.1.6/libImaging/Chops.c ./libImaging/Chops.c
 
*** /home/noah/Imaging-1.1.6/libImaging/Chops.c 2006-12-03 03:37:25.000000000 -0800
 
--- ./libImaging/Chops.c        2007-05-29 10:29:04.000000000 -0700
 
***************
 
*** 90,101 ****
 
--- 90,132 ----
 
  Imaging
 
  ImagingChopDifference(Imaging imIn1, Imaging imIn2)
 
  {
 
      CHOP(abs((int) in1[x] - (int) in2[x]), NULL);
 
  }
 
 
 
+ double ImagingChopDifferenceRMS(Imaging imIn1, Imaging imIn2)
 
+ {
 
+    int x, y;
 
+    long count, n, ns;
 
+
 
+    if (!imIn1 || !imIn2 || imIn1->type != IMAGING_TYPE_UINT8 ||
 
+        (strcmp(imIn1->mode, imIn2->mode) != 0))
 
+        return -1.0; //(Imaging) ImagingError_ModeError();
 
+
 
+    if (imIn1->type  != imIn2->type  ||
 
+        imIn1->bands != imIn2->bands ||
 
+        imIn1->ysize != imIn2->ysize ||
 
+        imIn1->xsize != imIn2->xsize)
 
+        return -2.0; //(Imaging) ImagingError_Mismatch();
 
+
 
+    ns = 0;
 
+    count = 0;
 
+    for (y = 0; y < imIn1->ysize; ++y)
 
+    {
 
+        UINT8* in1 = (UINT8*) imIn1->image[y];
 
+        UINT8* in2 = (UINT8*) imIn2->image[y];
 
+        for (x = 0; x < imIn1->linesize; ++x)
 
+        {
 
+            ++ count;
 
+            n = (long) in1[x] - (long) in2[x];
 
+            ns += n*n;
 
+        }
 
+    }
 
+    return sqrt((double)ns / (double)count);
 
+ }
 
+
 
  Imaging
 
  ImagingChopMultiply(Imaging imIn1, Imaging imIn2)
 
  {
 
      CHOP((int) in1[x] * (int) in2[x] / 255, NULL);
 
  }
 
 
 
diff -r -C 6 -x.svn -x'*.jpg' -x'*.png' -x'*.gif' -x'*.swp' -x'*.a' -x'*.so' -x'*.o' -x'*.pyc' -x'*.exe' -x'*.class' -xCVS -xcore -xa.out /home/noah/Imaging-1.1.6/libImaging/Imaging.h ./libImaging/Imaging.h
 
*** /home/noah/Imaging-1.1.6/libImaging/Imaging.h      2006-12-03 03:37:25.000000000 -0800
 
--- ./libImaging/Imaging.h      2007-05-27 19:48:14.000000000 -0700
 
***************
 
*** 307,318 ****
 
--- 307,319 ----
 
 
 
  /* Channel operations */
 
  /* any mode, except "F" */
 
  extern Imaging ImagingChopLighter(Imaging imIn1, Imaging imIn2);
 
  extern Imaging ImagingChopDarker(Imaging imIn1, Imaging imIn2);
 
  extern Imaging ImagingChopDifference(Imaging imIn1, Imaging imIn2);
 
+ extern double  ImagingChopDifferenceRMS(Imaging imIn1, Imaging imIn2);
 
  extern Imaging ImagingChopMultiply(Imaging imIn1, Imaging imIn2);
 
  extern Imaging ImagingChopScreen(Imaging imIn1, Imaging imIn2);
 
  extern Imaging ImagingChopAdd(
 
      Imaging imIn1, Imaging imIn2, float scale, int offset);
 
  extern Imaging ImagingChopSubtract(
 
      Imaging imIn1, Imaging imIn2, float scale, int offset);
 
diff -r -C 6 -x.svn -x'*.jpg' -x'*.png' -x'*.gif' -x'*.swp' -x'*.a' -x'*.so' -x'*.o' -x'*.pyc' -x'*.exe' -x'*.class' -xCVS -xcore -xa.out /home/noah/Imaging-1.1.6/PIL/ImageChops.py ./PIL/ImageChops.py
 
*** /home/noah/Imaging-1.1.6/PIL/ImageChops.py  2006-12-03 03:37:15.000000000 -0800
 
--- ./PIL/ImageChops.py 2007-05-27 20:07:09.000000000 -0700
 
***************
 
*** 120,131 ****
 
--- 120,149 ----
 
 
 
      image1.load()
 
      image2.load()
 
      return image1._new(image1.im.chop_difference(image2.im))
 
 
 
  ##
 
+ # Calculate RMS difference
 
+ # <p>
 
+ # Returns the RMS of the difference between the two images.
 
+ #
 
+ # @param image1 First image.
 
+ # @param image1 Second image.
 
+ # @return float.
 
+
 
+ def difference_rms(image1, image2):
 
+    """This returns the RMS difference of two images.
 
+    This returns a double float
 
+    """
 
+
 
+    image1.load()
 
+    image2.load()
 
+    return image1.im.chop_difference_rms(image2.im)
 
+
 
+ ##
 
  # Superimpose positive images
 
  # (image1 * image2 / MAX).
 
  # <p>
 
  # Superimposes two images on top of each other. If you multiply an
 
  # image with a solid black image, the result is black. If you multiply
 
  # with a solid white image, the image is unaffected.
 
diff -r -C 6 -x.svn -x'*.jpg' -x'*.png' -x'*.gif' -x'*.swp' -x'*.a' -x'*.so' -x'*.o' -x'*.pyc' -x'*.exe' -x'*.class' -xCVS -xcore -xa.out /home/noah/Imaging-1.1.6/setup.py ./setup.py
 
*** /home/noah/Imaging-1.1.6/setup.py  2006-12-03 03:37:29.000000000 -0800
 
--- ./setup.py  2007-03-14 11:27:25.000000000 -0700
 
***************
 
*** 137,148 ****
 
--- 137,150 ----
 
              add_directory(library_dirs, "/sw/lib")
 
              add_directory(include_dirs, "/sw/include")
 
              # darwin ports installation directories
 
              add_directory(library_dirs, "/opt/local/lib")
 
              add_directory(include_dirs, "/opt/local/include")
 
 
 
+        #add_directory(library_dirs, "")
 
+        add_directory(include_dirs, "/usr/include/tcl8.4")
 
          add_directory(library_dirs, "/usr/local/lib")
 
          # FIXME: check /opt/stuff directories here?
 
 
 
          prefix = sysconfig.get_config_var("prefix")
 
          if prefix:
 
              add_directory(library_dirs, os.path.join(prefix, "lib"))
 
***************
 
*** 192,203 ****
 
--- 194,206 ----
 
 
 
          #
 
          # add standard directories
 
 
 
          add_directory(library_dirs, "/usr/local/lib")
 
          add_directory(include_dirs, "/usr/local/include")
 
+        add_directory(include_dirs, "/usr/include/tcl8.4")
 
 
 
          add_directory(library_dirs, "/usr/lib")
 
          add_directory(include_dirs, "/usr/include")
 
 
 
          #
 
          # insert new dirs *before* default libs, to avoid conflicts
 
***************
 
*** 244,255 ****
 
--- 247,259 ----
 
              if freetype_version:
 
                  feature.freetype = "freetype"
 
                  feature.freetype_version = freetype_version
 
                  if dir:
 
                      add_directory(self.compiler.include_dirs, dir, 0)
 
 
 
+        add_directory(include_dirs, "/usr/include/tcl8.4")
 
          if _tkinter:
 
              # the library names may vary somewhat (e.g. tcl84 or tcl8.4)
 
              version = TCL_VERSION[0] + TCL_VERSION[2]
 
              if find_library_file(self, "tcl" + version):
 
                  feature.tcl = "tcl" + version
 
              elif find_library_file(self, "tcl" + TCL_VERSION):
 
 
</pre>
 
</pre>
 +
 +
[http://www.noah.org/engineering/src/python/Imaging-1.1.6.patch Download patch]
 +
 +
<include src="/var/www/usr/local/apache2/htdocs/engineering/src/python/Imaging-1.1.6.patch" highlight="diff" />

Latest revision as of 06:04, 28 March 2008

Note

?isn't this equivalent to:

    ImageStat.Stat(ImageChops.difference(i, im)).rms

-- Fredrik Lundh fredrik at pythonware.com

Add "difference_rms" method to the PIL

I originally wrote this to help implement a video stabilization filter. In video stabilization I take two frames of a video and shift one of them around until the RMS Difference is minimized. You could also use this to quantify how much a lossy compression algorithm distorts an image relative to some other compression algorithm.

This is a patch against the Python Imaging Library Imaging-1.1.6. This adds the method ImageChops.difference_rms(im1, im2) which returns a float of the RMS difference between the two given images, im1 and im2. This is about 10 times faster than doing it in Python. This can be used to detect changes in images (say, for motion detection) or to compare the effect of different image operations. If the two images are exactly equal then difference_rms() will return 0.0. As the images diverge the value returned will increase. It will always be a positive number. In general, the greater the difference between the two images then the greater the RMS difference will be.

To apply the patch and build PIL execute the following commands. This assumes that Imaging-1.1.6.tar.gz and Imaging-1.1.6.patch are in the same directory.

tar xzf Imaging-1.1.6.tar.gz
cd Imaging-1.1.6
patch -p 1 < Imaging-1.1.6.patch
python setup.py install

Download patch

<include src="/var/www/usr/local/apache2/htdocs/engineering/src/python/Imaging-1.1.6.patch" highlight="diff" />