views:

629

answers:

5

I have two JPEG's and would like to overlay one on the other with the same results as the "Luminosity" mode available in Photoshop (and Fireworks). You can read more about Luminosity mode here: http://www.adobetutorialz.com/articles/662/1/Photoshop%92s-Luminosity-Mode

How can I do this? Programming language doesn't matter much, but I am most fluent with Python and PHP (in that order). Python Imaging Library seems like a perfect fit, but luminosity is not a built-in function and I do not know the proper procedure. See http://www.pythonware.com/library/pil/handbook/imagechops.htm

A: 

The Gimp would be another option - it has a scripting interface ans a python api - here is an article on luminosity and the Gimp. Not sure if it is the same effect you are going for though.

Shane C. Mason
Probably not your fault, but that URL isn't accessible.
Matthew Wensing
+5  A: 

First you need to understand what Photoshop does.

It preserves under layer perceptual color information and replaces it's luminosity with the top layer's perceptual luminosity information. To do that, you need to convert the images to the right color space.

Here is the shoping list of things you will need to do if you decide to implement everything by yourself:

  • Load both the source and target JPEGs
  • Convert the pixels from RGB color space to L*a*b color space (or any other color space with luminosirty information)
  • Preserve target color channels and replace its luminosity channel by source's luminosity
  • Convert back to RGB space
  • Save the JPEG

If you think Lab is too complicated, you can also use HSL color space, it's much simpler but it will give inferior results.

Coincoin
+1  A: 

In pseudo-code:

foreach rgb_pixel1, rgb_pixel2 in image1, image2 {
    hsl1 = RgbToHsl(rgb_pixel1);
    hsl2 = RgbToHsl(rgb_pixel2);
    hsl3 = hsl(hsl1.h, hsl1.s, hsl2.l);
    output_rgb = HslToRgb(hsl3);
}

Conversion from rgb to hsl and back is here.

plinth
I think I'm going to try this first. Another commenter said HSL quality is inferior, but I'd like to judge that before I spend any extra time. PIL doesn't support HSL, but apparently I can get HSL values for an RGB pixel using colorsys: http://effbot.org/zone/pil-hsl.htm
Matthew Wensing
A: 

You could have a look at the OpenCV image processing library. It has Python bindings and handles a lot of these lower level image manipulation tasks for you, or at least makes them easier.

pix0r
+1  A: 

I don't know about this specific filter but I can tell you how to follow Coincoin steps in PIL. I didn't actually run the code, but you can use it as a reference:

Load both the source and target JPEGs

from PIL import Image
img1 = Image.open('image1.jpg')
img2 = Image.open('image2.jpg')

Convert the pixels from RGB color space to L*a*b color space (or any other color space with luminosirty information)

# Color matrix for Lab
colorMatrix = (
    x1, y1, z1, 0,
    x2, y2, z2, 0,
    x3, y3, z3, 0
)
img1 = img1.convert("RGB", colorMatrix)
img2 = img2.convert("RGB", colorMatrix)

Preserve target color channels and replace its luminosity channel by source's luminosity

l1, a1, b1 = img1.split()
l2, a2, b2 = img2.split()
img1.putdata(zip(l1.getdata(), a2.getdata(), b2.getdata()))

Convert back to RGB space

# Color matrix for RGB
RGBcolorMatrix = (
    x1, y1, z1, 0,
    x2, y2, z2, 0,
    x3, y3, z3, 0
)
img1 = img1.convert("RGB", RGBcolorMatrix)

Save the JPEG

img1.save('new_image.jpg')
Nadia Alramli
Wow. THANK YOU.
Matthew Wensing
Actually ... hate to say it, but can you explain the colorMatrix piece with x1, y1, z1? Obviously Python won't allow that since those are undefined at compile-time. What vals am I supposed to be using in place of those in your pseudo-code?
Matthew Wensing
You see this page for more details about the convert function and how to use it http://www.pythonware.com/library/pil/handbook/image.htm
Nadia Alramli
You should be able to get the matrix value from a reference.
Nadia Alramli
If you can't find a conversion matrix then you can use the point function. You can use it like this: img.point(rgb2labfunction)
Nadia Alramli
Nadia, the img1.putdata(zip(l1, a2, b2)) line doesn't work because l1 is an Image instance, and the first argument to zip must support iteration. Hrm.
Matthew Wensing
ah, I'll update the post and fix it.
Nadia Alramli
I updated the code. It'll work now. I'm using getdata() to get the image pixel colors.
Nadia Alramli