$ m/ z! }7 x; P8 h" ^' r. G# L使用opencv qt 以及 tensorflow2 进行神经网络分类 ( w8 Q: v- \, d4 e- i" C工具选择 ; `; Z$ J3 C. P9 |我们将会学习使用图片分类器和合适的GUI界面,GUI界面使用QT,选择一个camera 或者一个视频文件作为输入进行分类,这里是实时进行分类,qt本身是一个跨平台的GUI设计工具,同时我们使用Tensorflow 和 opencv 去进行分类工作。 ( G0 {4 z A3 ~6 K$ b3 w1 w* h7 r
opencv 本身具有一个深度学习推理模块,名字叫做dnn, 3.4.1 以上opencv版本, 使用dnn模块,我们可以加载和使用深度学习模型,这种模型来自于像tensorflow的第三方工具,当然他还支持caffe,darknet 等等,我们这里使用tensorflow 模型,使用 ssd_mobilenet_v1_coco - a: K2 }1 U5 z4 l8 f5 J" f 7 g' m) x( y Q8 u1 \* z本身在windows 或者其他操作系统上应该都是可以的,我们以windows为例 & o0 z4 f$ U0 Z& f# P% P9 L& g. P c, X8 x W7 ^$ N! F
需要的工具 & P% D7 Z0 \; S" E4 r# k• 1 Microsoft Visual Studio 2019 7 K6 u- |& S' o. K: D• Qt5 (https://www.qt.io)2 P( F1 K& l( i O: w- K! P5 b
• OpenCV 4 (https://opencv.org)- P2 ]: ~- _* F, W0 Z; v$ F
• CMake (https://cmake.org)& N1 F! ~) V+ d) d
• Python 64-bit (https://www.python.org)1 v* C6 ~0 k) L6 [# F0 f( b
• TensorFlow2 (https://www.tensorflow.org) 4 k/ |6 G" C" U$ E6 v: O \- k$ y- N/ l4 w, v( `
创建 Qt GUI Project 选择CMake7 r, v, M) B0 l2 `. K9 f2 }& s6 _
我们将会创建一个QT GUI 应用程序,编译方式选择CMake,当然了,不是一定要选择这个了,读者自己可以选择其他方式。0 l+ f" U2 ~% B4 _7 ]9 V
% A3 h l5 U* e8 O3 u这一这里选择CMake8 x4 {6 Z7 I& B: D1 }5 U: Q
; |7 L3 n" |# K5 r/ N
3 J' U" Z: t( Z! e( r
项目创建以后& c7 E" c% Q, a0 r
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): 0 O+ N; ^; x' q, U/ A6 S# t( s9 A" t7 X
# Specify the minimum version of CMake(3.1 is currently recommended by Qt) % Z, D% g" r7 B9 F0 Zcmake_minimum_required(VERSION 3.1) ! \& u6 @& Y( \4 B9 B/ Y % K7 J# V, F: h5 j2 O0 g7 g# Specify project title" L; n3 C% q5 s" Y7 A1 u
project(ImageClassifier)0 L& q5 o# i7 L" e& ]) w G8 c4 l; R
+ j. |) ?& L) ~" q, P2 t# To automatically run MOC when building(Meta Object Compiler) 0 O% Y6 q/ @$ g! y: c$ e% {, S" u" pset(CMAKE_AUTOMOC ON)/ S, C1 z( g% X D: `2 ]
0 i! U- k$ O9 u6 n3 c" L8 a- ^
# To automatically run UIC when building(User Interface Compiler)( u, E8 Z# Z* v* T* O2 J9 N* U! L
set(CMAKE_AUTOUIC ON) 1 m6 Y# N6 \ y/ Q. @3 B% U. {" d( N) j. y' F
# To automatically run RCC when building(Resource Compiler)* Y! C9 ~! n: J* z; v/ D9 j! M5 I: ]
set(CMAKE_AUTORCC ON) # F5 w" z1 l1 z& k7 l3 Z. r6 n" c( D
# Specify OpenCV folder, and take care of dependenciesand includes ' r+ J% n6 l" M2 c6 V$ i$ iset(OpenCV_DIR "path_to_opencv")# v) v. B o; q3 k4 m6 H/ p
find_package(OpenCV REQUIRED) $ i [; u8 G# T& j; K2 h; Uinclude_directories(${ OpenCV_INCLUDE_DIRS }) + A; ]+ g9 H( c * L& Y/ c+ o9 p# `) p- x& }# Take care of Qt dependencies; e7 N$ }; [$ C
find_package(Qt5 COMPONENTS Core Gui Widgets REQUIRED)/ H: Y* @7 D. n! ^
M; M3 G4 _7 X( i3 P4、swapRB:OpenCV中认为我们的图片通道顺序是BGR,但是我平均值假设的顺序是RGB,所以如果需要交换R和G,swapRB=true $ T) {/ i* G% d; ?6 d6 K8 a8 I" P8 m ]- X8 _% z
调用:* t7 Q% g9 t* T9 v0 V# u" N7 p; x
* c* l6 e* ^: P' f% LMat inputBlob = blobFromImage(image,4 P1 m' K5 \+ K/ n3 x
inScaleFactor, ) J6 [. @* O7 U8 _$ r1 i8 @7 Y Size(inWidth, inHeight), + v2 Z9 {% g% @+ f1 y Scalar(meanVal, meanVal, meanVal),/ N2 t# b( \" C4 s. l Z
true,- U" ~" `: u1 t) S4 k' C" F I
false);, l9 g7 A' q q7 F% b: Z
18 U( b. U+ l/ a; c" z3 [
2/ |9 Q) R/ K. _- |& b* n* X0 a
3 5 ~( W4 C6 z% L' M3 R4 x4# K2 h9 Y- c3 F
5+ S/ a5 m' z o6 H
6 2 p- H2 ~3 R1 Z/ M, O- ` iThe 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:; ~+ J( `5 R* p ]8 B# _2 s3 G4 d0 W
1 p' }) f8 N% ^ G: {! cconst int inWidth = 300; 7 e n& B3 \6 ~- Z& \6 vconst int inHeight = 300; 7 H! F: y) ^1 a. f6 j2 I( Jconst float meanVal = 127.5; // 255 divided by 2) e5 C1 \$ G0 }! }
const float inScaleFactor = 1.0f / meanVal;9 t* ^% {$ Q& k" |
1 ' _0 y; k: k8 {9 ?5 s26 Q, I4 A. {5 O7 c/ r' g# @
36 D" A: X" B; E) y+ J
4 ( Q- m( z& e w7 d! K$ W- \使用Opencv4 以上和Tensorflow 2.0 以上,让这个inScaleFactor值可以为0.95 $ u7 m& w S$ @3 o5 R( y5 m让后进入网络,获取推理结果,像下面这样写就行:6 c! [4 c. V$ f0 _) D
% b q( \3 G% ^* d% H! K e2 \$ K
tfNetwork.setInput(inputBlob);9 ?3 ]7 E! ~8 [' j
Mat result = tfNetwork.forward();/ _# ~ d) N! p$ ]# _0 E% i0 c) ?
Mat detections(result.size[2], result.size[3], CV_32F, result.ptr<float>());, t" l' Y3 L: k2 h6 u) e
1 ( X( L3 u& V: E% U) Y, V4 Q/ W" K1 O23 [( E4 F* K. K- u) q2 N+ N' y
3 2 O8 l" H$ e# _) { w, ?处理代码里面比较简单就是为blob 设置 网络,使用forward()方法来计算结果,最后创建一个探测Mat 类, 有关参考opencv数组mat 可以查看一下链接- v6 v# h# J3 r0 s% v
https://docs.opencv.org/3.4.1/d6/d0f/group__dnn.html#ga4051b5fa2ed5f54b76c059a8625df9f5& l1 V' _' _* X
下一部分是使用detector后拿到识别的物体绑定矩形盒子,打印类名称,同时做显示$ x% g* L7 g2 k7 `" Y4 S; J
0 t$ G9 a, g" I/ r( R
for (int i = 0; i < detections.rows; i++) " H5 H: ^0 @; i1 q( Q0 Y9 S3 ^{ / S3 d q5 V$ x) x! y( y1 m3 t float confidence = detections.at<float>(i, 2); 6 C* m5 H. `) } R! [+ d5 m. o" t 7 R' B, Z: S5 T if (confidence > confidenceThreshold) 0 X# r$ [1 E% z6 x { + H3 c0 P& @( ~+ X2 @5 | l using namespace cv;, h" {3 ^) J; B5 A: M/ E; ~# c1 n
5 @! S) C- {4 w: ?2 a
int objectClass = (int)(detections.at<float>(i, 1)); - Q$ Z) N/ g k0 ~/ [7 g$ x6 n* X M$ m( c) b6 j% {7 x int left = static_cast<int>(" w5 C& V f! X' R1 |6 r+ U
detections.at<float>(i, 3) * image.cols); 1 h% g6 r( W& `2 X$ {# d( x# e9 ` int top = static_cast<int>(; A# }4 u0 H& _7 \
detections.at<float>(i, 4) * image.rows);- U' W) ]/ o+ T
int right = static_cast<int>(" x. c0 U' l3 d7 p6 P
detections.at<float>(i, 5) * image.cols);! f- y/ e' x# k& U0 G
int bottom = static_cast<int>(0 j5 t6 @% r7 \ s$ S
detections.at<float>(i, 6) * image.rows);5 R3 I( `- y$ d- K" [
* k; M* y0 r% D+ l( U7 e, d9 V S
rectangle(image, Point(left, top),% y1 p2 Q" H. G; H( j; c" S
Point(right, bottom), Scalar(0, 255, 0));5 n2 ?& l! A5 J) p( r# K' C: P
String label = classNames[objectClass].toStdString(); N! s- N, x' _* ]8 s
int baseLine = 0; 2 S, b, x3 |& @2 V: E" Y9 p; A8 L Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, % ]4 @6 J; p& f, @" K 0.5, 2, &baseLine);2 ]7 F( U. M# l% W
top = max(top, labelSize.height); . W2 i1 k& F( ?% B4 J" g rectangle(image, Point(left, top - labelSize.height), & d) X' @0 @9 x Point(left + labelSize.width, top + baseLine), ( {3 q4 i& N8 G& L Scalar(255, 255, 255), FILLED);6 t, n$ [) s/ z2 X4 h; V! |2 h
putText(image, label, Point(left, top), * b; k l5 U0 Q+ ? FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 0)); " H5 [) y7 Q" x- _9 X/ B- ^ } ! \* @" \+ Z- z. P( v- ]}& b) e a( J* N9 c. U: }
4 G6 q$ U) O9 u; Zpixmap.setPixmap( / P( c; _7 z! y7 A QPixmap::fromImage(QImage(image.data, O3 g. b# }$ |
image.cols,/ |& V/ F3 ?1 p
image.rows, % s8 `( y! Q, z0 ^5 Y2 [ image.step, " M& q. G6 `. h( d QImage::Format_RGB888).rgbSwapped())); 9 ?- U, Y6 f4 h4 \- z& M Vui->videoView->fitInView(&pixmap, Qt::KeepAspectRatio); , m# }; `# X* C' X1 5 B' _7 y* I0 F. L, x& }: L2 5 j, Q# Z/ g- g8 R7 O6 q. {3& D% z3 R1 N! K5 W% @
44 ?% Y8 b+ X# Q. a0 Y; M- ^
5 : g I m5 d) [4 |4 w1 Q3 f5 `$ b) v6 ; K+ a) N& p) @7 C0 M# v1 H0 s- a7 $ b9 d3 N2 C" {! P8 + p/ `5 y, q4 `& n( b U9 9 U5 Q- [; f% {( j# w1 w- T0 e10 g3 S1 ^" @! `& `; k" V9 L9 W115 T4 P3 Y1 V& { C, H0 r
12$ Q3 a1 j9 C# J- Q# r
13 6 {' g* ~. W" u* t1 h' F. R/ v141 V6 F7 L+ l3 C) [6 s( D/ ?
15+ `* v G3 P D9 d9 a8 M
16( E6 O) }: u, Z2 f1 @2 @8 G
17! o6 T# o, ~- \. A u3 A
18. Y# V8 {! H+ n) b* }
19# t, ` x- d, x0 C+ W! _/ m
208 d/ H( a( D5 v p/ A+ D5 m7 `
216 o s5 {: `, F. j4 k: s
22 I) O: k+ ~4 p6 Z+ q5 z23 1 U, _+ f3 I( y6 z' v& _! R24 G Y- m* |( T1 ?1 j
25/ r+ a( \# @5 e, T
26 2 V0 V7 [9 ~# g27 % \, ^% ]& Y% W, f8 z28& t& L( X& V6 K2 a
29 / L4 w+ h4 L0 f. a30 ( l, B6 l% K/ {+ E& |2 \31 ; D" q2 B7 |& C/ M( b) n- ?32 " ?! p; T. z) a, B33; U0 u* i6 D/ @$ G% Y( C
340 B9 x" q2 J: `0 h' E- Q6 h
35$ e3 q( B. r2 N0 ~% d4 `' p
36/ u, ^/ u8 n! R8 Y2 y3 E6 F- u: H* p
37 $ ?* Z- T# L! A; `! d38 ; Y' K ~$ Y) l39+ f! a% W" n- T6 ?) d
40 5 y6 K3 h3 O6 M0 W( k41 + @5 z% p0 E0 Q6 u* A3 o这样我们的程序基本就完成了, 不过这里我们还是需要预备一个TensorFlow 网络,同时需要获取tensorflow 模型 , q1 X- d" o' o5 e9 z# H- V/ |; f6 }4 w ; q- {9 {1 O9 e; OTensorflow模型获取( L; B% a1 j8 U: _) s. t( n
首先,我们下载预先训练好的Tensorflow 模型,从下面这个网址2 Y7 a* \* R* |7 z0 Y1 @
; U2 ~' [- N4 R9 ~# r' yThis 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: 2 y( U6 A a8 ^, u " |. m) w# y8 Rhttp://amin-ahmadi.com/downloadfiles/qt-opencv-tensorflow/class-names.txt 6 ?3 S* `# J F+ l% Z7 c' M7 r" N- a$ m* t) |; F, I! r0 B
Now we have everything we need to run and test our classification app in actio k& s* D- J/ Q
% G6 D) d+ C o* U5 {/ _3 h2 N; ]启动图片分类应用程序+ B0 p3 k2 r- {) p
从QT Creator 中切换lab, 输入这些文件, 6 Q6 a- a4 O3 a. f6 ~% t+ { 8 C. A6 t, h0 l/ Z现在切换回去,就可以开始探测了, 0 d. N I: \* s H g, _$ d ; G4 P4 h+ ~: v. v" P7 ^8 |; } R. p- Q" |# w6 T. i; _0 L
以下网页应该对我们有帮助:' ]- P$ C, [* b( O, ~
https://github.com/opencv/opencv/tree/master/samples/dnn 2 W. I& }: p* h; @https://www.tensorflow.org/tutorials/image_retraining' Y+ h+ Y+ P7 H* ]" B; {* h" m$ f+ V
————————————————- k" e+ z- o' t. L0 f
版权声明:本文为CSDN博主「qianbo_insist」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 - j3 c ?3 ` t2 s; K+ y9 X原文链接:https://blog.csdn.net/qianbo042311/article/details/126253546 6 N8 d3 g4 J P: L5 O- d 1 x( [6 n3 x) q5 q b4 h 4 t( J# v# \' f4 r0 V: K2 S9 D; ^; X s