1

I'm trying to emulate the linear invert function in GIMP with opencv and python. I can't find more information on how that function has been implemented, besides it being used under linear light.Since I read that opencv imports linear BGR images, I proceeded to trying normal inversion on a RGB opencv but I can only replicate the common inversion method on GIMP.

Inversion function:

def negative(image):
    img_negative = (255-image)
    return img_negative

Original

Original

Linear Inverted (Negative) Image on GIMP

What I want

Inverted (Negative) Image on GIMP

What I'm getting in opencv

Any insight would be appreciated.

3
  • it is useful to know how are you actually doing the inverted image in OpenCV?
    – api55
    Commented Aug 18, 2018 at 12:49
  • I just included the function now Commented Aug 18, 2018 at 13:03
  • 1
    You can convert to linear RGB, use the same formula to invert, then convert back to sRGB using formulae here entropymine.com/imageworsener/srgbformula Commented Aug 18, 2018 at 14:26

2 Answers 2

4

It took a little bit of trial and error, but in addition to you inverting the image, you also have to do some scaling and translation as well.

What I did specifically was in addition to inverting the image, I truncated any values that were beyond intensity 153 for every channel and saturated them to 153. After using this intermediate output, I shift the range such that the lowest value gets mapped to 102 and the highest value gets mapped to 255. This is simply done by adding 102 to every value in the intermediate output.

When I did that, I got a similar image to the one you're after.

In other words:

import cv2
import numpy as np

im = cv2.imread('input.png') # Your image goes here
im_neg = 255 - im
im_neg[im_neg >= 153] = 153 # Step #1
im_neg = im_neg + 102 # Step #2
cv2.imshow('Output', np.hstack((im, im_neg)))
cv2.waitKey(0)
cv2.destroyWindow('Output')

Thankfully, the minimum and maximum values are 0 and 255 which makes this process simpler. I get this output and note that I'm concatenating both images together:

enter image description here

Take note your desired image is stored in im_neg. If you want to see just the image by itself:

enter image description here

Compared to yours:

It's not exactly what you see in the output image you provide, especially because there seems to be some noise around the coloured squares, but this is the closest I could get it to and one could argue that the result I produced is better perceptually.

Hope this helps!

6
  • 1
    Thank you very much! I personally couldn't find the relation between the two inverted images. Closest I came was through image exposure but I couldn't get it to look this similar. Thanks again. Commented Aug 18, 2018 at 17:37
  • You're very welcome. It occurred to me that some sort of linear transform was used because when you invert the image, the white regions should be black, but in the GIMP output image they were gray. I figured there has to be some offsetting and scaling done to get that result.
    – rayryeng
    Commented Aug 18, 2018 at 17:42
  • What is the meaning of that gray value then? Why does white map to an intermediate gray value and not black? Does that help perceptually, or is there some other reasoning? Commented Aug 18, 2018 at 19:09
  • @CrisLuengo The truncation of the values that I did squashes any values that are larger than 153 to 153. After, I shift everything by 102, which means that any black pixels in the inverted image (0, 0, 0) get transformed to (102, 102, 102). Seeing gray in the inverted output led me to the conclusion that the dynamic range of the RGB values was truncated and shifted.
    – rayryeng
    Commented Aug 18, 2018 at 19:10
  • 1
    @CrisLuengo I honestly have no idea. I suppose they did this shifting to make dark values a bit brighter so you can see everything but I honestly am not sure of their rationale behind doing it this way and why there's no proper documentation about the process.
    – rayryeng
    Commented Aug 18, 2018 at 19:14
0

Gimp as of 2.10 works in linear color space and if you look at the original source code for the function it's just bitwise not. SO, here's what the code should look like in opencv-python:

import numpy as np
import cv2

#https://www.pyimagesearch.com/2015/10/05/opencv-gamma-correction/

def adjust_gamma(image, gamma=1.0):
    # build a lookup table mapping the pixel values [0, 255] to
    # their adjusted gamma values
    invGamma = 1.0 / gamma
    table = np.array([((i / 255.0) ** invGamma) * 255
        for i in np.arange(0, 256)]).astype("uint8")

    # apply gamma correction using the lookup table
    return cv2.LUT(image, table)

def invert_linear(img):
    x= adjust_gamma(img, 1/2.2)
    x= cv2.bitwise_not(x)
    y=  adjust_gamma(x, 2.2)

    return y



Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.