**
**
最近老师布置了一个讨论专题,是关于红眼去除,对于我一个初学者来说,当然是一脸懵了,不过还好百度上有一些资源可以 参考,在几天的了解下,也是成功完成了。
我主要参考:https://blog.csdn.net/LuohenYJ/article/details/90035284
里面讲清楚了红眼去除的原理,以及附带程序;
刚开始并不是完全看懂,但是温故而知新,看了几遍也有了一些理解。
我做的这个红眼实验包括打开图像,红眼处理,保存处理后图像到指定位置。
以下是我在做的过程遇到的一些问题,分享给和我一样的初学者。
首先打开QT,进行窗口的设计:
这个过程中,一定要记住自己设置的对象名称,如果和程序中不一样的话,会报错,而且不容易发现,我就是记错了,导致我找了半天。
接下来就是在.pri的地方添加Opencv的路径,因为后面的程序需要调用opencv库。
定义私有成员:
// An highlighted block
QGraphicsScene sceneL, sceneR;//场景,新增的
QPixmap pixmapL,pixmapR;//图像,新增的
构造函数定义:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->openButton->setEnabled(true);
ui->eyeOutButton->setEnabled(false);
ui->saveButton->setEnabled(false);
//关联场景和视图
ui->graphicsViewL->setScene(&sceneL);
ui->graphicsViewR->setScene(&sceneR);
}
槽函数:
打开图像:
void MainWindow::on_openButton_clicked()
{
if(ui->openButton->text()=="关闭图像"){
sceneL.clear();
ui->openButton->setText("打开图像");
ui->saveButton->setEnabled(false);
ui->eyeOutButton->setEnabled(false);
return;
}
QString fileName = QFileDialog::getOpenFileName(
this,
"打开图像",
QDir::currentPath(),
"Images (*.png *.bmp *.jpg *.tif)");
if (!fileName.isNull()){
QFileInfo file(fileName);
if(pixmapL.load(file.absoluteFilePath())){
sceneL.clear(); //清除原有图像信息
sceneL.addPixmap(pixmapL);
ui->openButton->setText("关闭图像");
ui->saveButton->setEnabled(false);
ui->eyeOutButton->setEnabled(true);
}
}
return;
}
保存图像:
void MainWindow::on_saveButton_clicked()
{
QString fileName = QFileDialog::getSaveFileName(
this,
"保存图像",
QDir::currentPath(),
"Images (*.png *.bmp *.jpg *.tif)");
if(pixmapR.save(fileName,0,100))
QMessageBox::information(this,
tr("OK"),
tr("保存成功"));
else
QMessageBox::information(this,
tr("NG"),
tr("保存失败"));
return;
}
红眼处理:
void MainWindow::on_eyeOutButton_clicked()
{
ImageConversion imgConversion;
if(!pixmapL.isNull()){
// Read image 读彩色图像
Mat img = imread("F:/Qt/hongyanshiyan/hongyan/red_eyes1.jpg", CV_LOAD_IMAGE_COLOR);
// Output image 输出图像
Mat imgOut = img.clone();
// Load HAAR cascade 读取haar分类器
CascadeClassifier eyesCascade("E:/openCV/openCVwithContrib-3.3.1build/install/etc/haarcascades/haarcascade_eye.xml");
// Detect eyes 检测眼睛
std::vector<Rect> eyes;
//前四个参数:输入图像,眼睛结果,表示每次图像尺寸减小的比例,表示每一个目标至少要被检测到4次才算是真的
//后两个参数:0 | CASCADE_SCALE_IMAGE表示不同的检测模式,最小检测尺寸
eyesCascade.detectMultiScale(img, eyes, 1.3, 4, 0 | CASCADE_SCALE_IMAGE, Size(100, 100));
// For every detected eye 每只眼睛都进行处理
for (size_t i = 0; i < 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 detector 红眼检测器,获得结果掩模
Mat mask = (bgr[2] > 150) & (bgr[2] > (bgr[1] + bgr[0]));
// Clean mask 清理掩模
//填充孔洞
fillHoles(mask);
//扩充孔洞
dilate(mask, mask, Mat(), Point(-1, -1), 3, 1, 1);
// Calculate the mean channel by averaging the green and blue channels
//计算b通道和g通道的均值
Mat mean = (bgr[0] + bgr[1]) / 2;
//用该均值图像覆盖原图掩模部分图像
mean.copyTo(bgr[2], mask);
mean.copyTo(bgr[0], mask);
mean.copyTo(bgr[1], mask);
// Merge channels
Mat eyeOut;
//图像合并
cv::merge(bgr, eyeOut);
// Copy the fixed eye to the output image.
// 眼部图像替换
eyeOut.copyTo(imgOut(eyes[i]));
}
// Display Result
//imshow("Red Eyes", img);
//imshow("Red Eyes Removed", imgOut);
//waitKey(0);
pixmapR=imgConversion.cvMatToQPixmap(imgOut);
waitKey(0);
sceneR.clear();
sceneR.addPixmap(pixmapR);
ui->saveButton->setEnabled(true);
}
return ;
}
额外函数:
void fillHoles(Mat &mask)
{
Mat maskFloodfill = mask.clone();
//漫水填充
floodFill(maskFloodfill, cv::Point(0, 0), Scalar(255));
Mat mask2;
//反色
bitwise_not(maskFloodfill, mask2);
//或运算
mask = (mask2 | mask);
}
红眼处理过程遇到的问题: