数字图像处理——红眼去除(Python)

输入的图像一般都是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()

实验结果展示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值