作为刚学习动态库的新手抑或是c++还未入门的菜狗(Me)来说,Linux编写动态库入门简单,无需复杂操作,因为Linux下gcc编译的执行文件默认是ELF格式,无需初始化入口,也无需对函数做特别声明,编写方便。
话不多说,直接上示例:

c++上机代码


#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/dnn/dnn.hpp>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <vector>

std::vector<std::string> CLASSES = { "occlusion" };

std::vector<int> nms(cv::Mat& dets, float thresh) {
   ...
    return keep;                                                               
}

cv::Mat xywh2xyxy(cv::Mat x) {                                                 
   ...
    return y;
}

cv::Mat filter_box(cv::Mat org_box, float conf_thres, float iou_thres) {
    ...
    return output;
}
 
void draw(cv::Mat& image, cv::Mat& box_data) {                                            
    for (int i = 0; i < box_data.rows; i++) {
        int left = box_data.at<float>(i, 0);
        int top = box_data.at<float>(i, 1);
        int right = box_data.at<float>(i, 2);
        int bottom = box_data.at<float>(i, 3);
        float score = box_data.at<float>(i, 4);
        int cls = static_cast<int>(box_data.at<float>(i, 5));

        std::cout << "class: " << CLASSES[cls] << ", score: " << score << std::endl;
        std::cout << "box coordinate left,top,right,down: [" << left << ", " << top << ", " << right << ", " << bottom << "]" << std::endl;

        cv::rectangle(image, cv::Point(left, top), cv::Point(right, bottom), cv::Scalar(255, 0, 0), 2);
        cv::putText(image, CLASSES[cls] + " " + std::to_string(score), cv::Point(left, top - 10), cv::FONT_HERSHEY_SIMPLEX, 0.6, cv::Scalar(0, 0, 255), 2);
    }
}

int main() {
    cv::dnn::Net net = cv::dnn::readNetFromONNX("/home/fortune/program_csj/idcard/best.onnx");
    cv::Mat img = cv::imread("/home/fortune/program_csj/idcard/1.bmp");
    cv::resize(img, img, cv::Size(640, 640));
    cv::Mat blob = cv::dnn::blobFromImage(img, 1 / 255.0, cv::Size(640, 640), cv::Scalar(0, 0, 0), true, false);
    net.setInput(blob);
    cv::Mat detection = net.forward();
    cv::Mat filtered_boxes = filter_box(detection, 0.25, 0.45);
    draw(img, filtered_boxes);
    cv::imshow("Detection Result", img);
    cv::waitKey(0);
    return 0;
}

由于我的代码由函数组成,所以为了创建动态库,首先创建一个新的类来封装这些函数。在类中定义这些函数作为类的成员函数。
将原本的全局变量转换为类的成员变量,如果有多个函数共享某个变量,将其定义为私有成员变量,并通过公有成员函数来访问和修改。
将原本的函数调用转换为类内部的函数调用,确保函数之间的逻辑关系正常。
如果有全局函数,可以将其转换为静态成员函数或者非成员函数,以便在类外直接调用。

封装后的代码:

#pragma once
#include "/home/fortune/program_csj/Encapsulation/pch.h"

ObjectDetector::ObjectDetector(const std::string& modelPath) {
    net_ = cv::dnn::readNetFromONNX(modelPath);
    classes_ = { "occlusion" };
}


void ObjectDetector::detectObjects(cv::Mat& image, float confThres, float iouThres) {
        cv::Mat blob = cv::dnn::blobFromImage(image, 1 / 255.0, cv::Size(640, 640), cv::Scalar(0, 0, 0), true, false);
        net_.setInput(blob);
        cv::Mat detection = net_.forward();
        cv::Mat filteredBoxes = filterBox(detection, confThres, iouThres);
        drawBoxes(image, filteredBoxes);
}



cv::dnn::Net net_;
std::vector<std::string> classes_;


std::vector<int> nms(cv::Mat& dets, float thresh) {
    ...

    return keep;    
}                                                           


cv::Mat xywh2xyxy(cv::Mat x) {                                                 
    ...
    return y;
}


cv::Mat filterBox(cv::Mat orgBox, float confThres, float iouThres) {
...
  
}
return output;


}

void drawBoxes(cv::Mat& image, cv::Mat& box_data) 
{                                            
    for (int i = 0; i < box_data.rows; i++) 
    {
	int left = box_data.at<float>(i, 0);
	int top = box_data.at<float>(i, 1);
	int right = box_data.at<float>(i, 2);
	int bottom = box_data.at<float>(i, 3);
	float score = box_data.at<float>(i, 4);
	int cls = static_cast<int>(box_data.at<float>(i, 5));

	std::cout << "class: " << classes_[cls] << ", score: " << score << std::endl;
	std::cout << "box coordinate left,top,right,down: [" << left << ", " << top << ", " << right << ", " << bottom << "]" << std::endl;

	cv::rectangle(image, cv::Point(left, top), cv::Point(right, bottom), cv::Scalar(255, 0, 0), 2);
	cv::putText(image, classes_[cls] + " " + std::to_string(score), cv::Point(left, top - 10), cv::FONT_HERSHEY_SIMPLEX, 0.6, cv::Scalar(0, 0, 255), 2);
    }
}

int main() {
ObjectDetector detector("/home/fortune/program_csj/encapsulation/best.onnx");
cv::Mat img = cv::imread("/home/fortune/program_csj/encapsulation/1.bmp");
cv::resize(img, img, cv::Size(640, 640));
detector.detectObjects(img, 0.25, 0.45);
cv::imshow("Detection Result", img);
cv::waitKey(0);
return 0;
}


生成动态库

首先,生成目标文件

  • g++ -fPIC -C pch.cpp
    -fPIC 创建与地址无关的编译程序,以实现在多个应用程序中共享。

然后生成动态库,此时要加上链接器选项-shared

  • g++ -shared -o libpch.so pch.o

    -shared 指定生成动态链接库
    g++: 是 GNU 编译器集合中的 C++ 编译器。
    -shared: 表示生成一个共享库。
    -o libpch.so: 指定生成的共享库的名称为 libpch.so, 注意名称以lib开头。
    pch.o: 是需要链接的目标文件,这里是指定了一个名为 pch.o 的目标文件。
    

上述两个命令亦可合并为;

  • g++ -fPIC -shared -o libpch.so pch.cpp

至此,动态库生成完毕。

更多推荐