/ }3 U" `' a7 T2 y- t6 z创建 Qt GUI Project 选择CMake - d3 G7 q1 J2 ^4 [, P$ }! B6 H% G我们将会创建一个QT GUI 应用程序,编译方式选择CMake,当然了,不是一定要选择这个了,读者自己可以选择其他方式。% z# g" F' d! k
, Y9 B/ J2 n1 E% I) `
这一这里选择CMake " q. Y& g6 M) r- B2 H, _, e* B e3 ]4 G/ @0 T7 A
- ~' G4 J) a) w' P+ D) y. u7 g
项目创建以后' Q6 q$ S- j8 m& [5 G8 I
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):4 T3 H, @9 ?$ E
2 i( |' I; R- {2 E$ Y+ H. [4 L# Specify the minimum version of CMake(3.1 is currently recommended by Qt)/ Q1 k- Z- }! D* t
cmake_minimum_required(VERSION 3.1) # L5 _0 n7 \+ F! g# k7 e ( J8 C0 ]2 x4 |) E* C& X$ P4 Z# Specify project title, w8 M# {% r% ], v
project(ImageClassifier) 0 ~8 c7 C& h% E& D7 W9 n' K/ t( P [" ?9 U0 O& h! h1 u
# To automatically run MOC when building(Meta Object Compiler) % J$ p2 L( D/ n. {) Qset(CMAKE_AUTOMOC ON)5 [, f9 _; F* O1 E, y. ]
6 l- y& t( y) c6 X+ C$ x, V# To automatically run UIC when building(User Interface Compiler) % |+ s, R* v6 F7 r( Zset(CMAKE_AUTOUIC ON); z: [; g* \; S+ h
, \/ F! d j+ K. J' |9 L7 b L# To automatically run RCC when building(Resource Compiler) 1 V. ^5 F9 ` H) o3 C& mset(CMAKE_AUTORCC ON)9 {. v" v9 z9 o" x
) }; a1 a& `4 D5 Y, j! y( q" _# Specify OpenCV folder, and take care of dependenciesand includes8 @! U0 Q) i+ y" r6 t; y" C& ^
set(OpenCV_DIR "path_to_opencv")0 H. x% g% J8 o- ?) o% V# F% F1 c
find_package(OpenCV REQUIRED) / m& k. h2 f9 E: S- @include_directories(${ OpenCV_INCLUDE_DIRS }) 7 m# e3 @" y/ h& x% S w3 I ) {8 u M; M' |" R4 I, w# Take care of Qt dependencies1 y( m: f {) H7 ?
find_package(Qt5 COMPONENTS Core Gui Widgets REQUIRED)) ? h$ Y! H1 ^# l* u' v
+ F/ }" B4 Y! k5 q" t* t$ c# add required source, header, uiand resource files/ v" e; m' P# a& F" A' {
add_executable(${ PROJECT_NAME } "main.cpp" "mainwindow.h" "mainwindow.cpp" "mainwindow.ui") + ]3 z/ d0 z; V p y& z& A- x% Q
# link required libs- P4 g: A) I( B* b+ U" P' l
target_link_libraries(${PROJECT_NAME} Qt5::Core Qt5::Gui Qt5::Widgets ${OpenCV_LIBS}). r h( \7 t. Z+ I- e
1 % i+ {9 i" H1 V! \ j23 \. W6 O% }6 R! `- G5 M0 m
3 : }% O6 R J3 Z$ U- H& J4 6 G. n& a0 x8 p$ U. r0 [5 E" q* _5 2 a) P9 ]2 y0 d5 b; X65 r( J, m O1 I, P, D. q; }
7 - t" {: a4 O0 t80 h, _, o* W% W V/ |; e) T1 q8 Z
9# q. N9 x6 e* E9 |7 a
10( ?5 _7 H% r* [
11 - N: J( V- r& J9 x, A12# T4 N+ W; J. P6 `- M) t
13/ l# \. b" u( X& K
14' f' h2 Y8 E+ `
15 & n0 R* e9 h: u' X, W) y3 W161 z7 F! }% p1 x$ J0 v
17 0 |; m- H! `2 K18% t0 `0 G. m2 k
196 o2 U6 Y$ Z& M* J
20* D/ C$ W& l. f1 k1 ~( G
21: |+ Y4 u! a. w
228 ]! g( z! K& H9 j4 |! v
23$ L o( C- ?: k- Y8 d* h7 ~) k, o
246 o0 ~# S0 }# I
25 ( h# R, Q2 j& U$ w" g/ _ o& ^26- I3 c/ P; Y6 _7 [5 T
276 s1 l; U, z2 W2 t
28 1 ^. v5 ?. j& U把里面正确的地址写好,把main.cpp 里面开始mainwindow.cpp 。0 `# d* t5 x, D, Q
! u6 c# j' C1 Y1 Z. U+ T- p; L
写好main.cpp2 Q Y4 V. m# d
#include "mainwindow.h" # t+ q- P/ E% u#include <QApplication> 9 H, o4 E+ W+ ^2 M, N2 z ) y, O" j+ r' J: G* r# Eint main(int argc, char* argv[])5 s" p$ W) e: B
{ - F# ~' I& z3 E' j8 |9 N QApplication a(argc, argv); ) h: u% a! Z2 B4 B$ I9 | MainWindow w;7 ^/ L# C4 q: K4 k6 Q* j
w.show(); : R" r: N) L; n, u( k1 n+ m# Q/ }9 o( x/ K. C( I, [# @
return a.exec(); . Y- R7 j3 g4 M& o! L. V} 7 y5 _2 e" }* V0 y+ ?1 2 d- |$ O! h' s2 e W2 ) t# E# y( f ] h9 l. N32 W! @, {, N- ]
4 * k1 L: G3 r2 S6 B) W5" r: i4 _4 p7 S. E
6 + C) m( D* m# h5 }7 ; k0 C7 j: Z3 p$ A/ N86 |) R1 t% Y! ?2 E1 }
9 4 G7 `; b; Y0 B i& o& u/ R10+ f9 C; s: j8 t" c5 Y
11. X6 z& B: Y8 M2 o& E- X. L
现在使用设计器加上一个窗体, + T0 b9 x' m) b: A0 W6 j+ i . P L+ b2 r6 _. Q& e; ?选择Main Window 9 k1 I7 H3 p/ r' M/ B; K7 H+ T; `! w7 A+ Q% j$ l3 j% V, J% d6 ?, [
; t; j" A' X! Q) Z3 ?像下面这样设计窗体就行了 # ?# \7 }+ O7 S, ?# V# v( ?# V ! ]4 ?1 f- m0 \* x* Z# Y, _. P* h ! P+ d# Z% R5 I9 c g; `“mainwindow.h” 文件代码如下2 a8 ^7 H8 A( G# |8 A
; w6 y2 Z, W/ }' ]2 q: f7 m5 V, E/ M#include <QMainWindow>4 }# R D0 t/ g3 \
#include <QMessageBox>% D) C v# i/ D( u
#include <QDebug> ) l7 }' N' @5 V% e/ N#include <QFile>4 R! m" p {1 Z& a
#include <QElapsedTimer> 0 U' t' U ^. t) ~: X) q0 i#include <QGraphicsScene>( ^0 a0 Z- W9 {6 M2 l
#include <QGraphicsPixmapItem>) x+ l" |, t3 m+ _
#include <QCloseEvent> 3 I0 X! L* D3 }; g4 V0 F#include <QFileDialog> , Y. ]( x) E1 ^6 A" V#include <opencv2/opencv.hpp> 1 J. f% Z) F* X, Q8 D7 e" c. wWe will also need the following private members:5 ^/ N3 {% h7 M, q$ H
6 r: }" C2 q( X5 }; f6 K1 Z3 Q
cv::dnn::Net tfNetwork;9 K5 }: p7 Q- E9 @- c2 ~
QGraphicsScene scene;$ V8 z z* K. {8 V; o! D
QGraphicsPixmapItem pixmap; 1 y' I2 T* m4 ~) X" j4 H8 i3 nbool videoStopped; + G& E6 U }5 A. [7 `' |: {1 + t. p. Z3 h5 C, A) p3 }0 j8 u* H2 6 i2 n" A4 I& J8 t5 n3! W) W, V) R/ y, P! g
4 + K7 d2 u; |3 h& n5/ K) S9 f% E# k' Y
6 ( }+ S7 S9 q5 l7) \+ Z' {7 _0 E- K0 c
85 Y1 M" ]6 R$ R( c& H* w& C1 w6 E
93 V4 h" [' z% ?6 @
10 6 a7 N' `/ @7 ~0 v5 ~11 9 u; I# r- x3 i* Q ]12 ( P( [# H! M2 |3 u4 u3 S8 J: y13 % F& _( ?, z. J9 r14 % H) d6 Y6 Y2 t* x% _1 i15 : X* Y: k3 ~1 E3 _, H1 v% v16 9 M' Y, e7 W9 F+ ZtfNetwork 是opencv的深度网络分类器,场景scene and pixmaps 用来显示,变量 videoStopped 作为一个标记去停止视频. 我们的代码如下所示. 9 r& Q9 w* Y* u9 ~: Y : j+ x2 i0 s- w0 ]/ b! z, j#ifndef MAINWINDOW_H 1 Z) E0 i9 F. D3 S+ e% q3 R#define MAINWINDOW_H6 W/ b3 s8 F2 W3 N
) F7 Z* I I& L8 Y8 x+ i, a调用: " |0 Z: n" ?) u# y x0 t$ N; ?3 z/ [
Mat inputBlob = blobFromImage(image,: ?$ y- P2 L! W# a7 v% V; P
inScaleFactor, & Y) ]4 v4 M1 Y7 |0 Y Size(inWidth, inHeight),0 Y5 S9 J1 ?% \3 A
Scalar(meanVal, meanVal, meanVal),/ H1 g. F, r- ^* C5 F* v, M8 y
true, : E" \6 Q; H) v5 e# f5 B4 ^9 L false);+ t: j1 E( H+ x. W) x7 c
1 ) A- d7 {* X! ]) a7 ~2 n( K2 # k* t7 G) j: m- b3 . K9 h% [8 w" R* v. t/ g4( x. J* e: S9 K$ l+ H
50 F+ G# X6 x4 d0 c
6; v; ~9 g5 u6 h4 I% g
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:* p" k, b& U' ]) L- P, ]3 H S4 G
; z' f3 E. v* f, mconst int inWidth = 300; ! `' U K, C8 f& W4 Kconst int inHeight = 300; 1 w; k" q" k p! ~ s7 nconst float meanVal = 127.5; // 255 divided by 2+ C& N+ I$ e9 e5 k' J! S5 H
const float inScaleFactor = 1.0f / meanVal;& d, |+ P! [( c9 J. n$ {
1 & r. o: u- w5 G9 C2 I& ?2: z3 h9 ~; v" B" ^% X# p, }) t
3( T; L. ]9 F, e" i- j5 a
46 L/ O4 H% O& |. f
使用Opencv4 以上和Tensorflow 2.0 以上,让这个inScaleFactor值可以为0.95 8 ~2 `' R) ?9 B X4 M1 |让后进入网络,获取推理结果,像下面这样写就行:# G$ ?, U9 N3 _- C+ e3 T
( {, ]. P9 U! W+ p/ f6 }5 otfNetwork.setInput(inputBlob);/ z8 H5 J0 \% q# j5 _& f! S9 T) h1 Y
Mat result = tfNetwork.forward();/ k& y# Z# o/ c& p8 ^$ D2 m$ E
Mat detections(result.size[2], result.size[3], CV_32F, result.ptr<float>());# b1 E' w$ G7 s5 \0 }0 K7 L
1 ! n _5 c1 n7 H9 @5 C' u9 w2 & S& a, x W" F$ S# v1 |3 * X0 E+ ?8 B3 M) c) r2 f处理代码里面比较简单就是为blob 设置 网络,使用forward()方法来计算结果,最后创建一个探测Mat 类, 有关参考opencv数组mat 可以查看一下链接+ F$ D! y, l2 W+ h) d6 }& [+ T u- S
https://docs.opencv.org/3.4.1/d6/d0f/group__dnn.html#ga4051b5fa2ed5f54b76c059a8625df9f59 |- y- {3 F; j3 E. A
下一部分是使用detector后拿到识别的物体绑定矩形盒子,打印类名称,同时做显示 p2 x' ]& i5 a( `' b0 A) B & C& \( F/ w: y$ X/ `: m6 hfor (int i = 0; i < detections.rows; i++) ! A T) Z4 b2 f{5 y( M2 {7 k2 j: P( i% I
float confidence = detections.at<float>(i, 2); # u& C( C- |7 H* x5 l' Z2 d2 [) O6 B
if (confidence > confidenceThreshold) , c& b) T7 w" ]( \9 `9 }3 R$ T {5 T/ H# R. n; @) [% F
using namespace cv; W3 x4 ~% }$ v# K9 K/ ^( c1 }1 \8 B" v, Z4 |% D3 @! r0 z. v3 K
int objectClass = (int)(detections.at<float>(i, 1));: z2 t6 w+ \: s8 Z/ H
- y* A9 _, ]: y& W; D" P
int left = static_cast<int>( : W5 G4 ^6 p" o8 Z3 Z9 y, z detections.at<float>(i, 3) * image.cols); % a- _) R$ u N! X, T int top = static_cast<int>(. a/ p8 B4 h# [% s7 f- {! V% l
detections.at<float>(i, 4) * image.rows);3 X* ~ q# D+ b. `! ?9 y1 B! U6 G; s
int right = static_cast<int>(- J" _# j, _. U9 V- W
detections.at<float>(i, 5) * image.cols);! O7 ^: c! E. I, f8 x& c4 b; G
int bottom = static_cast<int>(+ D7 w: J, u3 v
detections.at<float>(i, 6) * image.rows);" N) d e5 q! k# H0 {% J
/ I6 H; V; `" o+ e. E rectangle(image, Point(left, top), 9 S7 r- a2 B( |9 d ~ Point(right, bottom), Scalar(0, 255, 0));$ r+ H) ~ |' R9 B& S3 }
String label = classNames[objectClass].toStdString();4 _" q8 `. v" W r& ^; U9 z
int baseLine = 0; $ b; }& [/ H# i3 c$ H Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, A1 p9 a) C* P! j$ O
0.5, 2, &baseLine);7 l! Y# b( D, f o3 G, W
top = max(top, labelSize.height); ) m1 }) d$ A7 q rectangle(image, Point(left, top - labelSize.height), 8 D3 U3 @1 D( Z U Point(left + labelSize.width, top + baseLine), 3 d4 \' F3 f- w- r- D Scalar(255, 255, 255), FILLED);4 W+ u4 S) `3 z9 D7 ]# C( A( \
putText(image, label, Point(left, top), 3 r& \# C$ [) V1 Z& Y FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 0)); 4 b1 R' M: \5 p' K& f6 [. _ } ' W$ [! i J$ d5 D, U* ? S3 ?4 T, F}: s- g; S& Z! o. S) J0 a
2 G( u4 ~% `# c+ b! P: B
pixmap.setPixmap( * A) Y% G1 c: b5 d QPixmap::fromImage(QImage(image.data, " m% a* O+ R# @7 [ image.cols,7 [% y$ B( n* \5 h6 c, f- w
image.rows,9 y- n: F! ?2 v# A5 S9 e
image.step, / V2 D2 C! H0 k9 R. {! d QImage::Format_RGB888).rgbSwapped()));" f1 \* M2 h2 S- ?9 V
ui->videoView->fitInView(&pixmap, Qt::KeepAspectRatio); 6 _% e) A0 q9 E3 S) c$ a1 Z8 y/ G- v' b: n2& p5 f9 ?5 S/ ~6 ^2 k+ L
3 3 n7 P# b" g; |% ]# |4 3 P1 O) j; U0 L H G7 y56 a* c" Q& e& f
6 " h" n0 }* c: n; r5 ?& _3 w1 `# m0 J73 D( w: P; Q6 X4 H) c$ U
8& p5 ]" J4 F/ z8 |- [- l
9 0 M a2 W( |- c' C104 ?/ C; N& x3 B
11/ ?" Q) f" _' L7 u6 E' b
12 2 r3 o: L5 P0 l' E7 z8 k P& o, u+ M13# e: {' s' k4 h4 C* I: c- Z+ v
14 + r L* J. q) V$ ?151 Y4 n& Y* }2 ?4 G! R1 b' A9 t
16$ ^' B9 Z; @# T, B5 ~. d( _
17 ( j9 C3 D V- U, ^' p; V: {180 B( P/ \; s, g# a6 _2 q
19: z" o! V. ?& Y# I" P" P: {
205 ?7 B8 K+ i$ ?2 N6 O
21 B) t- a& j4 j" l, ], ^! d
221 E: U8 \$ q, E6 M* j: R
23 0 p2 `8 g" P+ }" k! ~24 7 ^) u }5 J( G. X5 |0 `25; e l$ w4 U8 T/ \4 U$ k
26 ; x: Z4 J/ S/ O" a6 v A27 ) F/ `4 L: J+ U$ b5 N1 J: i28 * n% n/ l" Y, u2 v& P296 G7 T6 _5 G, |2 G0 B
30 + |9 o) ]" C: }3 x! I317 g$ s! Q: d' }. {5 {0 ~
32( {! g- _5 Y/ c. d' c
33' x4 d* ?: @& U: k3 d: I
34& g( ]9 d% k( t T: F
35 : s; G5 b) ^% i( T: E36 ) D/ U8 r) |$ e3 g37 : j9 X9 t( D5 T) ?0 P1 x1 [) V38 % R% v4 a/ `3 c39 _1 T* Z$ {3 `! w% u& @( W( f40 1 J. a# f0 R _7 s/ ^& n41 7 V7 E( K/ t; s6 W+ G这样我们的程序基本就完成了, 不过这里我们还是需要预备一个TensorFlow 网络,同时需要获取tensorflow 模型 / x4 t9 k3 X m' s" c/ M. _ # V% u3 N* Q8 Q& K+ e& ?$ dTensorflow模型获取 : K5 P2 h9 B$ O! [. j8 ` e. n首先,我们下载预先训练好的Tensorflow 模型,从下面这个网址 . W" M1 B3 B8 M: \$ v. q( K3 R7 L6 q% M
https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/detection_model_zoo.md( [* [) Q: D( c6 R5 S! M Y% r; V
然后使用ssd_mobilenet_v1_coco文件,可以从下面下载: 7 T) R7 m( Y, f" n" e" Q0 q& R$ p; f3 F
http://download.tensorflow.org/models/object_detection/ssd_mobilenet_v1_coco_2017_11_17.tar.gz$ l9 s: {( V8 x! B
: F1 Q `5 j M* A1 ~" f" S: F2 hExtract it to get ssd_mobilenet_v1_coco_2017_11_17 folder with the pre-trained files. 3 k& [1 x$ [* I' D3 _4 Q我们必须拿到text graph 文件 ,模型,这些文件应该和opencv 兼容, 我们可以使用下面的ssd.py,从opencv的源代码的samples里面可以找到下面这个文件 - N! s8 ~6 S/ s T- Y0 f& U3 G) n1 N5 x! q+ |' w9 Q; [; h2 S9 c- t
opencv-source-files\samples\dnn\tf_text_graph_ssd.py 6 z5 x5 ^. t u( F" H+ ~3 z* s$ M ]
当然也可以从opencv的github源码下面去下载 3 W6 k+ Q! \$ O. P5 I ! F2 d: d" L( I% g7 X" D! u. {https://github.com/opencv/opencv/blob/master/samples/dnn/tf_text_graph_ssd.py) `1 `( r+ h8 X# B0 e$ o
& g: K- J& U9 T拷贝ssd_mobilenet_v1_coco_2017_11_17 文件夹 并且像下面这样执行7 C7 ^3 a5 Q, W
Just copy it to ssd_mobilenet_v1_coco_2017_11_17 folder and execute the following:# S9 X: J( K0 f. K+ t
6 d/ b4 `* R+ C. w( PThis 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:: r p2 h- Z2 W) g' {# R
( a- P0 g% r) {
http://amin-ahmadi.com/downloadfiles/qt-opencv-tensorflow/class-names.txt6 H0 q# \ W5 D
' ]) e$ E+ i* Y6 T- [
Now we have everything we need to run and test our classification app in actio 0 ^% x: @$ z6 m3 R8 U* G6 U: R; [( [
启动图片分类应用程序: T! r& h9 b& {, a' _
从QT Creator 中切换lab, 输入这些文件,% u) o9 G& J5 z( {3 ~
5 T! C4 k" _! X现在切换回去,就可以开始探测了,6 r b* [. p/ d. B
( X, V5 j' v1 ]8 a: @0 P, O4 H : K G; r3 w; {0 a" I0 O以下网页应该对我们有帮助: ( W$ D: F0 V. [3 J% Chttps://github.com/opencv/opencv/tree/master/samples/dnn : @: s9 J$ f( L8 @6 O0 [3 Whttps://www.tensorflow.org/tutorials/image_retraining 6 Z4 j, z7 O7 R2 i" F————————————————8 h/ t1 m: `5 |+ N2 `6 C* O
版权声明:本文为CSDN博主「qianbo_insist」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 : j) w& `* n. L, ~( Q3 E原文链接:https://blog.csdn.net/qianbo042311/article/details/126253546, n M; }- u, n) c2 p7 O* n6 J