QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 3005|回复: 0
打印 上一主题 下一主题

[其他资源] 使用opencv qt 以及 tensorflow2 进行神经网络分类

[复制链接]
字体大小: 正常 放大
杨利霞        

5273

主题

82

听众

17万

积分

  • TA的每日心情
    开心
    2021-8-11 17:59
  • 签到天数: 17 天

    [LV.4]偶尔看看III

    网络挑战赛参赛者

    网络挑战赛参赛者

    自我介绍
    本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。

    群组2018美赛大象算法课程

    群组2018美赛护航培训课程

    群组2019年 数学中国站长建

    群组2019年数据分析师课程

    群组2018年大象老师国赛优

    跳转到指定楼层
    1#
    发表于 2022-9-5 16:01 |只看该作者 |倒序浏览
    |招呼Ta 关注Ta
    / J4 _9 v/ K! Y
    使用opencv qt 以及 tensorflow2 进行神经网络分类
    5 I( O1 }$ O; e工具选择# @2 U8 D( S3 ]/ u! z0 C- n, r
    我们将会学习使用图片分类器和合适的GUI界面,GUI界面使用QT,选择一个camera 或者一个视频文件作为输入进行分类,这里是实时进行分类,qt本身是一个跨平台的GUI设计工具,同时我们使用Tensorflow 和 opencv 去进行分类工作。8 q) j5 p1 @+ q5 c  y
    " W6 c$ m( N+ C5 L, c1 o9 F8 }
    opencv 本身具有一个深度学习推理模块,名字叫做dnn, 3.4.1 以上opencv版本, 使用dnn模块,我们可以加载和使用深度学习模型,这种模型来自于像tensorflow的第三方工具,当然他还支持caffe,darknet 等等,我们这里使用tensorflow 模型,使用 ssd_mobilenet_v1_coco
    + p% l% T0 S. W/ N: c. s" o# V; M0 G" s7 M& d" g5 u
    本身在windows 或者其他操作系统上应该都是可以的,我们以windows为例
    $ |! Y0 x$ x+ T( u+ Y; C
    3 V: f2 j) C# C- ?, a需要的工具  [$ E$ F$ [: [( K* T: h! V
    • 1 Microsoft Visual Studio 2019) l1 I& f0 y6 x
    • Qt5 (https://www.qt.io)
    3 T, ^! H0 Y" p, y# z' L+ R• OpenCV 4 (https://opencv.org)" H/ M8 a4 D( f2 v& L4 }6 d  L
    • CMake (https://cmake.org)
    7 O2 f3 H5 z1 M• Python 64-bit (https://www.python.org)% C/ E/ O' c$ Q" X# }- o( Y
    • TensorFlow2 (https://www.tensorflow.org)7 ?- v+ i+ A# m/ k! C: x# C
    : n6 K1 {4 D& i, T8 r3 r  g
    创建 Qt GUI Project 选择CMake+ [# D! T  Z! c9 B- a( L3 T( x
    我们将会创建一个QT GUI 应用程序,编译方式选择CMake,当然了,不是一定要选择这个了,读者自己可以选择其他方式。& r2 h( X- Z+ K

    2 I$ X+ `5 N' }5 W& A! j这一这里选择CMake- N  P  N/ H( N  C' H" a* w9 ^
    # {0 n8 q7 O! m
    3 q1 @; D) O( [) _( z
    项目创建以后
    # i- Z! H* t6 v5 }After the project is created, replace all of the contents of CMakeLists.txt file with the following (the comments in the following code are meant as a description to why each line exists at all):
    9 N- O3 z6 y3 t
    0 ]& h: G! H- Z7 \* S- }# Specify the minimum version of CMake(3.1 is currently recommended by Qt)$ m1 I3 t$ R  L0 I  I
    cmake_minimum_required(VERSION 3.1)& i& N+ F: Y6 F+ I

    6 [9 \4 _+ z2 \( E6 I" O; w/ k) y, i# Specify project title
    : V; ]+ L. J- z5 t! Vproject(ImageClassifier)
    ; F: `8 r5 G# {9 h( T4 g
    * c/ k& G# F  j- R3 _# To automatically run MOC when building(Meta Object Compiler)( }! H- v$ g8 ]4 ~" w
    set(CMAKE_AUTOMOC ON)
    2 ?# U& K6 p* a$ ^& @; o- g3 P% d/ b- n3 [$ S4 M
    # To automatically run UIC when building(User Interface Compiler). r1 p2 B7 x3 h/ j+ V+ J2 x: I
    set(CMAKE_AUTOUIC ON)2 b7 n. p( k; T% U/ S6 P
      U+ t- G! M  N- Y" m  e9 G
    # To automatically run RCC when building(Resource Compiler)' `7 ~& @$ n0 [, F
    set(CMAKE_AUTORCC ON)
    2 s+ u8 f* w) k2 B. I2 _- ~% I4 N
    # Specify OpenCV folder, and take care of dependenciesand includes# l  s& B) s: j9 h
    set(OpenCV_DIR "path_to_opencv")2 a3 ~8 N* l5 A, j! m0 B6 ^! s
    find_package(OpenCV REQUIRED)
    8 ~7 U/ g( N6 [! ]include_directories(${ OpenCV_INCLUDE_DIRS })# M8 \) z; c0 _; p7 O6 \
    ; e" _, R7 h* ?+ b
    # Take care of Qt dependencies
    2 U. _* E8 D" i. o( t+ O2 ~: S# Cfind_package(Qt5 COMPONENTS Core Gui Widgets REQUIRED)
    $ Y* S& _$ S5 r7 M
    2 h! h) |% b$ e3 y, q! [# add required source, header, uiand resource files
    & K7 H. ^. a( `: [0 kadd_executable(${ PROJECT_NAME } "main.cpp" "mainwindow.h" "mainwindow.cpp" "mainwindow.ui")* U- V5 c) t3 W% r: d

    ' I& ]" d: a) f# link required libs1 n; L& T! J" S$ w' X* \+ G) n
    target_link_libraries(${PROJECT_NAME} Qt5::Core Qt5::Gui Qt5::Widgets ${OpenCV_LIBS})1 ~7 ]$ V* n$ b' @! z
    1- A6 F, W# l- b( e# z% I
    2
    ) N* M  ?% q  ?+ t# X# a3% C5 I. T7 Q# n9 k
    4
    7 Q& g% E  Y0 G, Z59 ?' X8 n' [1 a7 e& R/ P! |2 J; J8 M
    6
    * ^* b! a3 K* y7 l0 v3 c# ]$ n7
    # H4 h9 z8 k8 x8
    & n6 y5 L- m' ?9
    7 O! b' X4 u  m8 b' X, B# ?10
      Y, t  a) a- N1 b) m11) }' X; o; }' C- {$ y
    12  B1 J  B; {6 K1 V  D
    13
    * y# O5 c+ v2 z2 Y( i14/ b5 q4 [: O1 N4 _6 N
    15- |4 ~) O' c  m# q# j1 u# i
    16
    & O5 E: J7 w) U% C+ g" Y170 J- x* y' t/ T" p9 ~+ n
    18$ v0 F) d% Z' P8 B! y" X* o
    19
    5 y$ ~% \$ }" x" O) q7 P9 l1 y20+ B. w7 c. T3 A, _# M( @9 K
    21
    $ G4 c3 t7 ^1 D: M0 ^/ j2 Z4 Z22
    3 Q  W- U6 I* ], T231 k9 L! i* b) @, q
    24
    # G. X: z2 y$ x5 P2 f# l- i251 D: E! j1 X4 b7 D' C
    261 c5 @1 J0 y# b
    275 b' M+ \( z; A) C
    28# N" ~* a7 R8 {3 g1 d/ B" ~
    把里面正确的地址写好,把main.cpp 里面开始mainwindow.cpp 。
    * J4 @4 I3 H6 e" H: v  C# d" Q8 o8 S/ r5 A
    写好main.cpp- W8 U7 L3 s& b4 g& @2 D
    #include "mainwindow.h"7 ]0 j/ y, C% `5 s& M3 L
    #include <QApplication>
    . M/ K0 F, D& i* ~5 F7 p2 I. q/ `# F+ |* |( w# [" Y
    int main(int argc, char* argv[])1 T; K8 _# _1 ^1 @7 N
    {$ r; V: F/ @% Y
            QApplication a(argc, argv);
    ( B- X& f, i, i& r; R' i" Q3 F6 c        MainWindow w;5 }7 A! i$ J+ Z3 i
            w.show();9 m1 g- `! U9 b

    4 F8 }; S. T* d; B6 d, l9 n5 `        return a.exec();
    ; M4 O! s* L7 U3 k( z}3 v( O( u% a$ l: x2 j  ~
    1
    : W& l' }1 T3 z  _" ?' ]+ ]2, I/ w, ^' Z/ w" q; n6 y% A
    3
    . _' m& a- G7 x' s4
    ' L- C" O7 s0 K2 _# N$ ?: j5
    7 W. @; L8 L8 N) N) S0 ^6! v, \2 P+ ]5 H: T. g, m7 m$ a
    7+ P! K  i8 t6 U1 x
    8, I6 {3 d6 A( `& B
    9
    ' w( J' c2 s0 a# j; O- G10
    4 ^0 C4 o) Y! @8 v6 w; S11/ B1 s$ f: B2 m/ N0 n( f
    现在使用设计器加上一个窗体,
    ! J! A) u9 [+ [# q" |7 H1 a" i7 {6 G" h, {) R; S
    选择Main Window* e; v7 R6 y+ `
    2 B+ ?" I& J4 Y3 W

    5 S+ D5 Q8 N9 T0 g7 G1 u像下面这样设计窗体就行了
    3 Y2 @/ l  W9 m) _6 i* E4 C  v( _) h4 p" |

    $ K! m5 i. T- F  S0 g“mainwindow.h” 文件代码如下, Q- C  J0 \# C3 Y8 _9 S% e& ^

    4 i9 u. O/ {) T$ x#include <QMainWindow>6 J! T8 ~! h/ I* i$ R: b( [5 K6 `
    #include <QMessageBox>* v7 {; j+ I+ U1 n1 ~! s# {
    #include <QDebug>- u- o" Z4 m% E2 L* d5 \7 {6 _
    #include <QFile>, |* ^( C& B2 B' a
    #include <QElapsedTimer>
    - M& F: H9 @& N4 G# f#include <QGraphicsScene>8 x  p; ^) i& j" o- M8 ~! s& H5 j
    #include <QGraphicsPixmapItem>
    8 Z$ Z1 [* }5 p# P9 ]- X8 c6 j9 x#include <QCloseEvent>4 ]' N" |  |/ J# |8 w
    #include <QFileDialog>
    0 z  Y5 l9 K) f9 n% _, p#include <opencv2/opencv.hpp>
    : a: Z/ m5 z# H4 hWe will also need the following private members:, o0 g0 o/ y! [# @1 N) k
    7 a" k( ^' c) p5 }) t
    cv::dnn::Net tfNetwork;
    1 K0 N- I5 q# T3 D4 P" AQGraphicsScene scene;. f+ f6 I+ L$ w5 y% U
    QGraphicsPixmapItem pixmap;3 |( |3 p# D$ v) U# X* |
    bool videoStopped;
    8 h% k5 V4 @% @/ X' V1
    " z2 C2 a* u5 W2
    ' @! T$ N% z, e- Q2 C3
    5 @+ N1 H2 {1 I% o6 u: G6 {8 ?, G4
    - f* w1 {: H4 t) n% _! g& c5$ f$ S6 C& y+ c: z: W" T0 b
    6& y$ a4 e" k, S
    7
    , N4 H# i1 X+ d2 ]# I  V: U/ \/ e8
    1 t, v" d; c) B/ D; p9 j9# u9 `- R5 r5 x: a
    10" m7 y4 M& N- V
    11
    . y. |5 ~' E# @" [& \# r12
    , B* _' m7 ?8 l7 L13
    ! B' k7 S* q1 @" J* W- v& s14
    3 ?  v$ f1 R' i+ i$ p7 {& B15
    " n5 W+ T, |0 u& F! e+ Z. U" S" B! V160 p4 t0 l! e8 r, G' d5 S3 h) H: T
    tfNetwork 是opencv的深度网络分类器,场景scene and pixmaps 用来显示,变量 videoStopped 作为一个标记去停止视频. 我们的代码如下所示.0 A* L6 l/ ?" \* \" y$ I: c/ F

    + `% Q# V5 i/ f  T. b#ifndef MAINWINDOW_H# x- W. e. y* k
    #define MAINWINDOW_H
    $ n& V6 q% D- x3 X1 F) s
    9 R# ~; A7 a0 |3 J- X7 f3 r#include <QMainWindow>+ s- p/ p" z8 b9 B: l* n
    #include <QMessageBox>
    8 x- @0 L( Q5 X6 T& ~#include <QDebug>
    + q, d' Q' X$ S; p6 D  w# N7 `#include <QFile>+ N- M& M2 a  o- i  N! j  q
    #include <QElapsedTimer>
    8 ^" ?6 g1 K( W% [+ B0 U7 R#include <QGraphicsScene>0 S/ w! j  I1 {. b/ l( a% F0 w; O
    #include <QGraphicsPixmapItem>! w2 Y8 j3 r5 W/ d) y) s9 w$ p
    #include <QCloseEvent>/ E1 W3 x/ I) h: i6 t8 d
    #include <QFileDialog>8 N4 K9 r# {+ H0 B5 k0 {  w
    #include <opencv2/opencv.hpp>
    # X( A3 v2 X0 j, S. b* I  S4 V! i7 B9 k, ^5 N' Z- T
    namespace Ui {
    1 P. m9 F! [6 w1 R; v" S8 d8 Dclass MainWindow;
    ) t0 w7 v+ e/ i- l- I) y7 j7 d  K$ c$ ^}
    2 A: n* ~& Z" C' g# l, y; d$ B" g3 ?2 B0 T; b2 T5 M7 G: K2 X
    class MainWindow : public QMainWindow
    - [" S  e2 V4 T7 B9 v{# X9 K) m) K$ I% z' ^
        Q_OBJECT$ Z: G3 c7 Z: }4 x

    . c. b7 W, a* H! ]public:( Q* }* c( c9 \
        explicit MainWindow(QWidget *parent = 0);
    ) H+ }% [( {7 E) l" `    ~MainWindow();- q# V7 q% m5 q/ U
    ! ~7 h& F! B* m) `$ h
        void closeEvent(QCloseEvent *event);
    9 w9 ~! o3 v1 R' n" C, p( Y. b) e0 f0 n0 h2 ]- P8 i
    private slots:
    ; X  ^2 ^6 Z; ~  p6 h: K. D! [; g    void on_startBtn_pressed();
    & {: D0 t7 P; \7 e" y6 P( ~2 c# Q% k
    + r4 P+ {7 m% v2 O/ M    void on_browseVideoBtn_pressed();: Q% H: c) m0 H& D- q

    1 ^: j8 p5 U/ I: F& {    void on_pbBrowseBtn_pressed();3 y0 W/ D$ A, F* B( j

    - X9 p6 f, S' E& X    void on_pbtxtBrowseBtn_pressed();& c  v* ?$ e3 [/ \
    % _6 j: d, T4 X" l' o" z- n
        void on_classesBrowseBtn_pressed();6 ]# [# b' h' U% G/ ^6 _! q* U

      U8 c0 p) o: L- |1 [private:
    ; c1 ^: D4 n/ T( A: d2 a4 `    Ui::MainWindow *ui;5 n" b! m* U$ Z" a3 W6 t

    ; e; J: L( B$ E4 V9 B* g    cv::dnn::Net tfNetwork;# g9 t& k3 B$ ^; w: k
    / z  t3 v( w) ]0 |" w% l
        QGraphicsScene scene;8 ?1 R" h7 E( H. ^  r
        QGraphicsPixmapItem pixmap;
    3 ]5 D9 [  I' J0 r! y1 M5 f( R+ X4 C% q3 O0 J- L! n. g
        bool videoStopped;
    6 C4 G" s  q3 J, w3 m" C8 ]/ q( r. K) K' H. X6 L6 y
    };
    % n" Z* f3 w' {4 P# ]# l6 |% D* @. F6 c+ K: L
    #endif // MAINWINDOW_H
    + _' N7 ]3 _2 D! t1! W, K3 ^1 {8 h3 L
    2
    5 u" q/ H- W9 f: c; w3 L3
    & c" D* L- I7 V# @( [4 [* k+ J47 s7 u. L" _2 d1 Q! u& x. l
    5
    . O/ K! }$ V* f( f8 g& L6
    . p, X' E: i3 p% V& u7" J: p8 O% b* e1 S5 ~, S/ j: F6 l
    8% w3 n) d7 T) E( d
    9) i4 \' B( g( h& ~& S3 N" {! d
    10% Y/ ?. B2 O  u8 z/ O' S
    11+ u3 W: S) q3 U2 v
    125 O5 d+ \# V4 l& j) Z( j' Y
    13! h+ e5 g; |9 d2 J' I3 G6 J% a
    14/ B# r) z" [6 ?0 T, `
    15$ F2 ^0 o0 b0 c9 W, W. C( F( s
    161 f2 o. Z/ Q. }, H# m+ J6 m
    17
    & W8 P8 Y4 T8 j18
    . g! ^- s+ J+ T19* C) z; y# L: p7 i: [; x
    20% I7 d7 Y" e" T; X
    21
    - E$ V8 E8 U3 f, g' s22
    : `6 ~# U2 D5 v5 O  ]) t# }23
    : V2 K1 s- ~5 a, b$ q24
    1 T9 H1 w2 w1 k# p( }0 u/ k25
    - g$ X  |( E, Z, v2 B$ H) \, O26
    0 i+ S) P/ V% N. A% G$ `# n27/ ^3 m5 s4 u% ?4 O! n
    28% R" [% h5 N% w
    29
    9 _* B- O8 [) a30
    ' i" I9 ?' S+ D5 m- R. z31
    ' \: i* O# C/ ^! V& f/ Q& A5 f. M32% w* |/ i2 R$ C. h* x
    33
    , D2 ]0 D2 }, s34
      n" T/ e- _( y2 z35/ l  k$ q7 w: ^! a# w, B
    36$ M8 p# p/ [2 k( _; D5 x$ p3 {
    37
    7 `, s; C  [* t! n  \" [2 p. ?; y38
    " ?4 t. }  l- ^39
    " @2 e9 C5 w  d$ }7 }  Y: k40
    ) ^8 @7 b' R* E$ {! u41
    2 f! `) J# x" i/ O42& e6 |& s6 r2 |  q: z7 z9 N& I
    43
    , Z1 D( D! G4 N( Y- A6 x440 }# g7 b1 S  z3 }$ d4 ?) u% Y
    450 ?/ G+ _, _# v& w. C
    46
    9 ]; {6 s6 K' f% K$ ~  e47
    2 v' A3 d; {! ^4 e9 `" b5 j486 W7 Y/ S- A( u1 j3 s! _, w
    49- @% k! Q, B8 k3 y* i
    50, C* J) l6 [: J$ h6 r
    51; q8 K" e/ n/ t
    52
    6 X: ~9 r- c/ b“mainwindow.cpp” 包含一些方法去处理用户狡猾,并且加载TensorFlow 模型和配置,并且执行探测,也就是做推理,首先,我们需要把预先训练的模型加载到网络里面。2 F  X3 V- U0 k! w  E( V
    tfNetwork = readNetFromTensorflow(ui->pbFileEdit->text().toStdString(), ui->pbtxtFileEdit->text().toStdString());. ~( k4 R2 ]; t9 U

    8 V0 P0 a- l0 p' ]! L$ u  opbFileEdit and pbtxtFileEdit 在代码里面是qt的 Line Edit widgets, 是所需要文件的地址路径,下一步,装载一个视频文件或者打开计算机的相机,使用两个 radio buttons, 让用户切换相机和视频文件,代码如下:
    9 q+ G1 H' ~+ u  g9 y. S" o( C+ ]; v* {$ ]' i
    VideoCapture video;
    8 H! C# W8 q0 {; B' f0 B) Uif (ui->cameraRadio->isChecked())
    ; j1 c& D  ?& c) _% c1 j2 i        video.open(ui->cameraSpin->value());2 S! n9 O1 [& ?; R# z+ R
    else
    7 B3 m2 l# g8 @; N. @  F) p9 q        video.open(ui->videoEdit->text().toStdString());
    1 O$ X. v4 e, B8 }) D1
    " y7 A  }% i. K* z2 s) ^& s2# ~6 J; ]7 }6 i' s% S# F2 E1 U
    30 i  R2 I0 n8 z7 p+ H- ]/ w8 i
    4* [- T. ^9 D. h% s  G0 z" N# M2 U
    5" k% e7 o3 ^$ N- J$ X8 q
    cameraRadio 是一个 Radio Button, cameraSpin 是一个 Spin Box 并且 videoEdit 是一个 Line Edit widget. 下一步我们需要循环读取视频帧并且处理推理,一直到结束:
    + A# ~- O. m( M. h, j) n! [7 y: i' R8 R3 k- i* n
    Mat image;2 q0 ]- a& \: V  n
    # b: c) c+ z5 b+ x& c
    while (!videoStopped && video.isOpened())
    % }2 k, n( t! q. m" s+ {# m{
    0 Z% c# n$ _. p( x2 W, O" T        video >> image;2 p4 q+ b1 ^3 E
    - H) P( M5 h- G6 B6 s
            // Detect objects ...1 V: L, G' B  M5 Y) n
    5 K+ G% m6 o9 }  H- F2 @3 p
            qApp->processEvents();
    ( t3 a4 }$ {# b. r+ Z2 E+ M}
    8 }" y8 A2 ~6 m; A1/ ~2 x  w8 E( a4 P" D, y  U' v
    26 q: E( y; Z: l9 B4 \# F) N& `& |
    3% s2 B! n3 n+ f; b& v2 s
    44 y, q, G* D0 _5 m
    5
    ; I7 U+ ~7 W+ O4 ^$ F; V6
    ( R( u; N+ ]- ~: y( ?7 C/ p7  l( v  {+ j+ ~
    89 q; N3 r9 J9 G9 H
    9- U& ?4 e9 E& X3 f
    10$ B; y" ~$ w" o7 d  S
    有很多方法可以去同步GUI和处理任务,我们把部分代码放入到QThread里面,探测部分如下所示:首先创建一个BLOB 兼容的Tensorflow 模型( E" I7 w. h' K' o2 u; B( z

    # S. s4 j  J% Q  r, _2 ]+ ]: A, qblobFromImage(InputArray image, 2 d* P  j# ]1 e# h- [
                              double scalefactor=1.0, * Y7 @& _! K( x8 I& i- G
                          const Size& size = Size(),
    8 ?, M7 A' p$ y  l, o! K$ W6 ^                          const Scalar& mean = Scalar(),
    # _' J) z" V* h( R2 c: K. u. D, p                          bool swapRB = false, 1 z# a/ U1 S/ {5 E9 m6 K
                              bool crop = false,* V% o! K) B! `& K
                              int ddepth = CV_32F); _6 L0 Q3 e' y) a; @1 {, q# U
    1" z. h# N1 U7 x2 z' `, p7 k
    27 M# S3 n' V" M; j
    3
    5 w; p# O, E) ^* k# N' r' q4
    , D; K- d4 \: ^: q3 N! N4 _) c5+ _& O3 C2 \3 X8 X1 |/ f* m
    6. R( k$ R4 }) S. Q. F- R3 a( I  |
    7' {1 j% W# o4 u
    下面是解释:2 T; h! \" `- s: t& {( [# l+ I
    0、image ,输入图片1 J2 |$ J# }" n) F4 d. n- j
    1 、mean:需要将图片整体减去的平均值,如果我们需要对RGB图片的三个通道分别减去不同的值,那么可以使用3组平均值,如果只使用一组,那么就默认对三个通道减去一样的值。减去平均值(mean):为了消除同一场景下不同光照的图片,对我们最终的分类或者神经网络的影响,我们常常对图片的R、G、B通道的像素求一个平均值,然后将每个像素值减去我们的平均值,这样就可以得到像素之间的相对值,就可以排除光照的影响。
    # Y. r0 z; O: g1 l  t) X* w; _  N* H$ \2 d& m0 @7 [
    2、scalefactor:当我们将图片减去平均值之后,还可以对剩下的像素值进行一定的尺度缩放,它的默认值是1,如果希望减去平均像素之后的值,全部缩小一半,那么可以将scalefactor设为1/2。
    7 |" t: o& {# P% m/ Q0 G7 ^4 b1 r+ o0 {8 @4 e5 Y4 H! @1 U
    3、size:这个参数是我们神经网络在训练的时候要求输入的图片尺寸。1 R6 x1 [# O$ _0 f+ M

    9 X' w, G- q# E; h; X" l2 K4、swapRB:OpenCV中认为我们的图片通道顺序是BGR,但是我平均值假设的顺序是RGB,所以如果需要交换R和G,swapRB=true9 r. Q$ p) @# U' p" r

    8 H- p5 K% t2 O0 q* y" B+ l调用:' a. C% k, _+ k
    6 z- I: `$ ]1 e+ _
    Mat inputBlob = blobFromImage(image,
    7 q/ c* `$ A$ h) ^0 s        inScaleFactor,
    : v; M' O# `  _* K& m& \  k        Size(inWidth, inHeight),
    0 G( B& y  D9 |" J" W        Scalar(meanVal, meanVal, meanVal),( V( f8 [/ V; n, @
            true,
    8 @# T/ w2 v6 Q% Q. E) B        false);
    / P$ B( I; u1 {1
    & `: O3 B9 x. `7 |2 p25 v, v1 }4 f$ b& }
    3/ }4 Y% n6 d8 c7 e& z2 A
    4+ I$ }: R! Q6 A1 Z/ i# y
    5! r9 k6 o9 `" a6 I" o6 b0 c
    69 |) `+ U2 |1 @) I, {
    The values provided to blobFromImage are defined as constants and must be provided by the network provider (see the references section at the bottom to peek into where they come from). Here’s what they are:
    ! |6 C- V  x. S, O0 F+ p0 y6 s2 b7 E) p
    const int inWidth = 300;$ I2 ?" ~; o: c6 `* ~( J# l
    const int inHeight = 300;
    6 t, w- q1 a9 [3 O5 dconst float meanVal = 127.5; // 255 divided by 2
    - T4 U% p% s& U3 d7 D3 t4 S) Qconst float inScaleFactor = 1.0f / meanVal;) r2 ^7 g! I5 x: q
    19 D4 S; |; e' ?! v
    2
    0 e% v0 W$ C. M9 }3 E, }3  i4 e; k& j( W
    4" A, `0 h5 m9 g0 v5 U5 r
    使用Opencv4 以上和Tensorflow 2.0 以上,让这个inScaleFactor值可以为0.953 \+ ]4 O/ f$ @, N
    让后进入网络,获取推理结果,像下面这样写就行:
    + R, Z# X8 {7 L9 [
    - q$ K6 g* Q7 h$ A5 DtfNetwork.setInput(inputBlob);. G& A7 u, [4 e/ ^* P4 a0 J& m
    Mat result = tfNetwork.forward();% f3 w: |  E+ ?
    Mat detections(result.size[2], result.size[3], CV_32F, result.ptr<float>());
    6 `( N$ m) }2 C# S) K. `1
    8 ~$ C" r$ c! x( }5 p2/ O$ L, j3 K) x9 l! G/ x
    30 v& c* }2 j) H/ s# `5 N
    处理代码里面比较简单就是为blob 设置 网络,使用forward()方法来计算结果,最后创建一个探测Mat 类, 有关参考opencv数组mat 可以查看一下链接
    - S; o  @9 Y6 v! Ghttps://docs.opencv.org/3.4.1/d6/d0f/group__dnn.html#ga4051b5fa2ed5f54b76c059a8625df9f55 l- `1 l2 f) O9 ]( S
    下一部分是使用detector后拿到识别的物体绑定矩形盒子,打印类名称,同时做显示6 `! e* j3 {# l4 |4 H: W7 c* ?
    ( }& x7 z! }4 `& A+ K
    for (int i = 0; i < detections.rows; i++)
    % F  A( f4 K' W( f' Y/ i" X{
    + V" G2 a4 {9 G7 d0 @( k7 ~        float confidence = detections.at<float>(i, 2);8 c: G7 `" Q( g4 S+ k+ b
    . |' @( |  a$ a- Z. M: Q
            if (confidence > confidenceThreshold); l, D+ p( }( }0 h, G" S+ i, n$ v
            {
      J! [: J; ~) u2 o& v( g' Q                using namespace cv;# y) N& n* |6 ^- P

    6 ~  d9 ^+ V; K$ g; Y6 [                int objectClass = (int)(detections.at<float>(i, 1));/ X' j8 ^& q  y
    9 g) }( q8 F) {4 J: d& d
                    int left = static_cast<int>(0 l; Z& |( `/ _8 O2 B
                            detections.at<float>(i, 3) * image.cols);
    , e9 E. r: A5 b0 ~8 B% B( T                int top = static_cast<int>(
    & K- J3 @, L+ l0 o  d/ \  {* r                        detections.at<float>(i, 4) * image.rows);$ F7 c7 h) M- q$ c3 B( i
                    int right = static_cast<int>(
    0 c! Q6 [$ u3 `9 w3 J# \2 k                        detections.at<float>(i, 5) * image.cols);
    1 x9 T& k! H4 Y% U* V4 Q; G( @                int bottom = static_cast<int>(! Y6 Z7 k$ |% P& o% m7 n
                            detections.at<float>(i, 6) * image.rows);
    3 w# r$ z/ C) v' L+ L% a+ Y) J  S" K7 x, V6 Y9 ]6 l- [. Q8 E
                    rectangle(image, Point(left, top),' {. e, o! U& I' ~% z
                            Point(right, bottom), Scalar(0, 255, 0));9 m/ `5 M- ?9 @/ h; \% j2 ]
                    String label = classNames[objectClass].toStdString();$ p; r5 x* J3 {, J, Q! B) Q+ K; _4 g
                    int baseLine = 0;0 {& C, w: u% ?) r8 c
                    Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX,& x5 `& J, p; Q, o+ a8 M  Q
                            0.5, 2, &baseLine);! V3 }8 ^, Z0 t- E; Z+ P( }! p: |) _
                    top = max(top, labelSize.height);
    0 _9 }6 b/ m! j. K( A1 t                rectangle(image, Point(left, top - labelSize.height),# N; P* Q8 [& k/ k2 B. C! e. i: r9 H
                            Point(left + labelSize.width, top + baseLine),
    ' o3 b* a6 J) S  @, T, A                        Scalar(255, 255, 255), FILLED);
    $ z( q% j4 b, s* k  X* j8 O. _- \! K                putText(image, label, Point(left, top),
    ) T5 O) s/ d& @# G* X                        FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 0));
    ! t# \" C/ s$ [; u& ^$ E        }0 M' x4 H: Q( L
    }
    8 r8 x( y! n7 Y
    ! T" ~/ y# J  Z2 b( P4 xpixmap.setPixmap(
    : K6 f2 {8 q' V2 W& x3 ?' V        QPixmap::fromImage(QImage(image.data,
    3 [5 g, f5 e; h/ B7 d                image.cols,
    ' ^6 _- l, p# p/ l                image.rows,
    9 Y8 p. l! y8 W: N" v                image.step,6 r- \) p* U& @& @# O& N
                    QImage::Format_RGB888).rgbSwapped()));
      k3 U$ h$ U9 g* Qui->videoView->fitInView(&pixmap, Qt::KeepAspectRatio);
    5 r6 o2 {8 K( U$ n1% S3 h2 r/ e  a" D( [5 a- |# O9 L
    2
    5 s( U/ q; W5 C% y) C3
    ; [3 l3 @/ N1 I) w# w4
    $ r0 O; k, @5 g5
      Z- Z* ?( m# ^6" @  W" g8 U: y( N+ }
    7$ z; U3 j0 X9 H+ ?, N3 q1 p  K
    8: }- C8 v+ U0 {' a. V6 Y* t, g
    9
    ; _  u( a  T0 T10: Q2 p. X) F1 M; `1 j
    11( n, ^" C5 _9 H. h+ W. {+ v
    12
    8 Y# v" @  Q0 @7 M6 |! z8 ~- ^13- u" U3 T( N- i' z: X* a
    14
    5 {% p" U( F" m6 m* q9 s- D" L15* a# }' [/ ~7 E8 J
    16
    , S4 g9 v" O4 Z+ x- \; {- g% [17
    " }1 B! e( w: P- R  b  D+ X1 `18
    5 ~5 s% I9 [' H4 W9 |19% B) |+ v7 M. k7 b/ \* l
    20
    ; B" x- s9 r: t; H- w( t* }9 Y6 Z21
    % c3 a4 k& G5 {2 B" \22
    % P0 r9 h' V! s( x/ R$ y# D2 q23, @  ]$ k$ W; K+ e/ h& v3 Y
    24" J* r) I5 S2 `! l3 ?
    25$ y/ m. h, Y6 S8 W; I& u
    26
    ) L2 Q. F9 A4 W  A27
    1 Y+ {& L5 t5 z5 [2 }( A( [' \: N28
    . @8 ^0 F$ f% r, `0 Q. T& k+ s29# s! F% }2 R% g9 n. J7 L
    30
    # B2 v/ K% E, f% f/ s% l31
    8 r* x) T' I. J( E- K- S, ]3 }32- l: o/ \* C/ L! p' h: b1 G
    33  H& A2 r/ d4 R! U
    34
    : W8 I; W+ ]: L+ v: L, v8 h) h35
    0 I6 ?- X( K1 t9 t& M368 v. q. B, L8 q3 [0 {
    37' f- e" a4 a, x5 g9 d, w) p
    383 U6 n) U+ N4 {' ]
    39! c$ |+ ?6 d3 A% O6 Z8 @! h) C1 s
    407 l% T$ M& M# c" z
    41! Z( c0 ?! g  A$ }3 C* |
    这样我们的程序基本就完成了, 不过这里我们还是需要预备一个TensorFlow 网络,同时需要获取tensorflow 模型
    ; }* S9 \1 y* N: y# Q) T3 f: S+ c& J0 ~0 J5 e# \- p2 c+ s% S0 d8 [
    Tensorflow模型获取
    - t" _  A( X' V首先,我们下载预先训练好的Tensorflow 模型,从下面这个网址5 [5 q, e! \3 z" s5 y5 q

    * Z+ t1 j2 G8 s( Z# g; Whttps://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/detection_model_zoo.md
    " }( g" ?/ U% g$ U然后使用ssd_mobilenet_v1_coco文件,可以从下面下载:' n2 t4 L9 w- E$ v& L2 H
    / O7 z, {2 Y4 o1 r2 K. N6 P% J# M
    http://download.tensorflow.org/models/object_detection/ssd_mobilenet_v1_coco_2017_11_17.tar.gz+ G. w/ V' E. ^7 k( p8 c# J, }

    7 F. n! B! x. m8 ~3 PExtract it to get ssd_mobilenet_v1_coco_2017_11_17 folder with the pre-trained files.6 K) M3 Z# N6 l
    我们必须拿到text graph 文件 ,模型,这些文件应该和opencv 兼容, 我们可以使用下面的ssd.py,从opencv的源代码的samples里面可以找到下面这个文件; K6 k* V/ j3 p

    ) f  a* u8 i# M. z' [( z# z6 `opencv-source-files\samples\dnn\tf_text_graph_ssd.py) X1 D; k2 G3 g+ }4 V
    3 j' I# ^% M) y# ?1 s5 p
    当然也可以从opencv的github源码下面去下载
    ! A! ~3 W+ E4 M9 y& M( L1 O3 X. E5 `  Q0 r: d1 s: Z  O
    https://github.com/opencv/opencv/blob/master/samples/dnn/tf_text_graph_ssd.py% n6 J! J, n9 w: F4 ]

    % u, w) U' Y/ p  r1 ^拷贝ssd_mobilenet_v1_coco_2017_11_17 文件夹 并且像下面这样执行  A0 Q; _, g3 O" p9 \7 @
    Just copy it to ssd_mobilenet_v1_coco_2017_11_17 folder and execute the following:" S0 o* ~8 [  ^6 e" j" x3 H
    6 b& J" D7 p% a
    tf_text_graph_ssd.py --input frozen_inference_graph.pb --output frozen_inference_graph.pbtxt' l( U! m) e7 n+ u  f0 f2 K
    新版可以这样执行:% {& |+ `4 K' H" G* L3 [
    tf_text_graph_ssd.py --input frozen_inference_graph.pb --output frozen_inference_graph.pbtxt --config pipeline.config' z- w3 f6 Q& Z
    分类文件和模型可以从下面下载; S% ]. s' U0 ]( k1 f
    https://github.com/tensorflow/models/blob/master/research/object_detection/data/mscoco_label_map.pbtxt
      O9 M* w  w; B' c! t3 R" T4 {$ _: u' _) H( L% @
    This file won’t be of use for us the way it is, so here is a here’s a simpler (CSV) format that I’ve prepared to use to display class names when detecting them:
    7 a% x( k8 H! r
    * `; Y- t2 v7 n) M  b, W( o4 X( K5 }  `http://amin-ahmadi.com/downloadfiles/qt-opencv-tensorflow/class-names.txt( m5 X. R/ x7 V5 p% `. B
    & g* N2 j2 O# G8 B5 o* \
    Now we have everything we need to run and test our classification app in actio6 k) j# ^' p- Z1 |+ |5 \. x2 t

    2 @/ e( r. F' e% [/ \, N9 q9 ]  L启动图片分类应用程序
    6 F5 g3 n( Q7 r! R9 k' [; Q  @: y从QT Creator 中切换lab, 输入这些文件,8 @; W7 W1 d* U) Y" {

    / R( W) z* C! r0 x0 B) r现在切换回去,就可以开始探测了,9 S1 J* V1 F  |9 _) \" u

    4 i7 `5 F& Z% w3 f
    % E. R5 A6 n( p3 I8 @4 P  ?( r; b9 _以下网页应该对我们有帮助:5 I' D$ r/ V8 i  V% H! L2 U7 k) @7 |
    https://github.com/opencv/opencv/tree/master/samples/dnn
    3 ~6 ^% E- t! }5 g5 _, w6 U$ Yhttps://www.tensorflow.org/tutorials/image_retraining+ O3 P9 q1 v# g. ^9 j0 y% T
    ————————————————
    3 [4 }, o1 K7 V( A4 M0 ~. ^+ P版权声明:本文为CSDN博主「qianbo_insist」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    5 Q" W$ A5 i5 C" l  j" z6 A; \原文链接:https://blog.csdn.net/qianbo042311/article/details/126253546
    - M+ K8 ^8 R2 O$ X) o, N$ o& ]6 z

    + r. ]; W9 m, C, ~, Z! f6 @# t, [
    zan
    转播转播0 分享淘帖0 分享分享0 收藏收藏0 支持支持0 反对反对0 微信微信
    您需要登录后才可以回帖 登录 | 注册地址

    qq
    收缩
    • 电话咨询

    • 04714969085
    fastpost

    关于我们| 联系我们| 诚征英才| 对外合作| 产品服务| QQ

    手机版|Archiver| |繁體中文 手机客户端  

    蒙公网安备 15010502000194号

    Powered by Discuz! X2.5   © 2001-2013 数学建模网-数学中国 ( 蒙ICP备14002410号-3 蒙BBS备-0002号 )     论坛法律顾问:王兆丰

    GMT+8, 2025-8-5 02:02 , Processed in 0.501773 second(s), 50 queries .

    回顶部