运用OpenCV对图像进行红眼校正

      • 为什么照片中会出现红眼现象?
      • 如何自动去红眼?
        • 步骤1:人眼检测
        • 步骤2:遮蔽红眼区
        • 步骤3:红眼处理
        • 步骤4:显示结果

大家有没有碰到过用照相机拍出来照片会出现红眼,是不是感觉有点邪恶,那么这是为什么呢?

为什么照片中会出现红眼现象?

在光线昏暗或者晚上,瞳孔往往由于光线不足而扩大。随着照相机闪光灯的闪烁,瞳孔没有来得及反应(缩小),因此而导致一束强光线射到视网膜又反射到照相机的镜头上。在眼球的背面有一层膜叫脉络膜,里面充满了血液,所以反射出来的颜色就是红色的。

大多数照相机都有一个设置,闪光灯会在拍照之前闪几下让瞳孔有时间快速调节到合适的大小。
这里有更好的方式就是通过图像处理来去除红眼现象。

如何自动去红眼?

步骤1:人眼检测

这里采用标准的OpenCV Haar 检测器(haarcascade_eye.xml)来实现人眼检测。
要让事情简单一点,最好图像只是一幅肖像或者眼睛的特写。
代码如下:

import cv2
import numpy as np

#read image
img = cv2.imread("testImg1.jpg") # pass the name of image to be read

outImage = img.copy()
# Load HAAR cascade
eyesCascade = cv2.CascadeClassifier("haarcascade_eye.xml")

#------------ Detect Eyes ------------#
# eyeRects contain bounding rectangle of all detected eyes

eyeRects = eyesCascade.detectMultiScale(img , 1.1, 5 )

步骤2:遮蔽红眼区

接下来需要找到导致红眼现象的瞳孔区域。
简单起见,可以认为红色通道应该大于某个阈值,同样蓝色和绿色通道也是。
对每个眼睛所处矩形区域逐个处理,去除红眼。

#Iterate over all eyes to remove red eye defect

for x,y,w,h in eyeRects:

    #Crop the eye region
    eyeImage = img [y:y+h , x:x+w]

    #split the images into 3 channels
    b, g ,r = cv2.split(eyeImage)

    # Add blue and green channels
    bg = cv2.add(b,g)

    #threshold the mask based on red color and combination ogf blue and gree color
    mask = ( (r>(bg-20)) & (r>80) ).astype(np.uint8)*255
  • 裁剪眼睛区域图像
  • 将图像分解成3个通道(注意OpenCV默认存储图像的格式是BGR)
  • 通过添加蓝色和绿色通道创建一个新图像(bg)
  • 创建红色区域掩码(可以使用阈值)
    这里写图片描述

    掩码区域可能包含一些不希望出现的区域。接下来可以找到所有不同的连通区域。
#find all contours
    contours, _ = cv2. findContours(mask.copy() ,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE )  # It return contours and Hierarchy

    #find contour with max Area
    maxArea = 0
    maxCont = None
    for cont in contours:
        area = cv2.contourArea(cont)
        if area > maxArea:
            maxArea = area
            maxCont = cont
    mask = mask * 0  # Reset the mask image to complete black image
    # draw the biggest contour on mask
    cv2.drawContours(mask , [maxCont],0 ,(255),-1 )
    #Close the holes to make a smooth region
    mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, cv2.getStructuringElement(cv2.MORPH_DILATE,(5,5)) )
    mask = cv2.dilate(mask , (3,3) ,iterations=3)
  • 查找所有轮廓
  • 找到面积最大的轮廓
  • 清除掩码图像
  • 画出轮廓区域
  • 掩码图像可能包含一些空心区域,用形态学闭操作来填充空心区域
  • 对掩码图像进行形态学膨胀操作,使得瞳孔其它区域被覆盖(因为外部边界可能无法检测到)
    这里写图片描述

步骤3:红眼处理

这样就产生了一个完美的掩码,它包含了眼睛中只有红色的区域。既然y通道的信息丢失了,那最好的方法就是是从另外两个通道(蓝色和绿色)来还原信息。

好一点的方式就是利用蓝色和绿色通道的平均值来获得纹理,并用所有的三个通道替换它,这将使瞳孔颜色变得深暗一些。

步骤4:显示结果

在前面的步骤中,我们处理了眼睛区域的图像,下面是将两幅图拼接后放在一起进行比较(原始的和经过红眼校正的)。

# Stack both input and output image horizontally
result = np.hstack((img,outImage))
#Display the Result
cv2.imshow("RedEyeCorrection" , result )
cv2.waitKey() # Wait for a keyPress
cv2.destroyAllWindows()

运用OpenCV对图像进行红眼校正_第1张图片

看起来感觉是不是很棒?
如果你想亲手尝试一下校正红眼的过程,要下载代码,可以点击 这里。

阅读本文,你需要对Python 和 OpenCV 非常熟悉,大多数情况下代码就是最好的注释,如果有任何疑问都可以评论的方式提出来。

原文来自:
https://pytech-solution.blogspot.hk/2017/04/red-eye-correction-from-image-using.html?spref=gp

你可能感兴趣的:(人工智能)