用gcc生成静态库和动态库以及opencv的图像编程

目录
一、用gcc生成静态库和动态库文件的有关操作
二、有关gcc的编译及EFF文件
三、学习opencv图像库编程
四、总结

一、用gcc生成静态库和动态库文件的有关操作

静态库和动态库简述

  • 静态库
    在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库

  • 动态库
    在程序编译时并不会被连接到目标代码中,而是在程序运行时才被载入,因此程序运行时还需要动态库存在。
    1、gcc生成静态库和动态库
    (1)创建目录
    mkdir test1
    cd test1
    (2)编辑程序代码

  • hello.h


 1. #infdef HELLO_H
 2. #define HELLO_H
 3. void hello(const char *name);
 4. #endif//HELLO_H

  • hello.c
#include<stdio.h>
void hello(const char *name)
{
printf("Hello%s!\n",name);
}
  • main.c
#include"stdio.h"
int main()
{
hello("everyone");
return 0;
}

(3)gcc编译.o文件

gcc -c hello.c

在这里插入图片描述

(4)用.o文件创建静态库
创建工具:ar
命名规则:以lib为前缀,扩展名为.a

ar -crv libmyhello.a hello.o

在这里插入图片描述
(5)使用静态库

  • 方法一

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

在这里插入图片描述

  • 方法二

gcc main.c libmyhello.a -o hello

在这里插入图片描述

  • 方法三

gcc -c main.c
gcc -o hello main.o libmyhello.a

在这里插入图片描述
(6)由.o文件创建动态库文件
命名规范与静态库类似,前缀为lib,只是文件扩展名为.so

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

在这里插入图片描述
(7)在程序中使用动态库

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

在这里插入图片描述
这里显示出错,原因是找不到文件libmyhello.so,解决如下:

mv libmyhello.so/usr/lib

键入./hello,可以看到程序成功运行在这里插入图片描述
(8)测试静态库和动态库同名时gcc命令使用哪个文件

  • 首先先删除.c和.h外的所有文件,恢复编辑举例程序状态
    在这里插入图片描述
  • 创建静态库文件和动态库文件
    在这里插入图片描述
  • 运行gcc命令使用函数库myhello生成目标文件hello,并运行程序hello
    在这里插入图片描述
    可以发现,当静态库和动态库同名时,gcc命令会优先使用动态库,默认去连/usr/lib和/lib等目录中的动态库,将文件libmyhello.so复制到目录/usr/lib中即可

2、改编作业一,将x2x和x2y目标文件用ar工具生成.a静态库文件,并进行链接
(1)编辑三个子程序sub1.c,sub2.c,main1.c

  • x2x函数程序sub1.c
#include<stdio.h>
float x2x(int a,int b)
{
        return a*b;}
  • x2y函数程序sub2.c
#include<stdio.h>
float x2y(int a,int b)
{
        return a+b;}
  • main函数程序main.c
#include<stdio.h>
int main()
{
        float x2x(int a,int b);
        float x2y(int a,int b);
        int x1,x2;
        x1=4;
        x2=5;
        printf("%f %f\n",x2x(x1,x2),x2y(x1,x2));
        return 0;}                         

(2)用gcc将三个.c文件编译为.o目标文件

gcc -c sub1.c
gcc -c sub2.c
gcc -c main1.c

(3)将x2x,x2y目标文件生成1个.a静态库文件
在这里插入图片描述
(4)用gcc将main函数目标文件与静态库文件链接在这里插入图片描述
2、将x2x,x2y文件生成.so动态库文件
(1)生成目标文件在这里插入图片描述
(2)生成共享库.so文件在这里插入图片描述
(3)创建可执行程序在这里插入图片描述
在这里插入图片描述
找不到对应.so文件,需将对应.so文件拷贝到对应路径
在这里插入图片描述
在这里插入图片描述
再次执行./main1后,程序成功运行

二、有关gcc的编译及EFF文件

1、gcc的编译
(1)示例程序test.c

#include<stdio.h>
int main(void)
{
 printf("Hello World!\n");
        return 0;}

(2)一步编译指令

gcc test.c -o test

(3)实质上编译的四阶段

  • 预处理

gcc -E test.c -o test.i(或gcc -E test.c)

预处理代码

  • 编译为汇编代码

gcc -S test.i -o test.s

汇编代码
在这里插入图片描述

  • 汇编

gcc -c test.s -o test.o

  • 连接

gcc test.o -o test

动态链接可执行文件大小
在这里插入图片描述
静态链接可执行文件大小
在这里插入图片描述

(3)执行程序在这里插入图片描述
2、ELF文件的分析

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

text:已编译程序的指令代码
rodata:ro代表read only,即只读数据。
data:已初始化的C程序全局变量和静态局部变量,
bss:未初始化的C程序全局变量和静态局部变量。
debug:调试符号表,调试器用此段的信息帮助调试。

在这里插入图片描述
用readelf -S查看section的信息如下:

readelf -S

在这里插入图片描述

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

  • objdump -D的反汇编

objdump -D test

在这里插入图片描述

  • objdump -S反汇编并将其c语言源代码混合显示

gcc -o test -g test.c
objdump -S test

在这里插入图片描述

三、学习opencv图像库编程

安装链接opencv安装
1、图片转换

  • 创建code文件夹,进入code文件夹(这里我用touch code创建文件夹后进入文件夹显示code不是目录,我将其改成了mkdir code)

mkdir code
cd code

在这里插入图片描述

  • 创建test1.cpp文件

gedit test1.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++ test1.cpp -o test1 pkg-config --cflags --libs opencv

  • 在code文件夹下准备jpg图片,这里命名为lena.jpg在这里插入图片描述
    执行命令

./test1

由结果可看到lena.jpg变成test.png
在这里插入图片描述
2、视频

(1)播放视频

  • 虚拟机获取摄像头权限
    快捷键win+R。输入services.msc,点击确定在这里插入图片描述
    找到VMmare USB Aribitration S…服务,确保其显示正在…启动
    点击“虚拟机”,点击“设置”
    选择"USB控制器”,“USB兼容性”设置为“USB3.1”,点击确定在这里插入图片描述

原博主设置的是USB3.0,我这里只显示有3.1,所以选择了3.1

再点击“虚拟机”,选择“可移动设备”的IMC Networks USB2.0 VGA UVC WebCam选项,选择连接,弹出的窗口点击“确定”
在这里插入图片描述
连接成功显示,见界面右下角
在这里插入图片描述

  • 创建test2.cpp文件

gedit test2.cpp

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

准备一个视频scene.mp4
在这里插入图片描述

  • 编译test2.cpp文件

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

输出结果

./test2

在这里插入图片描述

(2) 录制视频

  • 创建一个test3.cpp文件

gedit test3.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;
}

保存后退出

  • 编译test3.cpp文件

g++ test3.cpp -o test3 pkg-config --cflags --libs opencv

输出结果

./test3

可以看到,生成了一个Record Video.avi文件,视频开始录制,不断生成帧。
在这里插入图片描述

3、
(1)如果要求打开硬盘上一个视频文件来播放,请问示例代码1第7行代码如何修改?
答:选择好想要打开的视频文件后,将代码1中第7行的capture(0)括号里的内容改为想要播放的视频文件名
(2)在示例代码1第9行的while循环中,Mat是一个什么数据结构? 为什么一定要加一句waitKey延时代码,删除它行不行?
答:while 循环体中的 Mat 数据结构其实是一个点阵,对应图像上的每一个点,点的集合形成了一帧图像。waitKey(30) 中的参数单位是 ms 毫秒,也就是每一帧间隔 30 ms ,其函数功能是不断刷新图像。该语句是不能删除的,否则会执行错误,无法播放视频或录制视频。
(3)示例代码1代码会在while循环中一直运行,你如果试图用鼠标关闭图像显示窗口,会发现始终关不掉。需要用键盘Ctrl+C 强制中断程序,非常不友好。如何改进?
答:改进方法是增加一个判断语句来进行关闭。

四、总结

这次实验,学习了gcc的编译的一步编译和四个阶段的编译过程,对于程序的执行过程有了较为深切的认识,以及静态库.a文件和动态库.so文件如何生成和使用,opencv图像编程功能中图片的转换显现和视频的播放录制,总的来说,学习到的很多,及时中间多重困难,但是有了前人的帮助,最后仍是成功做出了不得不说还是有点成就感的。

参考资料
gcc生成静态库和动态库
ubuntu下opencv3.4.11的安装和使用示例

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值