Closed charpng closed 1 year ago
Hello, @charpng !
I believe you must re-apply the gamma correction after doing the matrix calculations. Also, can you try reversing the color channels? OpenCV, for example, will give you color channels BGR instead of RGB. The reverse order will interfere with the proper results.
Thank you for your kind advice! I thought image.open () in PIL library of Python opens the Image in RGB instead of BGR, but I just tried to reverse the color channels. I tried converting the image from RGB to BGR or BGR to RGB after reading it in, and the reverse before outputting the results. Either way, the output image changes from blue to red. Actually there`s another question and I wonder if this counts. My codes are as follows: In line 37, I converted the X×Y×3 image to X×3×Y using np.transpose(). This is because the image is read in as a X×Y×3 matrix (X, Y are the vertical and horizontal sizes of the image), and I cannot directly left-multiply the image by T matrix as in article. I wanted to know if this had an impact, and if so how I could do with it.
Thank you very much for taking the time to correct my mistakes.
I don't see the mistake but perhaps I can help more if I can try running the code. Can you try pasting the code in your response instead of pasting images? Refer to the github docs for info on now to do that. The main idea is you can use backticks to make the code look like code instead of regular text.
Yes @hx2A I'm more than happy to upload my code! I uploaded the images because I thought they would be easier to read than text.
import cv2
import numpy as np
from PIL import Image
def RGB_to_lRGB(img):
return np.where(img <= 0.04045*255, (img/255)/12.92 , np.power(((img/255)+0.055)/1.055 , 2.4))
def lRGB_to_RGB(img):
return np.where(img <= 0.0031308 , 255*12.92*img , 255*(np.power(1.055*img,0.41666)-0.055))
T = np.array([[0.31399022 , 0.63951294 , 0.04649755],
[0.15537241 , 0.75789446 , 0.08670142],
[0.01775239 , 0.10944209 , 0.87256922]]) # Matrix T
TI = np.array([[5.47221206 , -4.6419601 , 0.16963708],
[-1.1252419 , 2.29317094 , -0.1678952],
[0.02980165 , -0.19318073 , 1.16364789]]) # Inverse matrix of T
def protanopia() :
return np.array([[0 , 1.05118294 , -0.05116099],
[0, 1, 0],
[0, 0, 1]])
def deutranopia():
return np.array([[1, 0, 0],
[0.9513092 , 0 , 0.04866992],
[0, 0, 1]])
def tritanopia() :
return np.array([[1, 0, 0],
[0, 1, 0],
[-0.86744736 , 1.86727089 , 0]])
def transform(img_path, colorblindnesstype:str):
original_image = np.array(Image.open(img_path))
original_image = cv2.cvtColor(original_image,cv2.COLOR_BGR2RGB)
ori_img_lRGB = RGB_to_lRGB(original_image) ##remove the gamma correction
image_removed_gamma = np.transpose(ori_img_lRGB,(0,2,1))
original_image_lms = T @ image_removed_gamma
if colorblindnesstype == 'protanopia':
trans_matrix = protanopia()
elif colorblindnesstype == 'deutranopia':
trans_matrix = deutranopia()
elif colorblindnesstype == 'tritanopia':
trans_matrix = tritanopia()
img_transformed = trans_matrix @ original_image_lms
img_transformed = TI @ img_transformed
output_img = np.transpose(img_transformed,(0,2,1))
output_img = lRGB_to_RGB(output_img) #re-apply the gamma correction
output_img = cv2.cvtColor(output_img,cv2.COLOR_RGB2BGR)
cv2.imwrite('R to %s output.jpg' %(colorblindnesstype),output_img)
return
img_path = 'R.jpg'
transform(img_path,'protanopia')
transform(img_path,'deutranopia')
transform(img_path,'tritanopia')
I am a student from District 8 East, so please forgive me for not being able to keep in touch for the next few hours
I fixed an error in the function lRGB_to_RGB() as follows, but I still didn't get the correct result. From
res = np.where(img <= 0.0031308 , 255*12.92*img , 255*(np.power(1.055*img,0.41666)-0.055))
to
res = np.where(img <= 0.0031308 , 255*12.92*img , 255*(1.055*(np.power(img,0.41666))-0.055))
@charpng , I found the problem with your code.
The main issue had to do with OpenCV's BGR channels and Pillow's RGB channels. You have to be careful when mixing the two libraries together. To repair your code I removed OpenCV altogether because you don't really need it. Also, I see you read the image file with Pillow but then save it with OpenCV. Saving it with OpenCV was reversing the color channels again. You can save it with Pillow like this:
Image.fromarray(output_img.astype(np.uint8)).save('/tmp/R_to_%s_output.jpg' % (colorblindnesstype))
In the future, if you need to reverse the color channel order, you can do it by reversing the last axis, like this:
img_array = image_array[:, :, ::-1]
Here is the complete code (note I made some other small changes to suit my programming style)
import numpy as np
from PIL import Image
def RGB_to_lRGB(img):
return np.where(img <= 0.04045*255, (img/255)/12.92, np.power(((img/255)+0.055)/1.055, 2.4))
def lRGB_to_RGB(img):
return np.where(img <= 0.0031308, 255*12.92*img, 255*(1.055*(np.power(img, 0.41666))-0.055))
T = np.array([[0.31399022, 0.63951294, 0.04649755],
[0.15537241, 0.75789446, 0.08670142],
[0.01775239, 0.10944209, 0.87256922]]) # Matrix T
TI = np.array([[5.47221206, -4.6419601, 0.16963708],
[-1.1252419, 2.29317094, -0.1678952],
[0.02980165, -0.19318073, 1.16364789]]) # Inverse matrix of T
def protanopia():
return np.array([[0, 1.05118294, -0.05116099],
[0, 1, 0],
[0, 0, 1]])
def deutranopia():
return np.array([[1, 0, 0],
[0.9513092, 0, 0.04866992],
[0, 0, 1]])
def tritanopia():
return np.array([[1, 0, 0],
[0, 1, 0],
[-0.86744736, 1.86727089, 0]])
def transform(img_path, colorblindnesstype: str):
original_image = np.array(Image.open(img_path))
ori_img_lRGB = RGB_to_lRGB(original_image) # remove the gamma correction
image_removed_gamma = np.transpose(ori_img_lRGB, (0, 2, 1))
original_image_lms = T @ image_removed_gamma
if colorblindnesstype == 'protanopia':
trans_matrix = protanopia()
elif colorblindnesstype == 'deutranopia':
trans_matrix = deutranopia()
elif colorblindnesstype == 'tritanopia':
trans_matrix = tritanopia()
img_transformed = trans_matrix @ original_image_lms
img_transformed = TI @ img_transformed
output_img = np.transpose(img_transformed, (0, 2, 1))
output_img = lRGB_to_RGB(output_img) # re-apply the gamma correction
output = Image.fromarray(output_img.astype(np.uint8))
output.save('/tmp/R_to_%s_output.jpg' % (colorblindnesstype))
return output
img_path = '/tmp/R.jpg'
transform(img_path, 'protanopia')
I am a student from District 8 East,
What is District 8 East?
Good luck with your studies, and have fun learning about Python!
Thank you very much for your teaching! I only knew that OpenCV opened the image as BGR, but I didn't know that it also stored the image as BGR. I successfully got the correct result after modifying the code according to your instructions.
As for District 8 East, I just want to express that I am a student from China, so there is jet lag over ten hours, but I didn't make it clear when I expressed it.
You are welcome!
I only knew that OpenCV opened the image as BGR, but I didn't know that it also stored the image as BGR.
I should be a bit more clear here. The PNG image format is exactly the same, regardless of how it is saved. When you open a PNG image with OpenCV, it will by default give you an array with the channel order BGR. If you do the same with Pillow and convert it to an array, the channel order will be RGB. When you save a PNG image with OpenCV, it will assume the channel order of the array you provide it is also BGR. When converting an array to a Pillow image, it will assume the channel order of the array you provide it is RGB.
The channel ordering can be confusing it is better to keep everything RGB within a program. When I use OpenCV to read a webcam, I always switch the channel order right away to RGB with [:, :, ::-1]
. That keeps everything consistent and avoids these kinds of headaches.
I'm trying content repetition blindness simulation through the following url https://ixora.io/projects/colorblindness/color-blindness-simulation-research/
According to the content of the website, I
But the output image I got was not ideal. Compared to the effect image you gave in the article, the image I got was more blue, which confused me very much and I hope you can point out my mistake.
Here are pictures of the results of my simulation of deutranopia color blindness: