gcc生成静态库和动态库&opencv图像库编程

目录

一.用gcc生成静态库和动态库

1.编辑生成程序hello.h,hello.c,main.c

2. gcc编译得到.o文件

 3.静态库使用

(1).创建静态库

 (2).使用静态库

(3).验证静态库的特点

 4.动态库使用

(1). 创建动态库

(2). 在程序中执行动态库

5.当静态库和动态库同名时,gcc 命令会优先使用动态库

 6.具体例子运用

(1).程序代码

 (2).静态库

(3)动态库

 (4).静态库与动态库的生成文件的比较

二.Linux GCC常用命令

 1.程序代码test.c

2. 预处理

3.编译

4.汇编 

5.连接

6.多个程序文件的编译 

7. 检错

8.库文件连接 

9.size

三.ELF文件 

1.ELF 文件的段

2.反汇编 ELF

 四.opencv图像库编程

1.安装OpenCV

2.编写一个打开图片进行特效显示的代码 test1.cpp

解释g++命令:

3.使用视频

(1).虚拟机获取摄像头权限

(2).播放视频

问题1).播放上一个视频文件代码

问题2).MAT数据结构、waitKey()这个函数

问题3).程序改进

(3).录制视频

 总结

参考文献:



一.用gcc生成静态库和动态库

函数库分为静态库和动态库两种。
静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。动态库在程
序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需
要动态库存在。

1.编辑生成程序hello.h,hello.c,main.c

hello.h代码:

hello.c代码:

main.c代码:

2. gcc编译得到.o文件

 3.静态库使用

(1).创建静态库


   创建静态库的工具:ar 静态库文件命名规范:以lib作为前缀,是.a文件

ar -crv libmyhello.a hello.o

 (2).使用静态库

gcc -o hello main.c -L. -lmyhello

 gcc main.c libmyhello.a -o hello

 先生成main.o gcc -c main.c,生成可执行文件 gcc -o hello main.c libmyhello.a

(3).验证静态库的特点


在删掉静态库的情况下,运行可执行文件,发现程序仍旧正常运行,表明静态库跟程序执行没有联系。同时,也表明静态库是在程序编译的时候被连接到代码中的。

 4.动态库使用

(1). 创建动态库


创建动态库的工具:gcc,动态库文件命名规范:以lib作为前缀,是.so文件

gcc -shared -fPIC -o libmyhello.so hello.o

(2). 在程序中执行动态库


gcc main.c libmyhello.so -o hello或gcc -o hello main.c -L. -lmyhello

 再运行可执行文件hello,会出现错误。问题的解决方法:将libmyhello.so复制到目录/usr/lib中。因为运行时,是在/usr/lib中找库文件的。mv libmyhello.so /usr/lib

如果权限不够 则使用sudo解决  sudo mv libmyhello.so /usr/lib

5.当静态库和动态库同名时,gcc 命令会优先使用动态库

 6.具体例子运用

(1).程序代码

sub1.c

sub2.c sub.h

 main.c

 gcc -c sub1.c sub2.c

 (2).静态库

  1. 创建静态库:ar crv libsub.a sub1.o sub2.o
  2. 使用静态库:gcc -o main main.c libsub.a

(3)动态库

  1. 创建动态库:gcc -shared -fPIC -o libsub.so sub1.o sub2.o
  2. 使用动态库:gcc -o main main.c libsub.so

使用动态库时:将libsub.so复制到目录/usr/lib中。由于运行时,是在/usr/lib中找库文件的。

 mv libsub.so /usr/lib

 (4).静态库与动态库的生成文件的比较

静态库:

 动态库:

 通过对比发现静态库要比动态库小很多,生成的执行文件也有区别。

二.Linux GCC常用命令

 1.程序代码test.c

2. 预处理

gcc -E test.c -o test.i 或 gcc -E test 。可以输出 test.i 文件中存放着 test.c 经预处理之后的代码。

3.编译

编译为汇编代码(Compilation) 预处理之后,可直接对生成的 test.i 文件编译,生成汇编代码: gcc -S test.i -o。gcc 的-S 选项,表示在程序编译期间,在生成汇编代码后,停止,-o 输出汇编代码文件。

4.汇编 

汇编(Assembly) 对于上一小节中生成的汇编代码文件 test.s,gas 汇编器负责将其编译为目标文件,如下: gcc -c test.s -o test.o 

5.连接

连接(Linking) gcc 连接器是 gas 提供的,负责将程序的目标文件与所需的所有附加的目标文件连接起来,最终生 成可执行文件。附加的目标文件包括静态连接库和动态连接库。 对于上一小节中生成的 test.o,将其与C标准输入输出库进行连接,最终生成程序 test gcc test.o -o test 

6.多个程序文件的编译 

test.c

 test1.c

 test2.c

 t.h

 生成两个.o文件

gcc -c test1.c -o test1.o
gcc -c test2.c -o test2.o

连接test1.o,test2.o文件与test.c文件

gcc test1.o test2.o test.c -o test

7. 检错

-pedantic 选项能够帮助程序员发现一些不符合 ANSI/ISO C 标准的代码,

 gcc -pedantic test.c -o test

除了-pedantic外还有-Wall,使用它能够使 GCC 产生尽可能多的警告信息

gcc -Wall test.c -o test

 在编译程序时带上-Werror 选项,那 么 GCC 会在所有产生警告的地方停止编译,迫使程序员对自己的代码进行修改.

gcc -Werror test.c -o test

8.库文件连接 

编译成可执行文件

默认情况下, GCC 在链接时优先使用动态链接库,只有当动态链接库不存在时才考虑使用静态链 接库,如果需要的话可以在编译时加上-static 选项,强制使用静态链接库。

gcc -c -I /usr/dev/mysql/include test.c -o test.o

链接:

gcc -L /usr/dev/mysql/lib -lmysqlclient test.o -o test

强制链接时使用静态链接库

 gcc -L /usr/dev/mysql/lib -static -lmysqlclient test.o -o test

9.size

使用size查看大小,size test。

三.ELF文件 

1.ELF 文件的段

ELF 文件的段 ELF 文件格式如下图所示,位于 ELF Header 和 Section Header Table 之间的都 是段(Section)。一个典型的 ELF 文件包含下面几个段:

 .text:已编译程序的指令代码段。

.rodata:ro 代表 read only,即只读数据(譬如常数 const)。

.data:已初始化的 C 程序全局变量和静态局部变量。

.bss:未初始化的 C 程序全局变量和静态局部变量。

.debug:调试符号表,调试器用此段的信息帮助调试

 可以使用 readelf -S 查看其各个 section 的信息如下: $ readelf -S

readelf -S test

2.反汇编 ELF

由于 ELF 文件无法被当做普通文本文件打开,如果希望直接查看一个 ELF 文件包 含的指令和数据,需要使用反汇编的方法。

使用 objdump -D 对其进行反汇编如下: $ objdump -D test ……

使用 objdump -S 将其反汇编并且将其 C 语言源代码混合显示出来:

gcc -o test -g test.c //要加上-g 选项 

objdump -S hell

 四.opencv图像库编程

1.安装OpenCV

下载 OpenCV 3.4.11 数据包下载地址:OpenCV/opencv_contrib国内快速下载 | 绕云技术笔记

在解压缩包之前,将 opencv-3.4.11.zip 复制到 home 文件夹下,再解压缩。

 1.解压:unzip opencv-3.4.11.zip 

 

使用 cmake 安装 opencv

首先进入解压后的文件夹:opencv-3.4.11

cd opencv-3.4.11

首先进入 root 用户,并更新一下。

sudo su
sudo apt-get update

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

再创建 build 文件夹。

mkdir build

然后进入我们创建的文件夹:build

cd build

 使用 cmake 编译参数,或者使用第二条默认参数,都可以的。

 cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local ..
cmake ..

使用 make 创建编译

仍然是在 build 文件夹下进行。

sudo make

 

安装

sudo make install

 

sudo apt-get install cmake

配置环境

修改 opencv.conf 文件,打开后的文件是空的,添加 opencv 库的安装路径:/usr/local/lib

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

 

更新系统共享链接库

sudo ldconfig

在这里插入图片描述
配置 bash ,修改 bash.bashrc 文件

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

在这里插入图片描述
接下来查看 opencv 的版本信息。

pkg-config --modversion opencv

在这里插入图片描述

 就此安装成功。

2.编写一个打开图片进行特效显示的代码 test1.cpp

(1).代码:首先创建一个代码存放文件夹 mytest ,然后进入文件夹中。

mkdir mytest
cd opencv/opencv-3.4.11/mytest

创建一个 test.cpp 文件。

gedit test.cpp

 test.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("lena.jpg");
	argc == 2? cvLoadImage(argv[1]) : 0;
	
	cvShowImage("Image", image);
	
	
	if (!image) return -1; 	center = cvPoint(image->width / 2, image->height / 2);
	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("test.png", src);

    cvNamedWindow("test",1);  	imshow("test", src);
	 cvWaitKey();
	 return 0;
}

编译文件:

解释g++命令:

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

gcc编译器:g++ + 文件名 + -o + 输出文件流名称 +` 支持包

其中pkg-config是一个linux下的命令,用于获得某一个库/模块的所有编译相关的信息(包括头文件和库的所有信息)

 —cflags 是用来指定程序在编译时所需要头文件所在的目录

 —libs则是指定程序在链接时所需要的动态链接库的目录

在用同文件夹下准备一张图片,文件名为:lena.jpg

最后执行以下命令:

./test

3.使用视频







(1).虚拟机获取摄像头权限

 使用快捷键 Win + R ,输入 services.msc ,并回车。

找到 VMware USB Arbitration S… 服务,确保启动了。

点击 “ 虚拟机 ” ,然后点击 “ 设置(S)… ”。

虚拟机右下角这个摄像头图标有个小绿点,则连接成功。 

(2).播放视频

创建一个 test1.cpp 文件。

gedit test1.cpp

将以下代码复制粘贴进去。
test1.cpp:

test2.cpp:

#include <opencv2/opencv.hpp>
using namespace cv;
int main()
{
	//从摄像头读取视频
	VideoCapture capture("man.mp4");
	//循环显示每一帧
	while(1){
		Mat frame;//定义一个Mat变量,用于存储每一帧的图像
		capture >> frame;//读取当前帧
		if(frame.empty())//播放完毕,退出
			break;
		imshow("读取视频帧",frame);//显示当前帧
		waitKey(30);//掩饰30ms
	}
	system("pause");
	return 0;
}

问题1).播放上一个视频文件代码

如果要求打开你硬盘上一个视频文件来播放,请问示例代码1第7行代码如何修改?

修改代码

VideoCapture capture(“video_20201030_203850.mp4”);

问题2).MAT数据结构、waitKey()这个函数

Mat本质上是由两个数据部分组成的类: (包含信息有矩阵的大小,用于存储的方法,矩阵存储的地址等) 的矩阵头和一个指针,指向包含了像素值的矩阵(可根据选择用于存储的方法采用任何维度存储数据)。

waitKey()这个函数是在一个给定的时间内(单位ms)等待用户按键触发;
如果用户没有按下键,返回值为-1,并关闭当前显示的窗口;
如果用户按下键,则返回对于按键的ASCII码值,并关闭当前显示的窗口;waitKey()与waitKey(0),都代表无限等待,程序会无限制的等待用户的按键(适用于图像显示)  删掉不行。

问题3).程序改进

示例代码1代码会在while循环中一直运行,你如果试图用鼠标关闭图像显示窗口,会发现始终关不掉。需要用键盘Ctrl+C 强制中断程序,非常不友好。如何改进?
代码改进如下:

#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();
        return 0;
}

准备一个小视频,命名与代码中相同的名称 man.mp4 。

编译 test1.cpp 文件。

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

运行结果:./test1

(3).录制视频

创建test2.cpp 文件

gedit test2.cpp

编写代码
test2.cpp 

 /*********************************************************************
打开电脑摄像头,空格控制视频录制,ESC退出并保存视频RecordVideo.avi
*********************************************************************/
#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();
	return 0;
}

编译文件

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

运行程序

./test2

录制效果

 

 总结

  本次实验内容较多,遇到的问题也很多,比如在安装opencv,配置环境过程中可能出了错,导致最后不能运行结果,经过多方参考资料和同学帮助最后成功安装,其中博客中也有部分内容是转载的别人的内容。然后在打开摄像头的环节也出了一些小问题。总之,大家在安装时一定耐心,不同版本也会有不同的问题,慢慢搜索和查阅资料最后能成功。

参考文献:

Ubuntu18.04下OpenCV3.4.11的安装及使用示例_ssj925319的博客-CSDN博客

gcc生成静态库.a和动态库.so_Harriet的博客-CSDN博客

Ubuntu下Opencv安装与使用_星&&河的博客-CSDN博客

第七周作业 嵌入式程序调试与opencv图像库_Ether113的博客-CSDN博客

浏览

猜你喜欢

转载自blog.csdn.net/SS_SS_SSS_SSS/article/details/120667348
今日推荐