60、使用MNN+DBNET进行二维码检测

news2024/12/29 9:12:44

基本思想:顺手转了个模型,可以方便进行条形码和对应的数字检测,以方便下一步进行条形码识别和ocr进行数字检测(这里只检测暂不识别,识别暂定下一篇)

cmakelists.txt

cmake_minimum_required(VERSION 3.16)
project(untitled22)
set(CMAKE_CXX_FLAGS "-std=c++11")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fopenmp ")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp")
set(CMAKE_CXX_STANDARD 11)
include_directories(${CMAKE_SOURCE_DIR})
include_directories(${CMAKE_SOURCE_DIR}/include)
include_directories(${CMAKE_SOURCE_DIR}/include/MNN)
find_package(OpenCV REQUIRED)
#message(STATUS ${OpenCV_INCLUDE_DIRS})
#添加头文件
include_directories(${OpenCV_INCLUDE_DIRS})
#链接Opencv库

add_library(libmnn SHARED IMPORTED)
set_target_properties(libmnn PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/lib/libMNN.so)


add_executable(untitled22 main.cpp)
target_link_libraries(untitled22 ${OpenCV_LIBS} libmnn )

main.cop

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include<MNN/Interpreter.hpp>
#include<MNN/ImageProcess.hpp>


using namespace cv;
using namespace std;

class DBNet {
public:
    DBNet(const float binaryThreshold = 0.5, const float polygonThreshold = 0.7, const float unclipRatio = 1.5,
          const int maxCandidates = 1000);

    void detect(Mat &srcimg);

private:
    float binaryThreshold;
    float polygonThreshold;
    float unclipRatio;
    int maxCandidates;
    const int inpWidth = 736;
    const int inpHeight = 736;
    const float meanValues[3] = {0.485, 0.456, 0.406};
    const float normValues[3] = {0.229, 0.224, 0.225};

    float contourScore(const Mat &binary, const vector<Point> &contour);

    void unclip(const vector<Point2f> &inPoly, vector<Point2f> &outPoly);


};

DBNet::DBNet(const float binaryThreshold, const float polygonThreshold, const float unclipRatio,
             const int maxCandidates) {
    cout << "run dbnet" << endl;
    this->binaryThreshold = binaryThreshold;
    this->polygonThreshold = polygonThreshold;
    this->unclipRatio = unclipRatio;
    this->maxCandidates = maxCandidates;
    //OrtStatus* status = OrtSessionOptionsAppendExecutionProvider_CUDA(sessionOptions, 0);  gpu

}

void DBNet::detect(Mat &srcimg) {
    int h = srcimg.rows;
    int w = srcimg.cols;
    Mat dst;
    resize(srcimg, dst, Size(this->inpWidth, this->inpHeight));

    auto mnnNet = std::shared_ptr<MNN::Interpreter>(
            MNN::Interpreter::createFromFile("../best.mnn"));
    auto t1 = std::chrono::steady_clock::now();
    MNN::ScheduleConfig netConfig;
    netConfig.type = MNN_FORWARD_CPU;
    netConfig.numThread = 4;

    auto session = mnnNet->createSession(netConfig);
    auto input = mnnNet->getSessionInput(session, nullptr);

    mnnNet->resizeTensor(input, {1, 3, (int) inpWidth, (int) inpHeight});
    mnnNet->resizeSession(session);
    MNN::CV::ImageProcess::Config config;

    const float mean_vals[3] = {255 * 0.485, 255 * 0.456, 255 * 0.406};

    const float norm_255[3] = {1 / (255 * 0.229), 1 / (255 * 0.224), 1 / (255 * 0.225)};

    std::shared_ptr<MNN::CV::ImageProcess> pretreat(
            MNN::CV::ImageProcess::create(MNN::CV::BGR, MNN::CV::RGB, mean_vals, 3,
                                          norm_255, 3));

    pretreat->convert(dst.data, (int) inpWidth, (int) inpHeight, dst.step[0], input);

    MNN::Tensor inputHost(input, input->getDimensionType());
    input->copyToHostTensor(&inputHost);



    mnnNet->runSession(session);


    auto output = mnnNet->getSessionOutput(session, "output");

    MNN::Tensor outputHost(output, output->getDimensionType());
    output->copyToHostTensor(&outputHost);

    int shape_h = outputHost.height();
    int shape_c = outputHost.channel();
    int shape_w = outputHost.width();
    int shape_s = outputHost.size();
    printf("---c= %d  w= %d h= %d s= %d ----\n", shape_c, shape_w, shape_h, shape_s);


  //  for (int i = 0; i < shape_s; i++) { outputCount.push_back(outputHost.host<float>()[i]); }

    const float *floatArray = outputHost.host<float>();
//    for (int i = 0; i < shape_s; i++){
//        std::cout<<floatArray[i]<<" ";
//        if(i==100) break;
//    }
    Mat binary(dst.rows, dst.cols, CV_32FC1);
    memcpy(binary.data, floatArray, shape_s/4* sizeof(float));

    // Threshold
    Mat bitmap;
    threshold(binary, bitmap, binaryThreshold, 255, THRESH_BINARY);
    //cv::imshow("", binary);
    // Scale ratio
    float scaleHeight = (float) (h) / (float) (binary.size[0]);
    float scaleWidth = (float) (w) / (float) (binary.size[1]);
    // Find contours
    vector<vector<Point> > contours;
    bitmap.convertTo(bitmap, CV_8UC1);
    findContours(bitmap, contours, RETR_LIST, CHAIN_APPROX_SIMPLE);

    // Candidate number limitation
    size_t numCandidate = min(contours.size(), (size_t) (maxCandidates > 0 ? maxCandidates : INT_MAX));
    vector<float> confidences;
    vector<vector<Point2f> > results;
    for (size_t i = 0; i < numCandidate; i++) {
        vector<Point> &contour = contours[i];

        // Calculate text contour score
        if (contourScore(binary, contour) < polygonThreshold)
            continue;

        // Rescale
        vector<Point> contourScaled;
        contourScaled.reserve(contour.size());
        for (size_t j = 0; j < contour.size(); j++) {
            contourScaled.push_back(Point(int(contour[j].x * scaleWidth),
                                          int(contour[j].y * scaleHeight)));
        }

        // Unclip
        RotatedRect box = minAreaRect(contourScaled);

        // minArea() rect is not normalized, it may return rectangles with angle=-90 or height < width
        const float angle_threshold = 60;  // do not expect vertical text, TODO detection algo property
        bool swap_size = false;
        if (box.size.width < box.size.height)  // horizontal-wide text area is expected
            swap_size = true;
        else if (fabs(box.angle) >= angle_threshold)  // don't work with vertical rectangles
            swap_size = true;
        if (swap_size) {
            swap(box.size.width, box.size.height);
            if (box.angle < 0)
                box.angle += 90;
            else if (box.angle > 0)
                box.angle -= 90;
        }

        Point2f vertex[4];
        box.points(vertex);  // order: bl, tl, tr, br
        vector<Point2f> approx;
        for (int j = 0; j < 4; j++)
            approx.emplace_back(vertex[j]);
        vector<Point2f> polygon;
        unclip(approx, polygon);
        results.push_back(polygon);
    }
    confidences = vector<float>(contours.size(), 1.0f);
    for (int i = 0; i < results.size(); i++) {
        for (int j = 0; j < 4; j++) {
            circle(srcimg, Point((int) results[i][j].x, (int) results[i][j].y), 2, Scalar(0, 0, 255), -1);
            if (j < 3) {
                line(srcimg, Point((int) results[i][j].x, (int) results[i][j].y),
                     Point((int) results[i][j + 1].x, (int) results[i][j + 1].y), Scalar(0, 255, 0));
            } else {
                line(srcimg, Point((int) results[i][j].x, (int) results[i][j].y),
                     Point((int) results[i][0].x, (int) results[i][0].y), Scalar(0, 255, 0));
            }
        }
    }
}

float DBNet::contourScore(const Mat &binary, const vector<Point> &contour) {
    Rect rect = boundingRect(contour);
    int xmin = max(rect.x, 0);
    int xmax = min(rect.x + rect.width, binary.cols - 1);
    int ymin = max(rect.y, 0);
    int ymax = min(rect.y + rect.height, binary.rows - 1);

    Mat binROI = binary(Rect(xmin, ymin, xmax - xmin + 1, ymax - ymin + 1));

    Mat mask = Mat::zeros(ymax - ymin + 1, xmax - xmin + 1, CV_8U);
    vector<Point> roiContour;
    for (size_t i = 0; i < contour.size(); i++) {
        Point pt = Point(contour[i].x - xmin, contour[i].y - ymin);
        roiContour.push_back(pt);
    }
    vector<vector<Point>> roiContours = {roiContour};
    fillPoly(mask, roiContours, Scalar(1));
    float score = mean(binROI, mask).val[0];
    return score;
}

void DBNet::unclip(const vector<Point2f> &inPoly, vector<Point2f> &outPoly) {
    float area = contourArea(inPoly);
    float length = arcLength(inPoly, true);
    float distance = area * unclipRatio / length;

    size_t numPoints = inPoly.size();
    vector<vector<Point2f>> newLines;
    for (size_t i = 0; i < numPoints; i++) {
        vector<Point2f> newLine;
        Point pt1 = inPoly[i];
        Point pt2 = inPoly[(i - 1) % numPoints];
        Point vec = pt1 - pt2;
        float unclipDis = (float) (distance / norm(vec));
        Point2f rotateVec = Point2f(vec.y * unclipDis, -vec.x * unclipDis);
        newLine.push_back(Point2f(pt1.x + rotateVec.x, pt1.y + rotateVec.y));
        newLine.push_back(Point2f(pt2.x + rotateVec.x, pt2.y + rotateVec.y));
        newLines.push_back(newLine);
    }

    size_t numLines = newLines.size();
    for (size_t i = 0; i < numLines; i++) {
        Point2f a = newLines[i][0];
        Point2f b = newLines[i][1];
        Point2f c = newLines[(i + 1) % numLines][0];
        Point2f d = newLines[(i + 1) % numLines][1];
        Point2f pt;
        Point2f v1 = b - a;
        Point2f v2 = d - c;
        float cosAngle = (v1.x * v2.x + v1.y * v2.y) / (norm(v1) * norm(v2));

        if (fabs(cosAngle) > 0.7) {
            pt.x = (b.x + c.x) * 0.5;
            pt.y = (b.y + c.y) * 0.5;
        } else {
            float denom = a.x * (float) (d.y - c.y) + b.x * (float) (c.y - d.y) +
                          d.x * (float) (b.y - a.y) + c.x * (float) (a.y - b.y);
            float num = a.x * (float) (d.y - c.y) + c.x * (float) (a.y - d.y) + d.x * (float) (c.y - a.y);
            float s = num / denom;

            pt.x = a.x + s * (b.x - a.x);
            pt.y = a.y + s * (b.y - a.y);
        }
        outPoly.push_back(pt);
    }
}

int main() {
    DBNet mynet(0.3, 0.3, 4.5, 1000);
    string imgpath = "../testimgs/3.jpg";
    Mat srcimg = imread(imgpath);
    mynet.detect(srcimg);

    imshow("kWinName", srcimg);
    waitKey(0);
    destroyAllWindows();
}

测试结果

链接: https://pan.baidu.com/s/1qVAKk5b_nxHjIW6xF1Be4w?pwd=bmxt 提取码: bmxt 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/710160.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

两台电脑之间传输文件——就近共享

文章目录 背景步骤补充&#xff1a;跨设备共享 背景 两台电脑之间共享文件有很多种方式&#xff0c;这里介绍一种最简洁的——Windows自带的就近共享。它适合偶尔传输一些简单文件。比如把笔记本上的电子书传输到surface上阅读。 注意: 如果共享的电脑正在运行最新版本的Wind…

js对象数组去重:

目录 双层for循环&#xff1a; indexof()&#xff1a; map方法(推荐)&#xff1a; 双层for循环&#xff1a; ​ //双层for循环let arrObj [{name: "小红",id: 1},{name: "小橙",id: 1},{name: "小黄",id: 4},{name: "小绿",id: 3}…

软件设计模式与体系结构-设计模式-结构型软件设计模式-组合模式

目录 结构型软件设计模式概述 一、组合模式动机组合模式结构实例一&#xff1a;五子棋游戏实例二&#xff1a;空军指挥系统关于组合模式的讨论1. 安全形式的组合模式2. 透明形式的组合模式优缺点适用环境 课程作业 结构型软件设计模式 概述 动机 结构型软件设计模式的主要目的…

C++语言之 do-while 语句

有时候&#xff0c;使用 while 语句会想要先执行一遍循环体&#xff0c;这就可以使用 do-while 语句。下面会介绍 do-whie 语句。 目录 1.格式 1.1 格式1 1.2 格式2 2.执行过程 3.例题 1.格式 如果主体中只有单个语句的话&#xff0c;花括号可以省略。&#xff08;如格式…

Http host 标头攻击

一、什么是http host 标头攻击 HTTP Host 标头攻击是一种网络安全攻击技术&#xff0c;利用了 HTTP 协议中的 Host 标头字段的漏洞。Host 标头字段用于指定客户端请求的目标主机名或域名。 攻击者可以通过构造恶意的 HTTP 请求&#xff0c;伪造或篡改 Host 标头字段的值&#x…

【Python从入门到进阶】urllib的异常处理

接上篇《25、urllib获取快餐网站店铺数据》 上一篇我们讲解了如何使用urllib的post请求抓取某某快餐网站店铺数据。本篇我们来讲解urllib的异常处理机制。 一、异常处理的重要性 在编程过程中&#xff0c;无论是与网络交互还是执行其他操作&#xff0c;都存在各种意外和错误可…

阿里云外网无法访问Dcoker容器

应该是docker和linux网段冲突 1、路由策略开启转发 cat >> /etc/sysctl.conf <<EOF net.ipv4.ip_forward 1 net.bridge.bridge-nf-call-ip6tables 1 net.bridge.bridge-nf-call-iptables 1 net.bridge.bridge-nf-call-arptables 1 EOF sysctl -p 2、查看配置…

spring boot security自定义认证

前言 前置阅读 spring boot security快速使用示例 spring boot security之前后端分离配置 说明 实际场景&#xff0c;我们一般是把用户信息保存在db中&#xff08;也可能是调用三方接口&#xff09;&#xff0c;需要自定义用户信息加载或认证部分的逻辑&#xff0c;下面提供…

第三章javascript类型,值和变量

第三章类型,值和变量 计算机程序通过操作值(数值3.14)或文本(如"hello world")来工作,编程语言中这些可以表示操作的值被称为类型,而一门语言支持的类型集支持的类型集也是这门语言最基本的特征. 程序在需要吧某个值保存下来以便将来使用时,会把这个值赋给(或存入)…

UE4/5GeneratedDynamicMeshActor生成建模方块【更多建模的函数就等你自己去探索把,Append ...】

目录 装备工作 逻辑制作&#xff1a; 之前我们讲了很多关于GeneratedDynamicMeshActor复制别的网格体的东西&#xff0c;以及替换到网格体里面&#xff0c;但会发现这样终究是没什么用&#xff0c;所以这里我们来讲解一下&#xff0c;不用其他的网格体让GeneratedDynamicMesh…

Tuxera NTFS2023Mac标准版读写NTFS格式硬盘

NTFS是什么&#xff1f;这是微软随Windows系统开发的一种文件格式&#xff0c;专门为网络和磁盘配额、文件加密等管理安全特性设计。比起FAT格式&#xff0c;NTFS属于一种较为新型的磁盘格式。现在我们使用的u盘很大一部分都是NTFS格式。 那有小伙伴会询问&#xff0c;想在Mac系…

SpringSecurity(三):自定义认证数据源(源码+落地实现)。

自定义认证数据源 前言认证流程分析易混梳理AuthenticationManager 与 ProviderManagerProviderManager 与 AuthenticationProvider难点&#xff1a;为什么ProviderManager会有一个parent&#xff1f; 数据源的获取配置AuthenticationManager默认的全局 AuthenticationManager自…

RabbitMQ:高效传递消息的魔法棒,一篇带你助力构建可靠的分布式系统(上篇)

目录 一 什么是MQ1.1 MQ的概念1.2 MQ的流量消峰1.3 MQ的应用解耦1.4 MQ的异步处理1.5 MQ的分类以及如何选择1.5.1 ActiveMQ1.5.2 Apache Kafka1.5.3 RabbitMQ1.5.4 RocketMQ1.5.5 四种MQ的区别 1.6 MQ的核心概念1.6.1 MQ四大核心概念1.6.2 MQ六大核心部分 1.7 安装RabbitMQ 二.…

5.3 Web服务器简介及HTTP协议

5.3 Web服务器简介及HTTP协议 Web Server&#xff08;网页服务器&#xff09; 一个Web Server就是一个服务器软件&#xff08;程序&#xff09;&#xff0c;或者是运行这个服务器软件的硬件&#xff08;计算机&#xff09;。其主要功能是通过HTTP协议与客户端&#xff08;通常…

【洛谷】B3643 图的存储(邻接矩阵+邻接表)

思路简单&#xff0c;话不多说直接上ACcode(详细注释): ACcode:(安全饲用)&#xff1a; #include<bits/stdc.h> using namespace std; #define int long long const int N1e310; int mp[N][N],n,m; vector<int>v[N]; void fun1(){//邻接矩阵打印 for(int i1;i<…

学成在线----项目优化

1、项目优化-redis缓存 2、缓存穿透 使用缓存后代码的性能有了很大的提高&#xff0c;虽然性能有很大的提升但是控制台打出了很多“从数据库查询”的日志&#xff0c;明明判断了如果缓存存在课程信息则从缓存查询&#xff0c;为什么要有这么多从数据库查询的请求的&#xff1f…

RedmiBook Pro 15S AMD Ryzen 7 5800H电脑 Hackintosh 黑苹果efi引导文件

原文来源于黑果魏叔官网&#xff0c;转载需注明出处。&#xff08;下载请直接百度黑果魏叔&#xff09; 硬件配置 硬件型号驱动情况 主板RedmiBook Pro 15S 2021 处理器AMD Ryzen™ 7 5800H已驱动 内存16 GB 3200 MHz DDR4已驱动 硬盘Samsung 970EVO 512GB已驱动 显卡HD …

frida编译

官方过程 frida编译 Windows Make sure you have: Visual Studio 2022 Git on your PATH Python 3.10 on your PATH Select Add Python 3.10 to PATH Set the installation directory to C:\Program Files\Python310\, or edit releng\frida.props to change the PythonLocat…

Java安全——加密介绍

Java安全 加密介绍 在网络传输中&#xff0c;数据的加密鉴别是非常重要的&#xff0c;它可以保护数据的安全性&#xff0c;防止数据被窃取或篡改&#xff0c;并通过鉴别机制确保数据的完整性和真实性。Java安全中的加密鉴别主要包括对称加密算法、非对称加密算法、数字签名和证…

Pytroch本地安装方法

1 查看电脑安装的cuda版本 nvidia-smi这里的红圈标注的是cuda 最高版本&#xff0c;虚拟环境中安装&#xff0c;只要不超过12.0就可以 第二步 去官网看torch, torchvision等版本的匹配关系 https://pytorch.org/get-started/previous-versions/ 比如这里&#xff1a; &…