When I was searching internet for an algorithm to correct luminance I came across this article about prospective correction and retrospective correction. I’m mostly interested in the prospective correction. Basically we take pictures of the scene with image in it(original one), and two other ,one bright and one dark, pictures where we only see the background of the original picture.
My problem is that I couldn’t find any adaptation of these formulas in openCV or code example. I tried to use the formulas as they were in my code but this time I had a problem with data types. This happened when I tried to find C constant by applying operations on images.
This is how I implemented the formula in my code:
def calculate_C(im, im_b): fx_mean = cv.mean(im) fx_over_bx = np.divide(im,im_b) mean_fx_bx = cv.mean(fx_over_bx) c = np.divide(fx_mean, mean_fx_bx) return c #Basic image reading and resizing # Original image img = cv.imread(image_path) img = cv.resize(img, (1000,750)) # Bright image b_img = cv.imread(bright_image_path) b_img = cv.resize(b_img, (1000,750)) # Calculating C constant from the formula c_constant = calculate_C(img, b_img) # Because I have only the bright image I am using second formula from the article img = np.multiply(np.divide(img,b_img), c_constant)
When I try to run this code I get the error:
img = np.multiply(np.divide(img,b_img), c_constant) ValueError: operands could not be broadcast together with shapes (750,1000,3) (4,)
So, is there anything I can do to fix my code? or is there any hints that you can share with me to handle luminance correction with this method or better methods?
Advertisement
Answer
You are using cv2.mean function which returns array with shape (4,) – mean value for each channel. You may need to ignore last channel and correctly broadcast it to numpy.
Or you could use numpy for calculations instead of opencv.
I just take example images from provided article.
grain.png:
grain_background.png:
Complete example:
import cv2 import numpy as np from numpy.ma import divide, mean f = cv2.imread("grain.png") b = cv2.imread("grain_background.png") f = f.astype(np.float32) b = b.astype(np.float32) C = mean(f) / divide(f, b).mean() g = divide(f, b) * C g = g.astype(np.uint8) cv2.imwrite("grain_out.png", g)
Your need to use masked divide operation because ordinary operation could lead to division by zero => nan values.
Resulting image (output.png):