输入的图像一般都是RGB三层,但是红眼区域的定义是在HSI空间上进行定义,因此需要存在两个函数将图像数据在RGB空间与HSI空间进行转换,而转换的公式如下图所示:
原始图片数据:
实验代码:
import math
import cv2
import numpy as np
global img, ans
global point1, point2
readroad = '.\\data\\'
saveroad = '.\\ans\\'
picname = 'cateye.jpg'
# picname ='12031565.jpg'
# picname = 'child-red eye.jpg'
def rgb2hsi(R, G, B):
m = R - (G + B) / 2
n = cv2.multiply(R - G, R - G) + cv2.multiply(R - B, G - B)
theta = np.zeros([R.shape[0], R.shape[1]])
eps = 0.000001 # 定义一个微小量,避免出现分母为0至分式错误
# 下面按照公式进行变换
for i in range(R.shape[0]):
for j in range(R.shape[1]):
theta[i, j] = math.acos(m[i, j] / math.sqrt(n[i, j] + eps))
H = theta.copy()
mid = B > G
H[mid] = 2 * math.pi - theta[mid] # 给HSI空间中的H赋值
S = np.zeros([R.shape[0], R.shape[1]])
for i in range(R.shape[0]):
for j in range(R.shape[1]):
S[i, j] = 1 - (3 * min(R[i, j], G[i, j], B[i, j]) / (R[i, j] + G[i, j] + B[i, j] + eps)) # 给HSI空间中的S赋值
I = (R + G + B) / 3 # 给HSI空间中的I赋值
return H, S, I
def hsi2rgb(H, S, I):
mid = math.pi * 2 / 3 # 首先将120度转换为弧度制便于判定
R = np.zeros([H.shape[0], H.shape[1]]) # 初始化R,G,B矩阵
G = np.zeros([H.shape[0], H.shape[1]])
B = np.zeros([H.shape[0], H.shape[1]])
for i in range(H.shape[0]):
for j in range(H.shape[1]):
# 以下按情况进行分类讨论
if H[i, j] <= mid:
R[i, j] = I[i, j] * (1 + S[i, j] * math.cos(H[i, j]) / math.cos(0.5 * mid - H[i, j]))
B[i, j] = I[i, j] * (1 - S[i, j])
G[i, j] = 3 * I[i, j] - (R[i, j] + B[i, j])
elif (H[i, j] <= mid * 2) and H[i, j] > mid:
H[i, j] = H[i, j] - mid
G[i, j] = I[i, j] * (1 + S[i, j] * math.cos(H[i, j]) / math.cos(0.5 * mid - H[i, j]))
R[i, j] = I[i, j] * (1 - S[i, j])
B[i, j] = 3 * I[i, j] - (R[i, j] + G[i, j])
elif (H[i, j] <= mid * 3) and H[i, j] > mid * 2:
H[i, j] = H[i, j] - mid * 2
B[i, j] = I[i, j] * (1 + S[i, j] * math.cos(H[i, j]) / math.cos(0.5 * mid - H[i, j]))
G[i, j] = I[i, j] * (1 - S[i, j])
R[i, j] = 3 * I[i, j] - (B[i, j] + G[i, j])
return R, G, B
def on_mouse(event, x, y, flags, param):
global img, ans, point1, point2
img1 = img.copy()
if event == cv2.EVENT_LBUTTONDOWN: # 左键点击
point1 = (x, y) # 获取一个角点坐标
cv2.circle(img1, point1, 10, (0, 255, 0), 1)
cv2.imshow('image', img1)
elif event == cv2.EVENT_MOUSEMOVE and (flags & cv2.EVENT_FLAG_LBUTTON): # 按住左键拖曳
cv2.rectangle(img1, point1, (x, y), (255, 0, 0), 1)
cv2.imshow('image', img1)
elif event == cv2.EVENT_LBUTTONUP: # 左键释放
point2 = (x, y) # 获取对角角点坐标
cv2.rectangle(img1, point1, point2, (0, 0, 255), 1)
cv2.imshow('image', img1)
img2 = ans.astype(np.int32) # 转换数据类型方便进行运算
# 注意读入的图像三层分别对应RGB空间的B,G,R
H, S, I = rgb2hsi(img2[:, :, 2], img2[:, :, 1], img2[:, :, 0])
min_x = min(point1[0], point2[0]) # 获取待处理区域信息
min_y = min(point1[1], point2[1])
width = abs(point1[0] - point2[0])
height = abs(point1[1] - point2[1])
# 按照红眼定义在指定区域进行去红眼处理
for i in range(min_y, min_y + height + 1):
for j in range(min_x, min_x + width + 1):
# m,n=H[i, j],S[i, j]
if (H[i, j] < math.pi / 4) or H[i, j] > math.pi * 7 / 4:
if S[i, j] > 0.25:
S[i, j] = 0
R, G, B = hsi2rgb(H, S, I)
# 构造去红眼的结果影像
mid = np.zeros([R.shape[0], R.shape[1], 3])
mid[:, :, 0] = B
mid[:, :, 1] = G
mid[:, :, 2] = R
ans = mid.astype(np.uint8) # 转换数据类型方便结果展示与保存
cv2.imshow('image1', ans)
cv2.imwrite(saveroad + picname + '_outred.jpg', ans)
def main():
global img, ans
img = cv2.imread(readroad + picname)
ans = img.copy()
cv2.namedWindow('image')
cv2.setMouseCallback('image', on_mouse)
cv2.imshow('image', ans)
cv2.waitKey(0)
if __name__ == '__main__':
main()
实验结果展示: