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:
Take note your desired image is stored in im_neg
. If you want to see just the image by itself:
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!