利用OpenCV自带的分类器识别面部及眼睛
OpenCV自带里许多分类器,可在haarcascades下载
获取面部
// 获取面部
// image 为输入的OpenCV的格式的图像
// out 为输出图像 <- 此处输出图像为裁剪下来的矩形面部图像
bool get_face(cv::Mat image, cv::Mat &out)
{
// 将图像转为灰度图像,可提高识别精度
cv::Mat gray;
cv::cvtColor(image, gray, CV_BGR2GRAY, 0);
// 此处的rect为用来存储识别出的面部的定位 <- 这里为vector是因为识别的面部可能不止为一个
std::vector<cv::Rect> rect;
// 初始化OpenCV的分类器
cv::CascadeClassifier cas = cv::CascadeClassifier("haarcascade_frontalface_default.xml");
cas.detectMultiScale(gray, rect, 1.15, 5);
// 判断rect是否为空,为空的话就是没有被识别的面部
if (rect.empty())
{
return false;
}
// 输出图像,这里的rect可能不止为一个(因为可能不止一张脸),所以实际中应该使用for循环
// 我这里用rect[0]为了简化
out = image(rect[0]);
return true;
}
获取眼睛
// 这里与上面相同(这里我只识别左眼,OpenCV还提供了其他文件可获取右眼和双眼)
bool get_left_eye(cv::Mat image, cv::Mat &out)
{
// 之后与面部相同
cv::Mat gray;
cv::cvtColor(image, gray, CV_BGR2GRAY, 0);
std::vector<cv::Rect> rect;
cv::CascadeClassifier cas = cv::CascadeClassifier("xml/haarcascade_lefteye_2splits.xml");
cas.detectMultiScale(gray, rect, 1.15, 5);
if (rect.empty())
{
return false;
}
out = image(rect[0]);
return true;
}
瞳孔定位
- 获取的眼睛图像
- 裁剪去除眉毛
- 伽马矫正提高图像对比度
- 转化为灰度图像
- 利用threshold进行阈值操作(此处可能会改为inRange,目前还在测试)
- 腐蚀
- 膨胀
- medianBlur平滑图像
- 检测关键点并画在图像上
// 定位眼球 -> 检测关键点
std::vector<cv::KeyPoint> dector(cv::Mat image)
{
cv::SimpleBlobDetector::Params detector_params;
detector_params.filterByArea = true;
detector_params.maxArea = 1500;
cv::Ptr<cv::SimpleBlobDetector> blob_dector = cv::SimpleBlobDetector::create(detector_params);
std::vector<cv::KeyPoint> keypoints;
blob_dector->detect(image, keypoints);
return keypoints;
}
bool get_pupil(cv::Mat image, cv::Mat &out)
{
// width -> image.rows ;
// height -> image.cols;
// cut eyebrow 裁剪 去除眉毛
image = image(cv::Rect(image.cols / 10, image.rows / 2.5, image.cols * 8 / 10, image.rows / 2));
// Gamma correction/gamma nonlinearity 伽马校正 -> https://www.cnblogs.com/sdu20112013/p/11597171.html
cv::Mat look_up_table(1, 256, CV_8U);
uchar *p = look_up_table.ptr();
float gamma = 0.7;
for (int i = 0; i < 256; ++i)
p[i] = cv::saturate_cast<uchar>(pow(i / 255.0, gamma) * 255.0);
cv::LUT(image, look_up_table, image);
cv::Mat gray;
// 转化为灰度图像
cv::cvtColor(image, gray, CV_BGR2GRAY, 0);
// 阈值操作
cv::threshold(gray, gray, inRange_threshold, 255, CV_THRESH_BINARY);
//膨胀及腐蚀
cv::erode(gray, gray, cv::Mat(), cv::Point(-1, -1), 2);
cv::dilate(gray, gray, cv::Mat(), cv::Point(-1, -1), 3);
// 平滑图像
cv ::medianBlur(gray, gray, 5);
// 检测并画出关键点
cv::drawKeypoints(image, dector(gray), image, cv::Scalar(0, 0, 255), cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
out = image;
return true;
}
附录
OpenCV在ArchLinux上的使用
pacman -S opencv
# vtk和hdf5为opencv的依赖,不安装编译会失败
sudo pacman -S vtk
sudo pacman -Ss hdf5
Cmake文件
cmake_minimum_required(VERSION 3.14)
project(eyedector)
add_definitions(-std=c++11)
# 这里只需要添加OpenCV的就能编译成功
find_package(OpenCV REQUIRED)
link_libraries(${OpenCV_LIBS})
add_executable(out opencvtest.cpp)
利用安卓手机充当网络摄像头
手机安装这个IP Webcam,使用时会显示局域网中的地址
OpenCV中
cv::VideoCapture cap("http://192.168.0.xx:8080/video"); // 这里为网络摄像头的地址,需要在后面加上/video
while (true)
{
cv::Mat frame;
cap >> frame;
cv::imshow("test", frame);
if (cv::waitKey(1) == 27)
{
exit(0);
}
}