opencv

一、 项目准备

在开始介绍项目之前,要在树莓派上编译安装opencv,wiringPi,最后配置一下SMB服务器(可选,方便在windows下打开和编辑树莓派的文件)。

1.1、opencv在树莓派上的编译安装

欲先善其事必先利器,我选用opencv-3.4.10加上opencv_contrib-3.4.10。注意,opencv_contrib必须选择和opencv版本号相同,避免不必要的麻烦。
(1) 安装依赖软件

sudo apt-get install build-essential 
sudo apt-get install cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev
sudo apt-get install python-dev python-numpy libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libjasper-dev libdc1394-22-dev

(2) 准备opencv和opencv_contrib的源码
下载opencv和opencv_contrib的源码可以去opencv官方的Github上下载,这是opencv源码的下载链接: https://github.com/opencv/opencv/tags.
在这里插入图片描述

以下是opencv_contrib源码的下载链接: https://github.com/opencv/opencv_contrib/tags.
在这里插入图片描述
可以通过以上的链接下载自己想要的opencv版本,我这里下载的是opencv-3.4.10和opencv_contrib-3.4.10。

(3)编译前的简单配置
我之前在编译OpenCV 以及 openc_contrib 提示缺少boostdesc_bgm.i等一些文件出错,经过多方的百度寻求答案,最后在一个博主那里得到了解决:https://blog.csdn.net/u011736771/article/details/85960300
由于在编译的时候他会执行文件里面的脚本下载一些文件,但由于网络等问题这些文件下载失败了。日志文件里就有它的下载地址,直接复制其下载地址到网页可以看该到文件的源码,直接拷贝源码并生存同名文件,放在 opencv_contrib/modules/xfeatures2d/src/ 路径下即可。这里我就不过多的赘述了,大家可以参考上面的链接。相应的配置文件我也已经放在Github上(地址在文末)在这里插入图片描述

因为我是把源码放在服务器上编译的所以 以下的路径前缀/mnt/USER_lvzhe/换成自己主机相应的路径
在/mnt/USER_lvzhe/opencv-3.4.10/modules中的CMakeLists.txt中加上:

include_directories(
	/mnt/USER_lvzhe/opencv_contrib-3.4.10/modules/xfeatures2d/include
)

在这里插入图片描述

接下来我们开始编译和安装

/**进入opencv源码的目录**/
1. cd opencv-3.4.10/

/**创建存放编译的文件夹**/
2. mkdir build

/**通过cmake生成编译所用到的Makefile脚本文件**/
3. cmake -D CMAKE_BUILD_TYPE=Release -D OPENCV_GENERATE_PKGCONFIG=ON -D CMAKE_INSTALL_PREFIX=/usr/local -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-3.4.10/modules  ..

/**通过生成的Makefile编译整个源码,启动4个线程编译有可能导致树莓派死机,不嫌弃时间过长可以不用带上后面的参**/
4. sudo make -j4

/**编译完后需要安装**/
5. sudo make install

6. sudo vim /etc/ld.so.conf.d/opencv.conf 
7. /usr/local/lib           //添加/usr/local/lib,并保存
8. sudo ldconfig

/**我通过pkg-config这个软件来管理包,需要配置一下环境变量**/
9. sudo vim /etc/bash.bashrc
10. PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig  
11. export PKG_CONFIG_PATH            //打开文件,在末尾添加
/**保存退出,然后**/
12. source /etc/bash.bashrc

通过cmake的一些配置生成Makefile,以下是cmake的一些详细的讲解

> cmake 
> -D CMAKE_BUILD_TYPE=Release 
> -D OPENCV_GENERATE_PKGCONFIG=ON     //使能pkg-config管理opencv的包
> -D CMAKE_INSTALL_PREFIX=/usr/local           //opencv的安装路径
> -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-3.4.10/modules  //配置opencv_contrib的路径,我是将opencv和contrib放在同一级目录下,当前目录有在build,我使用了相对路径
> ..             //最后这两个点不能少,这是由于要编译的文件处于上一级目录      

最后出现configuring done就算配置成功,然后就可以编译了。
在这里插入图片描述

最后这样就算成功了。
在这里插入图片描述

1.2、wiringPi的简单介绍和安装

树莓派的GPIO可以像单片机(51单片机,Arduino,STM32等)一样进行IO控制(输出高、低电平,IIC,SPI,串口通信,PWM输出等),在此使用常用的WiringPi库来进行GPIO的操作。
wiringPi的安装可以使用:
方案一:使用git工具安装wiringPi库。
方案二:手动下载wiringPi源码然后在本地安装。

这里我使用第一种方案,采用git工具安装wiringPi库,以下是一些配置

1.#通过git在线获得wiringPi的源代码
git clone git://git.drogon.net/wiringPi

2.#进入wiringPi目录并安装wiringPi库
cd wiringPi
./build

执行build程序将会自动完成wiringPi库的编译和安装,安装完成如下…
在这里插入图片描述
以下就是安装成功…
在这里插入图片描述

1.3、SMB服务器的简单配置

我们使用树莓派的时候经常要在 windows 和树莓派之间进行文件传输,使用 samba 服务可实现文件共享。在 windows 的网上邻居即可访问树莓派文件系统,非常方便。

1.运行以下命令安装 samba 软件
sudo apt-get install samba samba-common-bin

2.安装完成后,修改配置文件/etc/samba/smb.conf
sudo vi /etc/samba/smb.conf
下面的配置是让用户可以访问自己的 home 目录。
a) 开启用户认证,找到‚##### Authentication #####‛,将‚# security = user ‛#号去掉。
b) 配置每个用户可以读写自己的 home 目录,在‚"[homes]"节中,把 "read only = yes" 改为 "read only = no"。

3.重启 samba 服务
sudo /etc/init.d/samba restart

4.添加默认用户 pi 到 samba
sudo smbpasswd -a pi
输入密码确定即可。

5.访问树莓派文件
使用文件管理器添加一个网络位置输入 ip 地址(ip 地址改为树莓派 IP 地址),输入用户密码,则可以访问树莓派 home 目录。

在这里插入图片描述

二、 项目说明

说完了前面的铺垫,最后来说一下整个项目的框架:
人脸检测采用opencv的harr级联分类器进行检测,将人脸的大小和中心点和整个图像的大小和中心点分别进行比较,调整舵机的位置使人脸处于图像的中心。源码如下:

/*=============================================================================
#       COPYRIGHT NOTICE
#       Copyright (c) 2019
#       All rights reserved
#
#       @author       :lvzhe
#       @mail         :1750895316@qq.com
#       @file         :opencv_faceCheck.cpp
#       @date         :2020/03/06 15:52
#       @algorithm    :
=============================================================================*/

#include "opencv2/objdetect.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <stdio.h>
#include <iostream>
#include <wiringPi.h>
using namespace std;
using namespace cv;

#define PwmMaxValue (250)
#define PwmMinValue (50)


/** Function Headers */
void detectAndDisplay();
void steeringPwmInit(void);
void steeringControlDir(Point face_center,Point frame_center,int face_size);


/** Global variables */
Mat frame;
int pitchPwmPin=18;
int yawPwmPin=13;
String face_cascade_name;
CascadeClassifier face_cascade;
String window_name = "Capture - Face detection";

/** @function main */
int main(int argc, const char **argv)
{
    face_cascade_name = "xml/haarcascade_frontalface_alt.xml";
    VideoCapture capture;
    //-- 1. Load the cascades
    if (!face_cascade.load(face_cascade_name))
    {
        printf("--(!)Error loading face cascade\n");
        return -1;
    }
	steeringPwmInit();
    //-- 2. Read the video stream
    capture.open(0);
	capture.set(CV_CAP_PROP_FRAME_WIDTH,640);//最大
 	capture.set(CV_CAP_PROP_FRAME_HEIGHT,480);
    if (!capture.isOpened())
    {
        printf("--(!)Error opening video capture\n");
        return -1;
    }

    while (capture.read(frame))
    {
        if (frame.empty())
        {
            printf(" --(!) No captured frame -- Break!");
            break;
        }
		Size dsize = Size(frame.cols*0.5, frame.rows*0.5);
        resize(frame, frame, dsize);
        //-- 3. Apply the classifier to the frame
        detectAndDisplay();
        if (waitKey(10) == 27)
        {
            break;
        } // escape
    }
    return 0;
}

/** @function detectAndDisplay */
void detectAndDisplay()
{
    std::vector<Rect> faces;
    Mat frame_gray;

    cvtColor(frame, frame_gray, COLOR_BGR2GRAY);
    equalizeHist(frame_gray, frame_gray);
     Point frame_center(frame.size().width/2,frame.size().height/2); 
    //-- Detect faces
    face_cascade.detectMultiScale(frame_gray, faces, 1.1, 2, 0 | CASCADE_SCALE_IMAGE, Size(60, 60));
    for (size_t i = 0; i < faces.size(); i++)
    {
        Point face_center(faces[i].x + faces[i].width / 2, faces[i].y + faces[i].height / 2);
        rectangle(frame,faces[static_cast<int>(i)],Scalar(255,0,0),2,8,0);
		steeringControlDir(face_center,frame_center,faces[i].area());
		// std::cout << "face size:" << faces[i].size()<<endl; 
    }
    //-- Show what you got
    imshow(window_name, frame);
}


/** @function steeringPwmInit */

void steeringPwmInit(void)
{
	wiringPiSetupGpio();
	pinMode(pitchPwmPin,PWM_OUTPUT);
	pinMode(yawPwmPin,PWM_OUTPUT);
	pwmSetMode(PWM_MODE_MS);

	pwmSetClock(192);
	pwmSetRange(2000);
}


int pitch_value=150;
int yaw_value=150;
float kx=0.2;
float ky=0.3;


/** @function steeringControlDir */
void steeringControlDir(Point face_center,Point frame_center,int face_size)
{
	int frame_size=frame.cols*frame.rows;
	int k =frame_size/face_size;
	float dx,dy;
	// std::cout << "k:" << k<<endl;
		if(k>=7){//如果整个图像相对人脸的大小来说很大,就要限制舵机的摆幅
			dx=(frame_center.x-face_center.x)*kx/k;
			dy=(frame_center.y-face_center.y)*ky/k;
		
			yaw_value+=dx;
			if(yaw_value >= PwmMaxValue)
			yaw_value=PwmMaxValue;
			else if(yaw_value <= PwmMinValue)
			yaw_value=PwmMinValue;	
			pwmWrite(yawPwmPin,(int)yaw_value);
		
			pitch_value+=dy;
			if(pitch_value >= PwmMaxValue)
			pitch_value=PwmMaxValue;
			else if(pitch_value <= PwmMinValue)
			pitch_value=PwmMinValue;	
			pwmWrite(pitchPwmPin,(int)pitch_value);
		}else {//如果整个图像相对人脸的大小来说很小,就要限制舵机的摆动的频率
			dx=(frame_center.x-face_center.x)*0.05;
			dy=(frame_center.y-face_center.y)*0.05;
			if(abs((int)dx)>=3){
				yaw_value+=dx;
				if(yaw_value >= PwmMaxValue)
				yaw_value=PwmMaxValue;
				else if(yaw_value <= PwmMinValue)
				yaw_value=PwmMinValue;	
				pwmWrite(yawPwmPin,(int)yaw_value);
			}
			
			if(abs((int)dy)>=2)
			{
				pitch_value+=dy;
				if(pitch_value >= PwmMaxValue)
				pitch_value=PwmMaxValue;
				else if(pitch_value <= PwmMinValue)
				pitch_value=PwmMinValue;	
				pwmWrite(pitchPwmPin,(int)pitch_value);
			}
		
		}
}

由于放不了视频只好将截图放上来了…
在这里插入图片描述

在这里插入图片描述

三、 项目总结

由于树莓派3B+有四路pwm分别是GPIO18和GPIO12,GPIO13和GPIO19,但是只有两路独立,因此我选择GPIO18和GPIO13,使用18控制云台的俯仰角,使用13控制云台的偏航角,之前不够了解树莓派的硬件导致浪费了很多时间。
在这里插入图片描述
整个项目的代码我打算放在Github上,有需要的同学可以去下载:
https://github.com/lvzhe-speed/program

下载的代码需要自己编译一下,就只有一个源文件,代码量很小,只是一个小的demo。由于我比较懒不太想为一个源文件创建一个Makefile,就采用命令的模式编译源码了。

1.编译的命令
g++ opencv_faceCheck.cpp -o faceCheck `pkg-config --libs --cflags opencv` -lwiringPi

2.执行的命令
sudo ./faceCheck 

之后我还会继续深入opencv和ffmpeg的项目学习中。

  • 11
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Keltop

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值