点击上方小白学视觉”,选择加"星标"或“置顶
重磅干货,第一时间送达

OpenCV实现照片自动红眼去除

使用闪光照相机拍照,在光线条件不足的情况,如果眼睛盯着相机镜头很容易造成拍出的照片中人眼球变成红色,虽然现在相机从系统和镜头上做了大量改进工作,防止这种情况发生,但是还是会出现这样的情况。这些照片后期可以通过PS手段进行修复,去除红眼得到正常照片显示。而做图像处理开发者可以借助OpenCV提供API功能轻松实现自动红眼去除修复。首先看一下效果吧图像
有红眼照片
修复之后的照片
实现步骤
眼睛检测
基于OpenCV自带的HAAR眼睛级联分类器特征数据(haarcascade_eye.xml),通过调用级联分类器实现眼睛检测,对检测到的眼睛用红色矩形框标注,如第一张图所示。
实现代码如下:
  1. vector<Rect> eyes;
  2. cvtColor(src, gray, COLOR_BGR2GRAY);
  3. equalizeHist(gray, gray);
  4. eye_detector.detectMultiScale(gray, eyes,1.1,3,0,Size(100,100));

提取红色眼球区域

根据红眼颜色特征可以看出这种情况下,对每个像素点来说在RGB三通道中红色通道的分量明显要大于其它两个通道的值,所以通过三个通道分离,对每个像素红色通道来说值大于150(R>150)而且R >(G+B)时候我们把它保留作为眼球区域。最终对两个眼睛提取区域图像如下:
代码实现如下:
  1. for(size_t t =0; t < eyes.size(); t++){
  2. // 通道分离
  3. Mat eye = src(eyes[t]);
  4.    vector<Mat>bgr(3);
  5.    split(eye, bgr);
  6. // 基于像素模型的红眼区域检测
  7. Mat mask =(bgr[2]>150)&(bgr[2]>(bgr[1]+ bgr[0]));
  8. }

逻辑操作与形态学处理

上述的白色区域就是红色眼球所在的区域,但是这样的情况下白色区域内部还有一些黑色小块,我们可以通过漫水填充与逻辑操作完整填充整个内部区域,然后通过形态的膨胀操作,让红色眼球进一步扩展,这样就会让整个处理之后的边界处看上去比较自然圆润一点。处理之后的效果如下:
代码实现如下:
  1. // 区域填充与提取
  2. Mat mask_floodfill = mask.clone();
  3. floodFill(mask_floodfill, cv::Point(0,0),Scalar(255));
  4. Mat mask2;
  5. bitwise_not(mask_floodfill, mask2);
  6. mask =(mask2 | mask);
  7. dilate(mask, mask,Mat(),Point(-1,-1),3,1,1);

红眼修复

对上面得到白色区域即为红眼区域,通过把上面结果作为遮罩,对检测到人眼区域进行修复即可。一般情况下人的眼球都是黑色,越中心地方越黑色越暗,对白色区域内的每个像素点,取它的B和G两个通道的平均值作为修复处理之后的R,G,B三通道的值,这样就得到修复之后的眼球区域,然后用修复之后的眼球区域替代原来的红眼区域即可得到修复之后的图像:
代码实现如下:
  1. // 修复
  2. Mat mean =(bgr[0]+ bgr[1])/2;
  3. mean.copyTo(bgr[0], mask);
  4. mean.copyTo(bgr[1], mask);
  5. mean.copyTo(bgr[2], mask);
  6. // 回填
  7. Mat eyeOut;
  8. merge(bgr, eyeOut);
  9. eyeOut.copyTo(imgOut(eyes[t]));

完整代码如下

  1. #include<opencv2/opencv.hpp>
  2. #include<iostream>
  3. usingnamespace cv;
  4. usingnamespace std;
  5. String filename ="D:/opencv3.1/opencv/build/etc/haarcascades/haarcascade_eye.xml";
  6. CascadeClassifier eye_detector;
  7. int main(int argc,char** argv){
  8. Mat src = imread("D:/23-01.jpg");
  9. if(src.empty()){
  10.        printf("could not load image...\n");
  11. return-1;
  12. }
  13. if(!eye_detector.load(filename)){
  14.        printf("could not load data file...\n");
  15. return-1;
  16. }
  17. Mat imgOut = src.clone();
  18. Mat gray;
  19.    vector<Rect> eyes;
  20.    cvtColor(src, gray, COLOR_BGR2GRAY);
  21.    equalizeHist(gray, gray);
  22.    eye_detector.detectMultiScale(gray, eyes,1.1,3,0,Size(100,100));
  23. for(size_t t =0; t < eyes.size(); t++){
  24. // 通道分离
  25. Mat eye = src(eyes[t]);
  26.        vector<Mat>bgr(3);
  27.        split(eye, bgr);
  28. // 基于像素模型的红眼区域检测
  29. Mat mask =(bgr[2]>150)&(bgr[2]>(bgr[1]+ bgr[0]));
  30. // 区域填充与提取
  31. Mat mask_floodfill = mask.clone();
  32.        floodFill(mask_floodfill, cv::Point(0,0),Scalar(255));
  33. Mat mask2;
  34.        bitwise_not(mask_floodfill, mask2);
  35.        mask =(mask2 | mask);
  36.        dilate(mask, mask,Mat(),Point(-1,-1),3,1,1);
  37. if(t ==1){
  38.            imshow("mask", mask);
  39. }
  40. // 修复
  41. Mat mean =(bgr[0]+ bgr[1])/2;
  42.        mean.copyTo(bgr[0], mask);
  43.        mean.copyTo(bgr[1], mask);
  44.        mean.copyTo(bgr[2], mask);
  45. // 回填
  46. Mat eyeOut;
  47.        merge(bgr, eyeOut);
  48.        eyeOut.copyTo(imgOut(eyes[t]));
  49.        rectangle(src, eyes[t],Scalar(0,0,255),2,8,0);
  50. }
  51.    imshow("input", src);
  52.    imshow("output", imgOut);
  53.    waitKey(0);
  54. return0;
  55. }

总结:

整个处理就是考察使用OpenCV图像处理的基本操作能力、以及像素操作ROI区域与MASK的巧妙运用。基于OpenCV3.1.0完成全部代码调试。
好消息!
小白学视觉知识星球
开始面向外开放啦👇👇👇
下载1:OpenCV-Contrib扩展模块中文版教程
在「小白学视觉」公众号后台回复:扩展模块中文教程即可下载全网第一份OpenCV扩展模块教程中文版,涵盖扩展模块安装、SFM算法、立体视觉、目标跟踪、生物视觉、超分辨率处理等二十多章内容。
下载2:Python视觉实战项目52讲
小白学视觉公众号后台回复:Python视觉实战项目即可下载包括图像分割、口罩检测、车道线检测、车辆计数、添加眼线、车牌识别、字符识别、情绪检测、文本内容提取、面部识别等31个视觉实战项目,助力快速学校计算机视觉。
下载3:OpenCV实战项目20讲
小白学视觉公众号后台回复:OpenCV实战项目20讲即可下载含有20个基于OpenCV实现20个实战项目,实现OpenCV学习进阶。
交流群
欢迎加入公众号读者群一起和同行交流,目前有SLAM、三维视觉、传感器自动驾驶、计算摄影、检测、分割、识别、医学影像、GAN算法竞赛等微信群(以后会逐渐细分),请扫描下面微信号加群,备注:”昵称+学校/公司+研究方向“,例如:”张三 + 上海交大 + 视觉SLAM“。请按照格式备注,否则不予通过。添加成功后会根据研究方向邀请进入相关微信群。请勿在群内发送广告,否则会请出群,谢谢理解~
继续阅读
阅读原文