1.1访问摄像头或者读取图片和视频流:?
? ? ? ? 在OpenCV中,通过cv::VideoCapture对象的open()方法可访问摄像头或者相机设备。
VideoCapture初始化:
????????bool VideoCapture::open(const string& filename)//开视频文件
????????bool VideoCapture::open(int device) //开摄像头
????????bool VideoWriter::isOpened() //若初始化成功返回true,失败返回false
imread与imshow:
????????Mat cv::imread ( const String & filename, int flags = IMREAD_COLOR )
????????参数1 filename, 读取的图片文件名,可以使用相对路径或者绝对路径,但必须带完整的文件扩展名(图片格式后缀)
????????参数2 flags, 一个读取标记,用于选择读取图片的方式,默认值为IMREAD_COLOR,flag值的设定与用什么颜色格式读取图片有关
????????void imshow(const string& winname, InputArray mat);
????????参数1 winname,生成的窗口的名称
? ? ? ? 参数2 mat 懂的都懂
????????void nameWindow(const string& winname,int flags = WINDOW_AUTOSIZE) //新建一个窗口
????????参数1:新建的窗口的名称。自己随便取。
????????参数2:窗口的标识,一般默认为WINDOW_AUTOSIZE 。
????????WINDOW_AUTOSIZE 窗口大小自动适应图片大小,并且不可手动更改。(上面图1就是使用的它)
????????WINDOW_NORMAL 用户可以改变这个窗口大小(上面图2就是使用的它)
????????WINDOW_OPENGL 窗口创建的时候会支持OpenGL ?
????????int cv::waitKey ( int delay = 0 ) ????????//等待一个按键,等待的时间取决于参数,0则无限等待,返回按键的ASCII值
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
void main(int argc,char *argv[]){
auto cameraNumber = 0;
if(argc > 1){
cameraNumber = atoi(argv[1]);
}
//这里尝试去打开摄像头设备
VideoCapture camera;
camera.open(cameraNumber);
if(!camera.isOpened()){
cerr<<"ERROR : cannot open the camera"<<endl;
exit(1);
}
//设置摄像头的分辨率 640 * 480
camera.set(CV_CAP_PROP_FRAME_WIDTH,640);
camera.set(CV_CAP_PROP_FRAME_HEIGHT,480);
}
? ? ? ? 由于版本变量的更名,若使用CV_CAP_PROP_FRAME_WIDTH发生报错,则去掉前面的CV_即可。
? ? ? ? cerr:输出到标准错误的ostream对象,常用于程序错误信息(重定向不会影响cerr)
? ? ? ?或者简单的使用如下的方式;
#include<iostream>
#include<opencv2/opencv.hpp>
#include <opencv2\imgproc\types_c.h>
void main(int argc, char *argv[]) {
Mat video;
VideoCapture capture(0);
while (1) {
capture >> video;
imshow("test",video);
waitKey(30);
}
return;
}
1.2桌面应用程序的相机处理主循环(实时相机应用程序)
? ? ? ? 实时相机应用程序的骨架:
while (true) {
Mat cameraFrame;
camera >> cameraFrame;
if (cameraFrame.empty()) {
cerr << "error!! cannot grap a camera frame" << endl;
exit(1);
}
//创建一个新的空白的画面,待会让程序画上去
Mat displayedFrame(cameraFrame.size(), CV_8UC3);
//将摄像机的画面画上去
cartoonifyImage(cameraFrame,displayedFrame);
//显示画面
imshow("Cartoonifier", displayedFrame);
auto keypress = waitKey(20);
if (keypress == 27) {
//若是返回键,则退出
break;
}
}
? ? ? ? 1.2.1卡通化图像
????????????????图像中灰度变化较大的非连续像素可以看做是边缘,若要将图片转化为黑白图画,可用边缘检测滤波器,若要获得彩色绘画,可采用边缘保留滤波器(双边滤波器),使用滤波器之前,需要对图像去噪,可使用中值滤波器来去噪。
????????这里我们采用Laplacian边缘滤波器,该滤波器使用灰度图像,因此需要将OpenCV的默认BGR格式转化为灰度。
void cartoonifyImage(Mat& src, Mat& dst)
{
Mat gray;
cvtColor(src, gray, CV_BGR2GRAY);
const int MEDIAN_BLUR_FILTER_SIZE = 7;
medianBlur(gray, gray, MEDIAN_BLUR_FILTER_SIZE); // 中值
Mat edges;
const int LAPLACIAN_FILTER_SIZE = 5;
Laplacian(gray, edges, CV_8U, LAPLACIAN_FILTER_SIZE); // 拉普拉斯
Mat mask;
const int EDGES_THRESHOLD = 80;
threshold(edges, mask, EDGES_THRESHOLD, 255, THRESH_BINARY_INV); //二值化
// 图片缩小
Size size = src.size();
Size smallSize;
smallSize.width = size.width / 2;
smallSize.height = size.height / 2;
Mat smallImg = Mat(smallSize, CV_8UC3);
resize(src, smallImg, smallSize, 0, 0, INTER_LINEAR);
// 双边滤波
Mat tmp = Mat(smallSize, CV_8UC3);
int repetitions = 7;
for (int i = 0; i < repetitions; i++)
{
int ksize = 9;
double sigmaColor = 9;
double sigmaSpace = 7;
bilateralFilter(smallImg, tmp, ksize, sigmaColor, sigmaSpace);
bilateralFilter(tmp, smallImg, ksize, sigmaColor, sigmaSpace);
}
// 图像复原
Mat bigImg;
resize(smallImg, bigImg, size, 0, 0, INTER_LINEAR);
dst.setTo(0);
bigImg.copyTo(dst, mask);
}
? ? ??
这里的CV_BGR2GRAY一直报错,说未定义标识符,搞了很久,只需要引入头文件#include <opencv2\imgproc\types_c.h>?即可。
? ? ? ? ?Sample:
? 1.2.2邪恶模式
????????进行两次Scharr滤波即可
void evilImage(Mat& src, Mat& dst)
{
Mat gray, mask;
cvtColor(src, gray, CV_BGR2GRAY);
const int MEDIAN_BLUR_FILTER_SIZE = 7;
medianBlur(gray, gray, MEDIAN_BLUR_FILTER_SIZE);
Mat edges, edges2;
Scharr(gray, edges, CV_8U, 1, 0);
Scharr(gray, edges2, CV_8U, 1, 0, -1);
edges += edges2;
const int EVIL_EDGE_THRESHOLD = 12;
threshold(edges, mask, EVIL_EDGE_THRESHOLD, 255, THRESH_BINARY_INV);
medianBlur(mask, mask, 3);
imshow("1", mask);
dst.setTo(0);
src.copyTo(dst, mask);
}
sample:
使用人脸模块进行人脸特征点及姿态检测
? ? ? ? 2.1人脸的特征点检测
? ? ? ? 特征点的检测先从人脸检测开始,在图像中寻找人脸以及范围(边界框),最简单
的方法,只需使用core模块中提供的cv::CascadeClassifier类即可。
? ? ? ? 下面是一个具有级联分类器的简单辅助函数来检测人脸:
void faceDetector(const Mat &image,vector<Rect> &faces,CascadeClassifier &face_cascade) {
Mat gray;
//灰度图像是最适合人脸检测的
if (image.channels() > 1) {
cvtColor(image, gray, COLOR_BGR2GRAY);
}
else {
gray = image.clone();
}
equalizeHist(gray,gray); //对图像进行直方图均衡化
faces.clear();
face_cascade.detectMultiScale(gray,faces,1.4,3,CASCADE_SCALE_IMAGE+CASCADE_FIND_BIGGEST_OBJECT);
}
这里注意最后一个语句的倒数第二第三参数,金字塔尺度因子和临近点数量。金字塔尺度因子用于创建图像金字塔,检测器将在其中查找人脸,在生成图像金字塔的每一步中,图像按此比例因子缩小,因此较小的因子(接近1.0)将导致生成更多的图像,但是却意味着更长的运行时间,结果更精准,第二个参数控制了邻近人脸的下限,若检测出至少三个相邻的人脸整个分类器只返回一个人脸。
? ? ? ? 首先要用OpenCV提供的模型来初始化级联分类器,这里对正面人脸标定训练分类器(序列化模型的XML在&OPENCV_ROOT/data/haarcascades目录)。
const string cascade_name ="E:/opencv/opencv/sources/data/haarcascades/haarcascades_frontalface_default.xml";
CascadeClassifier face_cascade;
if (not face_cascade.load(cascade_name)) {
cerr << "cannot load cascade classifier from file" << cascade_name << endl;
return -1;
}
vector<Rect> faces;
faceDetector(cameraFrame, faces, face_cascade);
if (faces.size() == 0) {
cerr << "cannot detect any faces in the image" << endl;
return -1;
}
? ? ? ? 确定边界之后,还要对cv::face::Facemark对象进行初始化:
????????这里的#include<opencv2/face.hpp>一般会报错,这是因为而opencv3的人脸识别库等contrib模块已经不再内置了,这里提供了下载的地址,解压到build/include/opencv2中即可。https://github.com/opencv/opencv_contrib/releases
#include<opencv2/face.hpp>
using namespace cv::face;
// ............
const string facemark_filename = "fata/lbfmodel.yaml";
Ptr<Facemark> facemark = createFacemarkLBF();
facemark->loadModel(facemark_filename);
cout << "Loaded facemark LBF model" << endl;
? ? ? ? 初始化后,使用facemark对象及其fit函数来查找面部形状。
vector<Rect> faces;
faceDetector(cameraFrame, faces, face_cascade);
if (faces.size() != 0) {
rectangle(cameraFrame, faces[0], Scalar(255, 0, 0), 2);
vector<vector<Point2f>> shapes;
if (facemark->fit(img, faces, shapes)) {
drawFacemarks(img, shapes[0], cv::Scalar(0, 0, 255));
}
}
else {
cout << "faces not detected" << endl;
}
sample:
?当然,将图片改成摄像头流,可以实时捕获到摄像头中出现的人脸。
下面是代码实例
#include <opencv2\imgproc\types_c.h>
#include<opencv2/opencv.hpp>
#include<opencv2/face.hpp>
#include<iostream>
using namespace std;
using namespace cv;
using namespace cv::face;
void faceDetector(const Mat &image,vector<Rect> &faces,CascadeClassifier &face_cascade) {
Mat gray;
//灰度图像是最适合人脸检测的
if (image.channels() > 1) {
cvtColor(image, gray, COLOR_BGR2GRAY);
}
else {
gray = image.clone();
}
equalizeHist(gray,gray); //对图像进行直方图均衡化
faces.clear();
face_cascade.detectMultiScale(gray,faces,1.3,3,CASCADE_SCALE_IMAGE+CASCADE_FIND_BIGGEST_OBJECT);
}
void evilImage(Mat& src, Mat& dst) //邪恶模式
{
Mat gray, mask;
cvtColor(src, gray, CV_BGR2GRAY);
const int MEDIAN_BLUR_FILTER_SIZE = 7;
medianBlur(gray, gray, MEDIAN_BLUR_FILTER_SIZE);
Mat edges, edges2;
Scharr(gray, edges, CV_8U, 1, 0);
Scharr(gray, edges2, CV_8U, 1, 0, -1);
edges += edges2;
const int EVIL_EDGE_THRESHOLD = 12;
threshold(edges, mask, EVIL_EDGE_THRESHOLD, 255, THRESH_BINARY_INV);
medianBlur(mask, mask, 3);
imshow("1", mask);
dst.setTo(0);
src.copyTo(dst, mask);
}
void cartoonifyImage(Mat& src, Mat& dst) //卡通化图像
{
Mat gray;
cvtColor(src, gray, CV_BGR2GRAY);
const int MEDIAN_BLUR_FILTER_SIZE = 7;
medianBlur(gray, gray, MEDIAN_BLUR_FILTER_SIZE); // 中值
Mat edges;
const int LAPLACIAN_FILTER_SIZE = 5;
Laplacian(gray, edges, CV_8U, LAPLACIAN_FILTER_SIZE); // 拉普拉斯
Mat mask;
const int EDGES_THRESHOLD = 80;
threshold(edges, mask, EDGES_THRESHOLD, 255, THRESH_BINARY_INV); //二值化
// 图片缩小
Size size = src.size();
Size smallSize;
smallSize.width = size.width / 2;
smallSize.height = size.height / 2;
Mat smallImg = Mat(smallSize, CV_8UC3);
resize(src, smallImg, smallSize, 0, 0, INTER_LINEAR);
// 双边滤波
Mat tmp = Mat(smallSize, CV_8UC3);
int repetitions = 7;
for (int i = 0; i < repetitions; i++)
{
int ksize = 9;
double sigmaColor = 9;
double sigmaSpace = 7;
bilateralFilter(smallImg, tmp, ksize, sigmaColor, sigmaSpace);
bilateralFilter(tmp, smallImg, ksize, sigmaColor, sigmaSpace);
}
// 图像复原
Mat bigImg;
resize(smallImg, bigImg, size, 0, 0, INTER_LINEAR);
dst.setTo(0);
bigImg.copyTo(dst, mask);
}
int main(int argc, char *argv[]) {
// Mat cameraFrame;
// const string filename = "E:/imgsource/3.jpg";
// cameraFrame = imread(filename,1);
Mat cameraFrame;
VideoCapture camera(0);
const string cascade_name = "E:/opencv/opencv/sources/data/haarcascades/haarcascade_frontalface_default.xml";
CascadeClassifier face_cascade;
if (not face_cascade.load(cascade_name)) {
cout << "cannot load cascade classifier from file " << cascade_name << endl;
return -1;
}
vector<Rect> faces;
while (1) {
camera >> cameraFrame;
faceDetector(cameraFrame, faces, face_cascade);
for (int i = 0; i < faces.size(); ++i)
rectangle(cameraFrame, faces[i], Scalar(255, 0, 0), 2);
imshow("test", cameraFrame);
auto keypress=waitKey(10);
if (keypress == 21) {
break;
}
}
return 0;
}
|