参考:https://github.com/spmallick/learnopencv


使用OpenCV的自动红眼删除(C ++ / Python)

在本教程中,我们将学习如何完全自动地从照片中删除红眼。

建立一个强大的红眼消除应用程序,将在各种图像工作超出了这篇文章的范围。但是,我们将学习基本原理,并构建概念应用的证明。

什么原因导致闪光摄影中的红眼效应?

当你在一个黑暗的房间里,你的瞳孔会扩大(放大)让更多的光线让你看得更清楚。 大多数相机的闪光灯非常接近镜头。 当您用闪光灯拍摄照片时,闪光灯的光线通过放大的瞳孔到达眼球的后部,并通过瞳孔返回到相机的镜头。 眼球的后面叫做眼底。 由于眼底充足的血液供应,呈红色。

眼底的图像显示在左边。 检查眼底可以揭示很多关于一个人的健康状况。 你甚至可以得到智能手机应用程序,帮助你看附件的眼底。

大多数相机闪烁这几天闪烁几秒钟,使瞳孔收缩,从而减少红眼的可能性。

要轻松地按照下面的文章,请在这里订阅并下载代码。

如何自动删除红眼?

在本节中,我们将逐步介绍用于自动消除红眼的算法。

第1步:眼睛检测

第一步是自动检测眼睛。 我们使用标准的OpenCV Haar探测器(haarcascade_eye.xml)来寻找眼睛。 有时,首先运行人脸检测器,然后检测人脸区域内的眼睛是有意义的。 为了简单起见,我们直接在图像上运行眼睛检测器。 当输入的图像是人像照片时,跳过人脸检测器工作,或者您有一个特写的眼睛。

您也可以按照这里的说明来训练您自己的HAAR物体探测器。

我在下面分享眼睛检测器的代码。

C++

// Read image
Mat img = imread("red_eyes.jpg",CV_LOAD_IMAGE_COLOR);// Output image
Mat imgOut = img.clone();// Load HAAR cascade
CascadeClassifier eyes_cascade("haarcascade_eye.xml");// A vector of Rect for storing bounding boxes for eyes.
std::vector<Rect> eyes;// Detect eyes.
eyesCascade.detectMultiScale( img, eyes, 1.3, 4, 0 | CASCADE_SCALE_IMAGE, Size(100, 100) );

Python

# Read image
img = cv2.imread("red_eyes.jpg", cv2.IMREAD_COLOR)# Output image
imgOut = img.copy()# Load HAAR cascade
eyesCascade = cv2.CascadeClassifier("haarcascade_eye.xml")# Detect eyes
eyes = eyesCascade.detectMultiScale(img,scaleFactor=1.3, minNeighbors=4, minSize=(100, 100))

第2步:掩蔽红色的眼睛

接下来,我们需要找到受红眼影响的那部分瞳孔。有很多不同的方式来找到红色的东西。有一点要注意的是,我们的颜色不只是红色,它是鲜红的!您可以将图像转换为HSV色彩空间和基于色调和亮度的阈值。在这篇文章中,我们使用了一个更简单的启发式。我们说他的红色通道应该大于一个门槛,也是绿色和蓝色通道的总和。对于概念验证系统来说,启发式就足够了,但是如果要为商业软件包构建自动防红眼系统,则需要收集成千上万的红眼图片才能找到更好的东西。

在下面的代码中,我们循环遍历前一步检测到的所有眼睛矩形。然后我们使用命令split将彩色图像分成三个通道。最后,我们为红色通道高于阈值(150)并且红色通道大于绿色和蓝色通道总和的每个像素创建一个mask。

C++

for( size_t i = 0; i &lt; eyes.size(); i++ )
{// Extract eye from the image.Mat eye = img(eyes[i]);// Split eye image into 3 channels.vector<Mat>bgr(3);split(eye,bgr);// Simple red eye detectorMat mask = (bgr[2] > 150) &amp; (bgr[2] &gt; ( bgr[1] + bgr[0] ));
}

Python

for (x, y, w, h) in eyes:# Extract eye from the image.eye = img[y:y+h, x:x+w]# Split eye image into 3 channelsb = eye[:, :, 0]g = eye[:, :, 1]r = eye[:, :, 2]# Add the green and blue channels. bg = cv2.add(b, g)# Simple red eye detectormask = (r > 150) &  (r > bg)# Convert the mask to uint8 format. mask = mask.astype(np.uint8)*255

第3步:清理瞳孔mask

上一步创建的mask很可能会有空洞。 上图中的左图显示了使用颜色处理获得的原始mask。 我们已经使用下面分享的代码删除了掩码中的洞。 要了解更多关于它的工作原理,你可以看看我的帖子填充孔。

C++

void fillHoles(Mat &amp;mask)
{Mat mask_floodfill = mask.clone();floodFill(mask_floodfill, cv::Point(0,0), Scalar(255));Mat mask2;bitwise_not(mask_floodfill, mask2);mask = (mask2 | mask);}

Python

def fillHoles(mask):maskFloodfill = mask.copy()h, w = maskFloodfill.shape[:2]maskTemp = np.zeros((h+2, w+2), np.uint8)cv2.floodFill(maskFloodfill, maskTemp, (0, 0), 255)mask2 = cv2.bitwise_not(maskFloodfill)return mask2 | mask

此外,扩大mask是一个好主意,因此它覆盖了一个稍大于必要的区域。 这是因为在边界,颜色逐渐消失,在我们原来的面具中可能没有发现一些发红。 在上图中,正确的图像是扩大的面具。 我们使用下面分享的代码生成扩张的mask。

C++

// Clean up mask by filling holes and dilating
fillHoles(mask);
dilate(mask, mask, Mat(), Point(-1, -1), 3, 1, 1);

Python

# Clean up mask by filling holes and dilating
mask = fillHoles(mask)
mask = cv2.dilate(mask, None, anchor=(-1, -1), iterations=3, borderType=1, borderValue=1)

第4步:修复红眼

现在我们有一个只包含每只眼睛的红色区域的mask。 接下来我们将展示如何处理这个mask内的区域来修复红色的眼睛。

我们知道,红色的眼睛饱和了图像中的红色通道。 换句话说,红色通道中的所有信息都被破坏了。 我们怎样才能恢复这些信息呢? 在固定红眼时,我们不需要在红色通道中检索真正的底层纹理; 我们只需要找到一个合理的纹理。

幸运的是,红眼效果只会在红色通道中破坏纹理; 蓝色和绿色的渠道还是不错的。 您可以在下图中看到图像的红色,绿色和蓝色通道。

绿色和蓝色通道的组合可以用来提出一个合理的红色通道。 例如,我们可以创建一个红色通道,它是图像中绿色和蓝色通道的平均值。 然而,这样做可能会给瞳孔一点点色彩,可能看起来不错,但不是很好。 注意中间图像中的紫色色调。

这给我们带来了一个重要的问题。 瞳孔的颜色应该是什么? 瞳孔是眼睛的开口,眼睛内部是完全黑暗的。 因此,瞳孔应该是无色的(灰度)和黑暗的。 我们不是只替换瞳孔区域的红色通道,而是用绿色和蓝色通道的平均值替换所有的通道。 这消除了紫色的色调。

下面的代码首先通过平均绿色和蓝色通道来创建平均通道。 然后用这个平均通道代替所有通道掩蔽区域内的所有像素。

C++

// Calculate the mean channel by averaging
// the green and blue channels
Mat mean = (bgr[0]+bgr[1])/2;// Copy the mean image to blue channel with mask.
mean.copyTo(bgr[0], mask);// Copy the mean image to green channel with mask.
mean.copyTo(bgr[1], mask);// Copy the mean image to red channel with mask.
mean.copyTo(bgr[2], mask);

Python

# Calculate the mean channel by averaging
# the green and blue channels. Recall, bg = cv2.add(b, g)
mean = bg / 2
mask = mask.astype(np.bool)[:, :, np.newaxis]
mean = mean[:, :, np.newaxis]# Copy the eye from the original image.
eyeOut = eye.copy()# Copy the mean image to the output image.
np.copyto(eyeOut, mean, where=mask)

第5步:更换固定的眼睛区域

在前一步,我们已经固定了三个通道。 最后一步是合并三个通道来创建RGB图像,然后将这个固定的眼睛区域放回到原始图像中。

C++

// Merge the three channels
Mat eyeOut;
merge(bgr,eyeOut);// Copy the fixed eye to the output image.
eyeOut.copyTo(imgOut(eyes[i]));

Python

# Copy the fixed eye to the output image.
imgOut[y:y+h, x:x+w, :] = eyeOut

自动红眼消除结果

完整代码

learn opencv-使用OpenCV的自动红眼删除相关推荐

  1. OpenCV实现照片自动红眼去除

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 OpenCV实现照片自动红眼去除 使用闪光照相机拍照,在光线条件不 ...

  2. python Opencv和pyautogui实现自动识图点击

    python Opencv和pyautogui实现自动识图点击 1.导入python及其他模块 匹配类是上一章博客内容,pyautogui自带的图片匹配效果不是很理想.就使用Opencv的图片匹配来实 ...

  3. 基于Python与OpenCV的纸质票自动统计功能的实现(一)界面编程

    基于Python与OpenCV的纸质票自动统计功能的实现(一)--界面编程 作为一个资深的自动化工程师,界面编程对我来说太熟悉不过了,但是当时用的都是工业界面编程软件,比如WINCC.组态王等等,在这 ...

  4. 如何在ARM开发板上从源码编译安装OpenCV和OpenCV contrib

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 本文主要介绍如何在ARM开发板上从源码编译安装OpenCV和OpenCV contrib. OpenC ...

  5. vs2017python配置opencv_[opencv +VS2017] opencv、vs2017安装配置,环境搭建

    文章目录 [opencv] 3.4.1下载安装 一.前言 二.说明 三.下载opencv 3.1 获取链接 3.2 下载结果 四.安装opencv 五.配置opencv环境 六.vs2017 6.1下 ...

  6. [opencv +VS2017] opencv、vs2017安装配置,环境搭建

    文章目录 [opencv] 3.4.1下载安装 一.前言 二.说明 三.下载opencv 3.1 获取链接 3.2 下载结果 四.安装opencv 五.配置opencv环境 六.vs2017 6.1下 ...

  7. CV之OpenCV:OpenCV库涉及概念、常见函数、常用案例、HALCON软件简介之详细攻略

    CV之OpenCV:OpenCV库涉及概念.常见函数.常用案例.HALCON软件简介之详细攻略 目录 CV入门 OpenCV使用过程 1.基本教程 OpenCV的相关概念 1.基本概念

  8. mysql 删除5天前 备份_mysql自动备份删除5天前的备份

    1.查看磁盘空间情况: df -h 2.创建备份目录: 上面我们使用命令看出/home下空间比较充足,所以可以考虑在/home保存备份文件: cd /home mkdir backup cd back ...

  9. 【OpenCV】OpenCV介绍及C++环境配置

    文章目录 OpenCV介绍 Windows OpenCV环境配置 OpenCV介绍 OpenCV是一个跨平台计算机视觉和机器学习软件库,可以运行在Linux.Windows.Android和Mac O ...

最新文章

  1. 「AI初识境」什么是深度学习成功的开始?参数初始化
  2. Exchange 2003 迁移至 Exchange 2010 完全攻略(二)
  3. CSS和JS样式属性对照表
  4. mysql 出现Cannot delete or update a parent row: a...
  5. 计算机组成原理手动在线模式,实验四计算机组成原理 运算器手动实验
  6. php构造函数里抛出异常_php-在类的构造函数中返回值
  7. linux shell trap的使用
  8. 有一个字长32位的浮点数符号位1位_边缘计算专题:(二)别看只有0和1,数学不好的勿进!...
  9. 蹭着 Java 热点出生的 JavaScript 已经 22 岁了!
  10. webservice系列1---基于web工程上写一个基本数据类型的webservice
  11. 【软件使用技巧】一(截图)
  12. 与报文交换比较,分组交换有哪些优点?
  13. Google play billing: Error refreshing inventory (querying prices of items). (response: 6:Error)
  14. AGV路径规划方法——A*算法
  15. OpenWhisk部署指南
  16. MPAndroidChart使用(BarChart为例)
  17. Aurora8B10B IP使用 -05- 收发测试应用示例
  18. PLC与Unity通讯☀️ 一、目标及术语解释
  19. ai项目实施_公司在实施AI时必须避免的6个最大陷阱
  20. java编译时为什么总找不到文件,javac编译时找不到文件的问题和运行项目找不到指定类问题...

热门文章

  1. 【SFace】《SFace: An Efficient Network for Face Detection in Large Scale Variations》
  2. 用python写一个NC(八)
  3. 【python初学】class类士兵开枪案例
  4. 为什么使用线程池,解释下线程池参数
  5. PS|渐变及海报制作
  6. python利用datetime模块计算时间差
  7. 记一次iphone更换电池难以取下旧电池解决办法
  8. Python实现头条自动发文章,赚点广告费!
  9. 利用duplicity与金山快盘 for UbuntuKylin 实现文件云备份
  10. Microsoft Word 教程「4」,如何在 Word 中应用样式、主题?