clifgray
clifgray

Reputation: 4419

Multiply each pixel in an image by a factor

I have an image that is created by using a bayer filter and the colors are slightly off. I need to multiply RG and B of each pixel by a certain factor ( a different factor for R, G and B each) to get the correct color. I am using the python imaging library and of course writing in python. is there any way to do this efficiently?

Thanks!

Upvotes: 3

Views: 17525

Answers (6)

Mark Setchell
Mark Setchell

Reputation: 207445

You can do this pretty efficiently and simply using a simple transform matrix with the convert() function:

#!/usr/bin/env python3 

from PIL import Image 

# Open image 
im = Image.open('tree.jpg') 

# Make transform matrix, to multiply R by 1.5, leaving G and B unchanged
Matrix = ( 1.5, 0,  0, 0, 
           0,   1,  0, 0, 
           0,   0,  1, 0) 

# Apply transform and save 
im = im.convert("RGB", Matrix) 
im.save('result.png') 

Input image:

enter image description here

Result image:

enter image description here


You can read that matrix as saying:

newRed   = 1.5*oldRed + 0.0*oldGreen + 0.0*oldGreen + 0.0
newGreen = 0.0*oldRed + 1.0*oldGreen + 0.0*oldBlue  + 0.0
newBlue  = 0.0*oldRed + 0.0*oldGreen + 1.0*oldBlue  + 0.0

Keywords: Python, PIL, Pillow, color matrix, colour matrix, transform, multiply channel, scale channel, separate, separately, individual channels, bands, components, individually, split channels, merge channels, image, image processing.

Upvotes: 7

DomagojM
DomagojM

Reputation: 101

If the type is numpy.ndarray just img = np.uint8(img*factor)

Upvotes: 0

fraxel
fraxel

Reputation: 35269

Here is how to do it:

  1. First split your image into the RGB channels.
  2. Use point to multiply a channel by factor (1.5 in the example, on the r channel).
  3. Merge the channels back.

Heres the code:

import Image
im = Image.open('1_tree.jpg')
im = im.convert('RGB')
r, g, b = im.split()
r = r.point(lambda i: i * 1.5)
out = Image.merge('RGB', (r, g, b))
out.show()

original:

enter image description here

With the red channel multiplied by 1.5 (its a bit redder..):

enter image description here

Upvotes: 10

Mark Ransom
Mark Ransom

Reputation: 308140

You can use .split to split the image into a separate image for each of the three channels, .eval as suggested by astynax, and Image.merge to put them back together.

If any of your multiplication factors are greater than 1, be sure to clamp the output to 255.

Upvotes: 1

Aleksei astynax Pirogov
Aleksei astynax Pirogov

Reputation: 2491

From documentation:

from PIL import Image
Image.eval(image, function) => image

Applies the function (which should take one argument) to each pixel in the given image. If the image has more than one band, the same function is applied to each band. Note that the function is evaluated once for each possible pixel value, so you cannot use random components or other generators.

Upvotes: 1

Matt Coughlin
Matt Coughlin

Reputation: 18906

As a basic optimization, it may save a little time if you create 3 lookup tables, one each for R, G, and B, to map the input value (0-255) to the output value (0-255). Looking up an array entry is probably faster than multiplying by a decimal value and rounding the result to an integer. Not sure how much faster.

Of course, this assumes that the values should always map the same.

Upvotes: 2

Related Questions