带你领略GDB和OpenCV


前言

调试在编程中是必不可少的,那如何在Ubuntu中进行调试呢,本文介绍了常用的GDB调试命令;摄像头在生活中的应用也是非常的广泛,本文手把手教你OpenCV入门。


一、GDB调试

首先我们编辑一个程序(用于调试),下面是一个整形数反转的程序

#include<stdio.h>
void ShowR(int iNum)          //整形数反转子程序
{
    
     
        while(iNum > 10)      //INum大于10时,进入循环
        {
    
     
        printf("%d",iNum%10);
        iNum=iNum/10;
        }
        printf("%d",iNum);
}
int main(void)
{
    
     
        int iNum;
        printf("Please input a numbrt:");
        scanf("%d",&iNum);
        printf("After revert:");
        ShowR(iNum);
}

启动GDB

启动GDB命令:

gcc -o ShowR -g ShowR.c   //编译
gdb ShowR    //调试

执行结果如下图所示:
GDB启动

gcc -g 选项

-g选项可以利用操作西永的“原生格式(native format)”生成调试信息、GDB可以直接利用这个信息,其他调试器也可以使用这个调试信息。

注意:如果想用调试器执行一个可执行文件,在GCC编译是必须加上 -g 选项

GDB部分调试命令

GDB查看代码命令

(gdb) l(ist) // ( 字母 l ) 从第一行开始列出源码,共列出10行。

扫描二维码关注公众号,回复: 12088708 查看本文章

执行结果如下图所示:
在这里插入图片描述
若想继续查看接下来的代码,可以直接 空格 或继续使用 l 命令,然后敲回车键,使用空格键查看接下来的命令如下图所示:
在这里插入图片描述
也可以使用数字命令,直接显示 某行 - 某行

(gdb) l 数字 ,数字

如下图所示
在这里插入图片描述
GDB设置断点命令

以行数设置断点:

(gdb) b(reakpoint) 数字

数字为设置断点的行数,示例如下图所示,(提示设置断点成功):
在这里插入图片描述
也可以通过函数名设置断点:

(gdb) b 函数名

示例如下图所示(提示第二个断点设置成功):
在这里插入图片描述
可以通过命令查看断点信息:

info b(reakpoint)

示例如下图所示:
在这里插入图片描述

GDB程序运行命令

GDB运行程序命令

(gdb) run

运行程序至断点处,会停止运行,查看断点行,然后输入 c(ontinue) 之后,可以继续运行,如下图所示:

(gdb) c

在这里插入图片描述
在调试过程中,如果需要查看参数类型,可以使用 whatis 命令,示例如下图所示:

whatis 参数

在这里插入图片描述
在调试过程中,如果需要查看参数的值,可以将参数值打印出来,使用 p(rint) 命令,示例如下图所示:

(gdb) p(rint)

在这里插入图片描述

常用的GDB命令

二、Ubuntu下的OpenCV

下载安装OpenCV

首先我们需要下载一个OpenCV的安装包,可以在官网下载,可以在Linux系统中下载,不过这样下载会比较慢,博主是直接下载到Windows系统中,然后复制到Linux系统中的,复制到Linux中的压缩包如下图所示。
在这里插入图片描述
然后进入到压缩包所在路径,对压缩包解压:

unzip opencv-3.4.1.zip

注意:版本有可能会不相同哦!

解压缩之后,文件中会有两个文件,一个是压缩包,一个是解压缩后的文件夹,如下图所示:
在这里插入图片描述
进入到opencv-3.4.1文件夹中:

cd opencv-3.4.1

如下图所示:
在这里插入图片描述
安装依赖库和cmake,如果提醒需要apt-get update,那就需要先进入root权限,再执行下面的命令:

sudo apt-get install cmake

执行结果如下图所示:
在这里插入图片描述

再执行以下命令:

sudo apt-get install build-essential libgtk2.0-dev libavcodec-dev libavformat-dev libjpeg.dev libtiff5.dev libswscale-dev libjasper-dev  

执行结果如下图所示:
温馨提示:此过程也需要耐心等待。
在这里插入图片描述

安装完成cmake之后,创建一个编译文件夹,然后进入文件夹内进行配置:

mkdir hy_by_dir
cd hy_by_dir
cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local ..

在这里插入图片描述

执行命令,开始漫长的编译过程:

sudo make 

在这里插入图片描述
漫长的等待后(博主等了大概两小时):
在这里插入图片描述
执行命令:

sudo make install

到此,就完成了OpenCV的下载安装工作,接下来就需要对OpenCV进行配置,输入命令:

sudo gedit /etc/ld.so.conf.d/opencv.conf

执行命令后,会出现一个空白的文件,此时需要在文件中输入:

/usr/local/lib 

保存后回到输命令的界面,执行命令:

sudo ldconfig  
sudo gedit /etc/bash.bashrc  

并在出现的文件的末尾添加:

PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig  
export PKG_CONFIG_PATH  

如下图所示:
在这里插入图片描述
黑框部分为添加的代码。
保存后退出,执行以下命令,并进行更新:

source /etc/bash.bashrc  
sudo updatedb

欧耶,配置完成!接下来,我们试试做图片的特效。

图片特效

首先创立一个文件夹,并到此文件夹下,编辑一个特效图像的函数:

mkdir hytest
cd hytest
touch hyimage.cpp
nano hyimage.cpp

hyimage.cpp 的内容如下所示:

#include <opencv2/highgui.hpp>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
    
    
        CvPoint center;
    double scale = -3; 

        IplImage* image = cvLoadImage("iu.jpg");      //注意对应图像的名称及后缀
        argc == 2? cvLoadImage(argv[1]) : 0;
        
        cvShowImage("Image", image);
        
        
        if (!image) return -1;  center = cvPoint(image->width / 2, image->heigh$
        for (int i = 0;i<image->height;i++)
                for (int j = 0;j<image->width;j++) {
    
    
                        double dx = (double)(j - center.x) / center.x;
                        double dy = (double)(i - center.y) / center.y;
                        double weight = exp((dx*dx + dy*dy)*scale);
                        uchar* ptr = &CV_IMAGE_ELEM(image, uchar, i, j * 3);
                        ptr[0] = cvRound(ptr[0] * weight);
                        ptr[1] = cvRound(ptr[1] * weight);
                        ptr[2] = cvRound(ptr[2] * weight);
                }

        Mat src;Mat dst;
        src = cvarrToMat(image);
        cv::imwrite("hyimage.png", src);     //生成图像的名称及后缀
    	cvNamedWindow("hyimage",1);
        imshow("hyimage", src);
        cvWaitKey();
        return 0;
}

执行命令,将.cpp文件生成可执行.exe文件(如果 gcc 不成功,可以换成 g++ 试试):

g++ hyimage.cpp -o hyimage `pkg-config --cflags --libs opencv`

执行结果如下图所示:
在这里插入图片描述

将图像从Windows系统复制到Linux系统中:
在这里插入图片描述
注意更改图像的名称哦!程序里面的图像名称要与文件夹中图像名称一致。
运行可执行文件:

./hyimage

执行结果如下图所示:
在这里插入图片描述

左边为原始图像,右边为特效后的图像;红色框为原始图像文件,黄色框为生成的图像文件。图像特效完成!

注意:
① 图像所在位置要与.cpp的位置在一个文件夹下,不然编译可能会出错;
② 也可以将 IplImage* image = cvLoadImage(“iu.jpg”); 改为绝对路径。

视频播放

依然在我们创立的文件夹下面,创建一个 .cpp 的文件,文件内容如下:

#include <opencv2/opencv.hpp>
using namespace cv;
int main()
{
    
    
  VideoCapture capture("Clouds.mp4");
  while(1)
  {
    
    
     Mat frame;
     capture >> frame; 
     imshow("读取视频帧",frame);
     waitKey(30);
   }
     system("pause");
     return 0;
}

再将一个视频添加到该目录下,可以直接在Windows系统中复制到Linux系统中,播放的视频支持.mp4和.avi格式:
在这里插入图片描述

注意:第五行的函数参数为视频名称及后缀,保证与文件夹中的视频名称及后缀对应。

如果你的视频文件和创建的.cpp文件不再同一目录下,需要在第五行函数参数中加上绝对路径。

视频文件添加好了,就可以试一下能否播放出视频。双击视频,如果能够播放出,则不需要一下操作;如果不能播放出,则按照系统提示下载插件即可。
此时,如果你直接编译运行程序,就会出现如下错误:
在这里插入图片描述

原因是你没有将你的摄像头设置在Ubuntu系统下,此时,你需要在Windows系统下运行 Win+R,然后执行语句 services.msc :
在这里插入图片描述
查看此选项是否启动,若没启动,则点击启动:
在这里插入图片描述
将虚拟机设置中的 USB 兼容性换成 USB 3.0 :
在这里插入图片描述
点击虚拟机,将摄像头连接到虚拟机:
在这里插入图片描述
温馨提示:如果换成兼容性换成 USB 3.0还是不成功,就换成 USB 2.0 或者 USB 1.1试试,总会有一款是兼容的。

如何查看自己的摄像头是否能够启用了?输入命令cheese如果有图像显示,则表明摄像头已经在虚拟机中启用,示例如下图所示:
在这里插入图片描述
此时就可以编译,运行程序了:

g++ hyvideo.cpp -o hyvideo `pkg-config --cflags --libs opencv`
./hyvideo

运行结果如下图所示:
在这里插入图片描述

疑难杂症

①如果要求打开你硬盘上一个视频文件来播放,请问VideoCapture capture(0)行代码如何修改?
修改为自己存储图像文件的目录及名称和后缀;若已在与.cpp相同的文件夹下,则只需要添加名称和后缀参数。

②在while循环中,Mat是一个什么数据结构? 为什么一定要加一句waitKey延时代码,删除它行不行?
Mat本质上是由两个数据部分组成的类:(包含信息有矩阵的大小,用于存储的方法,矩阵存储的地址等)的矩阵头和一个指针,指向包含了像素值的矩阵(可根据选用于存储的方法采用任何维度存储数据)。
Mat的第一件事是你不再需要手动分配其大小并且当你不需要它的时候,你不再需要手动释放它(自动内存管理)。
加了waitKey延时代码后,才能播放视频;如果删除延时代码,将不能观察到视频播放。
特殊:当waitKey的参数为0时,即waitKey(0),此时程序会无限制等待用户按下按键。

③此代码会在while循环中一直运行,你如果试图用鼠标关闭图像显示窗口,会发现始终关不掉。需要用键盘Ctrl+C 强制中断程序,非常不友好。如何改进?
在循环代码中加入条件语句:
if ( !cvGetWindowHandle ( " 窗口名字 " ) )
{
break;
}
此时就可以直接点击左上方的“×”号,直接结束程勋运行。

视频录制及保存

这里还有一种升级版代码,可以录制视频,并保存到本地文件夹中,程序示例如下:

#include<iostream>
#include <opencv2/opencv.hpp>
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
using namespace cv;
using namespace std;

int main()
{
    
    
	//打开电脑摄像头
	VideoCapture cap(0);
	if (!cap.isOpened())
	{
    
    
		cout << "error" << endl;
		waitKey(0);
		return 0;
	}

	//获得cap的分辨率
	int w = static_cast<int>(cap.get(CV_CAP_PROP_FRAME_WIDTH));
	int h = static_cast<int>(cap.get(CV_CAP_PROP_FRAME_HEIGHT));
	Size videoSize(w, h);
	VideoWriter writer("RecordVideo.avi", CV_FOURCC('M', 'J', 'P', 'G'), 25, videoSize);
	
	Mat frame;
	int key;//记录键盘按键
	char startOrStop = 1;//0  开始录制视频; 1 结束录制视频
	char flag = 0;//正在录制标志 0-不在录制; 1-正在录制

	while (1)
	{
    
    
		cap >> frame;
		key = waitKey(100);
		if (key == 32)//按下空格开始录制、暂停录制   可以来回切换
		{
    
    
			startOrStop = 1 - startOrStop;
			if (startOrStop == 0)
			{
    
    
				flag = 1;
			}
		}
		if (key == 27)//按下ESC退出整个程序,保存视频文件到磁盘
		{
    
    
			break;
		}

		if (startOrStop == 0 && flag==1)
		{
    
    
			writer << frame;
			cout << "recording" << endl;
		}
		else if (startOrStop == 1)
		{
    
    
			flag = 0;
			cout << "end recording" << endl;
			
		}
		imshow("picture", frame);
	}
	cap.release();
	writer.release();
	destroyAllWindows();
}

按下空格键录制视频和暂停录制:

在这里插入图片描述
录制的视频将存储在该目录下:
在这里插入图片描述
红色框为录制保存的视频。

三、总结

在Linux中,我们可以使用GDB来进行对程序的调试;此次学习OpenCV之后,对其有了初步的了解,OpenCV的海洋很深,等待着我们遨游。
加油吧,读书人!

猜你喜欢

转载自blog.csdn.net/guyuewangyue/article/details/109328010