[Image-SIG] Unsharp Masking?

Kevin@Cazabon.com kevin@cazabon.com
Sun, 17 Mar 2002 21:24:45 -0700


This is a multi-part message in MIME format.

------=_NextPart_000_0062_01C1CDFA.2929D510
Content-Type: text/plain;
	charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

I've cleaned it up a bit, and added documentation so you people other =
than me understand what's going on in the code a little more.

I've tried to move all the calculations upstream as much as possible, =
but it's still only about 7% faster than the original... there's a LONG =
way to go.  On a dual 1.2ghz box, it's taking 30 seconds to sharpen a =
400x600 pixel image!

Iterating over each channel of each pixel in Python is just too slow... =
would trying to implement this type of thing in a C extension (like the =
core _imaging.pyd file) help a lot?  Unfortunately, I'm not much of a C =
programmer.  FRED!!! HELP!!!  q:]

I could do the calculations on a gray-scale version of the file and only =
sharpen based on gray-contrast, but I'd rather not limit it that way... =
(max 3x speed improvement, minus time to create grayscale version of =
image)

The updated version, if anyone can give me a hand is available at:  =
http://www.cazabon.com/python/unsharpMask/UnsharpMaskingModule.py

(and it now can be used for gaussian blurring too, as an added bonus).

Thanks,
Kevin.
  ----- Original Message -----=20
  From: Moodie, Craig CA=20
  To: 'Kevin@Cazabon.com'=20
  Sent: Sunday, March 17, 2002 7:05 PM
  Subject: RE: [Image-SIG] Unsharp Masking?


  Kevin,
      On first inspection I would suggest that you remove as much as is =
physically possible from the inner loop. Put as much as you can into a =
lookup table-----avoid calculations.You should be able to at least get a =
speed increase of 2.
  For example
                          pixNumber =3D ((column + (row * =
image.size[0])) * channels) + c + (xr * channels) + (yr * image.size[0] =
* channels)
                         =20
                          if pixNumber < 0:
                              pixNumber =3D column * channels
                          elif pixNumber > len(imArray) - 1:
                              pixNumber =3D (column + (row * =
image.size[0])) * channels
                             =20
                          pixValue =3D imArray[pixNumber]
                         =20
                          pixWeight =3D pow(weight, (abs(xr) + =
abs(yr)))----------------------->LUT
                          totalValue =3D totalValue + ((origPixel - =
pixValue) * pixWeight)
  the underlined could all be calculated outside the xr,yr loops.
      Cheers
          Craig
    -----Original Message-----
    From: Kevin@Cazabon.com [mailto:kevin@cazabon.com]
    Sent: Monday, March 18, 2002 10:18 AM
    To: image-sig@python.org
    Subject: [Image-SIG] Unsharp Masking?


    Does anyone have a FAST unsharp-masking method for use with PIL?

    I wrote a brute-force module for this in Python today (attached, if =
it gets through the newsgroup filters) that works just fine, but it's =
mighty slow... anyone have something faster?  The built in =
ImageEnhance.Sharpness filter is OK for very basic stuff, but the best =
way to sharpen is through an unsharp-mask type algorithm... it's much =
more powerful and controllable.

    For those that don't know how unsharp masking works, here's the =
basics:

    1)  a copy of the image is blurred using a gaussian-type blurring =
algorighm (this is the 'unsharp' part), with a user-defined radius for =
the blur.

    2)  the blurred image is then compared (pixel by pixel if necessary) =
to the original image

    3)  the amount of difference between the blurred pixel and original =
pixel determines if it is an edge or not.  If the difference is greater =
than the user-specified "threshold", sharpening is performed in step 4)

    4)  the pixel is changed by the OPPOSITE amount of the difference =
between the original and blurred pixels, multiplied by the user-defined =
"percentage"



    Any help is appreciated in speeding this up!

    Kevin Cazabon.


  EOM=20



  NOTICE - This message and any attached files may contain information =
that is confidential and/or subject of legal privilege intended only for =
use by the intended recipient. If you are not the intended recipient or =
the person responsible for delivering the message to the intended =
recipient, be advised that you have received this message in error and =
that any dissemination, copying or use of this message or attachment is =
strictly forbidden, as is the disclosure of the information therein. If =
you have received this message in error please notify the sender =
immediately and delete the message.

------=_NextPart_000_0062_01C1CDFA.2929D510
Content-Type: text/html;
	charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META http-equiv=3DContent-Type content=3D"text/html; =
charset=3Diso-8859-1">
<META content=3D"MSHTML 5.50.4913.1100" name=3DGENERATOR>
<STYLE></STYLE>
</HEAD>
<BODY bgColor=3D#ffffff>
<DIV><FONT face=3DArial size=3D2>I've cleaned it up a bit, and added =
documentation=20
so you&nbsp;people other than me&nbsp;understand what's going on in the =
code a=20
little more.</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>I've tried to move all the calculations =
upstream as=20
much as possible, but it's still only about 7% faster than the =
original...=20
there's a LONG way to go.&nbsp; On a dual 1.2ghz box, it's taking 30 =
seconds to=20
sharpen a 400x600 pixel image!</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>Iterating over each channel of each =
pixel in Python=20
is just too slow... would trying to implement this type of thing in a C=20
extension (like the core _imaging.pyd file) help a lot?&nbsp; =
Unfortunately, I'm=20
not much of a C programmer.&nbsp; FRED!!! HELP!!!&nbsp; q:]</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>I could do the calculations on a =
gray-scale version=20
of the file and only sharpen based on gray-contrast, but I'd rather not =
limit it=20
that way... (max 3x speed improvement, minus time to create grayscale =
version of=20
image)</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>The updated version, if&nbsp;anyone can =
give me a=20
hand is available at:&nbsp; <A=20
href=3D"http://www.cazabon.com/python/unsharpMask/UnsharpMaskingModule.py=
">http://www.cazabon.com/python/unsharpMask/UnsharpMaskingModule.py</A></=
FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>(and it now can be used for gaussian =
blurring too,=20
as an added bonus).</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>Thanks,</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>Kevin.</FONT></DIV>
<BLOCKQUOTE dir=3Dltr=20
style=3D"PADDING-RIGHT: 0px; PADDING-LEFT: 5px; MARGIN-LEFT: 5px; =
BORDER-LEFT: #000000 2px solid; MARGIN-RIGHT: 0px">
  <DIV style=3D"FONT: 10pt arial">----- Original Message ----- </DIV>
  <DIV=20
  style=3D"BACKGROUND: #e4e4e4; FONT: 10pt arial; font-color: =
black"><B>From:</B>=20
  <A title=3DCraig.Moodie@bhpsteel.com=20
  href=3D"mailto:Craig.Moodie@bhpsteel.com">Moodie, Craig CA</A> </DIV>
  <DIV style=3D"FONT: 10pt arial"><B>To:</B> <A =
title=3Dkevin@cazabon.com=20
  href=3D"mailto:'Kevin@Cazabon.com'">'Kevin@Cazabon.com'</A> </DIV>
  <DIV style=3D"FONT: 10pt arial"><B>Sent:</B> Sunday, March 17, 2002 =
7:05=20
PM</DIV>
  <DIV style=3D"FONT: 10pt arial"><B>Subject:</B> RE: [Image-SIG] =
Unsharp=20
  Masking?</DIV>
  <DIV><BR></DIV>
  <DIV><SPAN class=3D055105401-18032002><FONT face=3DArial =
color=3D#0000ff=20
  size=3D2>Kevin,</FONT></SPAN></DIV>
  <DIV><SPAN class=3D055105401-18032002>&nbsp;&nbsp;&nbsp; <FONT =
face=3DArial=20
  color=3D#0000ff size=3D2>On first inspection I would suggest that you =
remove as=20
  much as is physically possible from the inner loop. Put as much as you =
can=20
  into a lookup table-----avoid calculations.You should be able to at =
least get=20
  a speed increase of 2.</FONT></SPAN></DIV>
  <DIV><SPAN class=3D055105401-18032002><FONT face=3DArial =
color=3D#0000ff size=3D2>For=20
  example</FONT></SPAN></DIV>
  <DIV><SPAN class=3D055105401-18032002><FONT face=3DArial =
color=3D#0000ff=20
  =
size=3D2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;=20
  pixNumber =3D (<STRONG>(column + (row * image.size[0])) * channels) + =
c</STRONG>=20
  + (xr * channels) + (yr * image.size[0] *=20
  =
channels)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&=
nbsp;=20
  =
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
  if pixNumber &lt;=20
  =
0:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;=20
  pixNumber =3D <STRONG>column *=20
  =
channels</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;=20
  elif pixNumber &gt; <STRONG>len(imArray) -=20
  =
1</STRONG>:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
  pixNumber <STRONG>=3D (column + (row * image.size[0])) *=20
  =
channels<BR></STRONG>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
  =
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
  pixValue =3D=20
  =
imArray[pixNumber]<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;=20
  =
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
  <STRONG>pixWeight =3D pow(weight, (abs(xr) +=20
  =
abs(yr)))-----------------------&gt;LUT<BR></STRONG>&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
  totalValue =3D totalValue + ((origPixel - pixValue) * =
pixWeight)<BR>the=20
  underlined could all be calculated outside the xr,yr=20
loops.</FONT></SPAN></DIV>
  <DIV><SPAN class=3D055105401-18032002>&nbsp;&nbsp;&nbsp; <FONT =
face=3DArial=20
  color=3D#0000ff size=3D2>Cheers</FONT></SPAN></DIV>
  <DIV><SPAN =
class=3D055105401-18032002>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
  <FONT face=3DArial color=3D#0000ff size=3D2>Craig</FONT></SPAN></DIV>
  <BLOCKQUOTE dir=3Dltr style=3D"MARGIN-RIGHT: 0px">
    <DIV class=3DOutlookMessageHeader dir=3Dltr align=3Dleft><FONT =
face=3DTahoma=20
    size=3D2>-----Original Message-----<BR><B>From:</B> =
Kevin@Cazabon.com=20
    [mailto:kevin@cazabon.com]<BR><B>Sent:</B> Monday, March 18, 2002 =
10:18=20
    AM<BR><B>To:</B> image-sig@python.org<BR><B>Subject:</B> [Image-SIG] =
Unsharp=20
    Masking?<BR><BR></FONT></DIV>
    <DIV><FONT face=3DArial size=3D2>Does anyone have a FAST =
unsharp-masking method=20
    for use with PIL?</FONT></DIV>
    <DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
    <DIV><FONT face=3DArial size=3D2>I wrote a brute-force module for =
this in Python=20
    today&nbsp;(attached, if it gets through the newsgroup =
filters)&nbsp;that=20
    works just fine, but it's mighty slow... anyone have something =
faster?&nbsp;=20
    The built in ImageEnhance.Sharpness filter is OK for very basic =
stuff, but=20
    the best way to sharpen is through an unsharp-mask type algorithm... =
it's=20
    much more powerful and&nbsp;controllable.</FONT></DIV>
    <DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
    <DIV><FONT face=3DArial size=3D2>For those that don't know how =
unsharp masking=20
    works, here's the basics:</FONT></DIV>
    <DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
    <DIV><FONT face=3DArial size=3D2>1)&nbsp; a copy of the image is =
blurred using a=20
    gaussian-type blurring algorighm (this is the 'unsharp' part), with =
a=20
    user-defined radius for the blur.</FONT></DIV>
    <DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
    <DIV><FONT face=3DArial size=3D2>2)&nbsp; the blurred image is then =
compared=20
    (pixel by pixel if necessary) to the original image</FONT></DIV>
    <DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
    <DIV><FONT face=3DArial size=3D2>3)&nbsp; the amount of difference =
between the=20
    blurred pixel and original pixel determines if it is an edge or =
not.&nbsp;=20
    If the difference is greater than the user-specified "threshold", =
sharpening=20
    is performed in step 4)</FONT></DIV>
    <DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
    <DIV><FONT face=3DArial size=3D2>4)&nbsp; the pixel is changed by =
the OPPOSITE=20
    amount of the difference between the original and blurred pixels, =
multiplied=20
    by the user-defined "percentage"</FONT></DIV>
    <DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
    <DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
    <DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
    <DIV><FONT face=3DArial size=3D2>Any help is appreciated in speeding =
this=20
    up!</FONT></DIV>
    <DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
    <DIV><FONT face=3DArial size=3D2>Kevin =
Cazabon.</FONT></DIV></BLOCKQUOTE><BR>
  <P><FONT face=3DArial size=3D2>EOM </FONT></P><BR>
  <P><FONT face=3DArial size=3D2>NOTICE - This message and any attached =
files may=20
  contain information that is confidential and/or subject of legal =
privilege=20
  intended only for use by the intended recipient. If you are not the =
intended=20
  recipient or the person responsible for delivering the message to the =
intended=20
  recipient, be advised that you have received this message in error and =
that=20
  any dissemination, copying or use of this message or attachment is =
strictly=20
  forbidden, as is the disclosure of the information therein. If you =
have=20
  received this message in error please notify the sender immediately =
and delete=20
  the message.</FONT></P></BLOCKQUOTE></BODY></HTML>

------=_NextPart_000_0062_01C1CDFA.2929D510--