) z: G+ O4 a* B& `* J$ K' b+ h5 r7 X 深度学习和目标检测系列教程 8-300:目标检测常见的标注工具LabelImg和将xml文件提取图像信息% R: p% D5 j: ^1 X
图像标注主要用于创建数据集进行图片的标注。本篇博客将推荐一款非常实用的图片标注工具LabelImg,重点介绍其安装使用过程。如果想简单点,请直接下载打包版(下载地址见结尾),无需编译,直接打开即可!3 Z* w/ E$ U! Y! _1 |4 E- ^9 L
* C& P( J# O H' l' ^
- s6 h5 K c( H I" @感谢原作者对Github的贡献,博主发现软件已经更新,可以关注最新版本。这个工具是一个用 Python 和 Qt 编写的完整的图形界面。最有意思的是,它的标注信息可以直接转换成XML文件,这和PASCAL VOC和ImageNet使用的XML是一样的。 6 d2 u* c( ]7 W5 G) M5 x6 T* y/ Y ! ?0 e2 p& y5 t E2 u+ Q7 x) l+ I8 Q- n( g. g( L$ N6 S/ D
附注。作者在5月份更新了代码,现在最新版本号是1.3.0,博主亲测,源码在Windows 10和Ubuntu 16.04上正常运行。 9 \; V: |# }, C$ Z . o( A2 D' v$ A7 ?$ }( [; X7 Y" H6 Q) D# T
具体的安装查看Github教程:https://github.com/wkentaro/labelme/#installation . W+ _1 i2 e" t" a, ^% v( e' `' @0 L/ Q0 q% ` N5 q
}& U3 c& L4 o5 U }; ~6 J3 u
在原作者的github下载源码:https://github.com/tzutalin/labelImg2 S) E+ }* \4 _/ K
。解压名为labelImg-master的文件夹,进入当前目录的命令行窗口,输入如下语句依次打开软件。 * q0 n9 M2 u" n4 _ 2 p, B( s" u3 T u , S d! }( D, ]( u! spython labelImg.py ; g5 Y8 X6 \, j* \$ X v1 3 n7 L$ E7 D+ H$ c+ |4 } u 5 a3 d C% Z: ]- x& O5 g$ n$ i1 d( B3 w7 @
5 J/ A& b) |' t( S5 p2 ]" v {# w0 c0 j# w$ {
具体使用; ~4 e" \8 S9 \" w; ^! y
修改默认的XML文件保存位置,使用快捷键“Ctrl+R”,更改为自定义位置,这里的路径一定不能包含中文,否则不会保存。+ _ @ r" Z% r- c& N' | P* V' K
' U: `6 O4 K* c) ^3 C! @
4 _* s6 d; m* p ~* Q2 x9 \使用notepad++打开源文件夹中的data/predefined_classes.txt,修改默认分类,如person、car、motorcycle这三个分类。$ [) ?: i/ W- m; w1 ?' y' y
% T' z# A9 W+ W# w* N . V8 s' h( _. `$ v0 v& x“打开目录”打开图片文件夹,选择第一张图片开始标注,用“创建矩形框”或“Ctrl+N”启动框,点击结束框,双击选择类别。完成一张图片点击“保存”保存后,XML文件已经保存到本地了。单击“下一张图片”转到下一张图片。6 x0 j2 @; \1 V& `- l8 K" v( o
, f k6 A, Q+ I3 u
6 p0 K3 c0 ~& W* [贴标过程可以随时返回修改,保存的文件会覆盖上一个。 ' r! M$ e- N& u" J6 ^3 n X. d! f
6 z# \5 X3 X. d2 a
完成注解后,打开XML文件,发现和PASCAL VOC格式一样。 % n9 y" p0 D3 C F3 C0 M& }: l4 X4 X0 Q& [1 E/ L
3 g4 g2 f$ i% b0 z. e将xml文件提取图像信息 F/ r* ~1 R* f7 y9 M
下面列举如何将xml文件提取图像信息,图片保存到image文件夹,xml保存标注内容。图片和标注的文件名字一样的。 2 d2 X' h+ a u' j7 [7 l- a ; E: m6 z9 i/ x5 H1 u& X: ~+ }. ]( l6 H
0 h+ w. q& C( _4 h' q' p ) s. w: ?- o; Y0 M# R下面是images图片中的一个。' @& C7 x% B: P' J1 q* m+ ?
, i9 m" j$ u% {1 g( z. G' P5 x# a / M5 a2 w$ I u( `下面是对应的xml文件。1 M& C5 G- N" z4 z: @* J" r
3 b q* E) ?$ s/ H8 v* }: k! \+ W' y! o
<annotation> , t; A2 ^- y5 H9 t: o; u0 l <folder>train</folder>' _" \1 J' ?7 w$ `* v
<filename>apple_30.jpg</filename> 0 Y) m6 i* S# O( x' M/ U7 L <path>C:\tensorflow1\models\research\object_detection\images\train\apple_30.jpg</path> ! f6 n# k- e+ W/ l( I <source>0 J9 _$ b) I A+ |
<database>Unknown</database>2 l* v8 o, Y6 b+ `
</source> " ]" e' p6 [* Y' f. r, ], n/ M* E7 Z <size>! W. P2 p, w; v
<width>800</width> $ v- \) S5 U! p5 R7 j2 W5 n1 A. o <height>800</height> 9 N( A. X! j/ H) B2 Q4 O' g <depth>3</depth>; [; ?% {5 i8 T
</size> % U7 {% V* X" I0 c+ a <segmented>0</segmented> - X! ]! }+ z$ l0 K$ U0 C, F <object>8 Z4 y& A7 v7 b4 k
<name>apple</name>8 {+ [' b- F5 x7 N( l/ H
<pose>Unspecified</pose> ) z- @- w. l+ A <truncated>0</truncated>4 m1 A2 B. J& J/ G5 m
<difficult>0</difficult>) q3 |/ B' V8 O; J7 n
<bndbox>! g/ M" l; Q( n+ Y, f4 G
<xmin>254</xmin> ; [3 j. a Q/ Z& A <ymin>163</ymin>0 k h K) l; x' @
<xmax>582</xmax>7 }, \1 C- d' W$ s' i, D3 c
<ymax>487</ymax> 0 q4 f7 f# x+ {7 @" `+ ^- s </bndbox>0 \# ~ m: a6 N/ a
</object> 6 A4 ^3 K% P+ V! A" v, a# F9 d, V; S <object> " K1 l" V: Y6 Z+ {: Y <name>apple</name>6 l7 X# w0 t6 r% z- S. M
<pose>Unspecified</pose> # x: M5 {) F3 g& T <truncated>0</truncated> . u- G* F8 z: f <difficult>0</difficult>! N. b8 H5 c: u
<bndbox> " A0 T) v1 m( v, _. } <xmin>217</xmin> A0 J+ s/ w# F. Z7 s L
<ymin>448</ymin> 2 H- z/ l9 ?6 @9 K <xmax>535</xmax> 5 w) Q: ^' S. i <ymax>713</ymax>+ {, b! _- B+ x& @" e
</bndbox>; K$ w) \# e, L
</object>. d S, Y& S" ?: T; J9 @9 j- E
<object> 9 u7 E; T( Z# Y7 l8 p <name>apple</name># X! p$ d9 D! j H! z2 E" R
<pose>Unspecified</pose> / E: R" K3 l, s0 t% D <truncated>1</truncated> 6 K! K- y' ?4 d: A, z. G <difficult>0</difficult>6 Z. g4 g& i* c7 w5 M
<bndbox>/ I, {$ L- Y+ i! O3 p+ _
<xmin>603</xmin>( s# E5 a p- O: N' N' F% n
<ymin>470</ymin>- E0 G' v2 }3 P4 o
<xmax>800</xmax> $ } O( P. \7 g# a2 M6 X6 i <ymax>716</ymax>* i2 I9 V4 m% W( K% S: H
</bndbox>7 q3 n3 m4 C3 y# Z
</object># ^ r3 s- ?1 ]1 ~
<object> * M; a: k0 c1 Q+ q+ k: T; g0 }- J& ~ <name>apple</name> / [! e& l N: s- A M: a0 M <pose>Unspecified</pose>) T1 ^. [1 y( a5 z+ G, r8 `0 | I1 J
<truncated>0</truncated>; K0 c- f6 s8 c' \1 g; p
<difficult>0</difficult>: D' _. O$ n7 U/ z. ?
<bndbox>( W1 Z& c$ r# }
<xmin>468</xmin>8 D" V/ N" }2 t( X4 H
<ymin>179</ymin> 4 u3 r7 v" W7 \1 Q$ k0 h( b- _ <xmax>727</xmax> . b5 n, {) B$ G# G2 B; G <ymax>467</ymax> . u+ C& ^, g, w </bndbox> " b1 F9 @( K2 f" X/ C </object>. ~* q# L1 y, k* v0 `. r
<object> 5 F) D$ i) K. @0 I4 J$ B <name>apple</name>3 W m% Z# a+ D
<pose>Unspecified</pose> , j! j$ D$ l! R- |/ L <truncated>1</truncated> - `- y% r8 A. r: v! B <difficult>0</difficult>( H9 x/ i; \& O( ]: [9 B# f7 e
<bndbox>- [) |! Z8 l& H4 D0 m6 D. x5 B$ [
<xmin>1</xmin>8 r- l% I/ R. }- y; u6 W) F
<ymin>63</ymin>* A2 J& Q) X6 o) _3 x
<xmax>308</xmax>" a* N7 w, }0 k- C6 z) n$ c: F& R1 L
<ymax>414</ymax>& v: Y, V* H& d
</bndbox>% U2 m2 o# ~: T% E- f
</object> ( l5 j. B) g0 H# B6 N J& v</annotation>3 C) \; t L& D# [( q: c, e6 l* t
1 ! X3 P9 \" m) S# I* r5 C7 B" ?2 ) O( U; k* `$ ?/ `4 Q3 ~, N3 4 F4 h- I0 e5 W3 V4 m, R4( Q; _! f# I a5 v/ R" z: Y
5 * ?$ V6 \, `( \- e; m0 A7 t6 6 G C9 x- K3 [- P) U% @7 ( F. Z9 D8 e& M; M8 / C8 B% Y5 X" @9 m Y2 W$ s# |! C- s9 2 I/ B1 Z8 ] ~) X10 ( L% f ~$ R' G117 O! r. a* L1 p
12 ; v9 u+ G: a t& P! K136 A- l5 H1 f# z s1 l7 m7 n+ r" ?
14 9 J1 q% E3 A6 B& f) x/ j" V" @15 * Z" A% d t. `, f9 N! D% I, y! J16 " C: i: Q0 f3 A/ u, E5 s178 S) X2 j: l" |: C
184 F! I4 Z( Q d' X- y5 x0 e
19- N9 q4 W9 @/ o" |: P# ~6 V
204 g, ^2 l' }! K$ z/ g% M, h
21 & f9 `* M# A L& t" o22& e# L: P% y( F
23 ' Q& }3 q; H, T248 v( g0 j$ |" |: p$ ?
25" R; R6 i0 U: @2 G0 t
26 / p- _: v* n7 P3 \# T( p) |27, B0 r: a. ^2 W" `
28/ p5 J3 r6 @# P" X) M4 X- e0 `
298 ~6 Q8 a: z+ ^- E& M
30 1 |6 E. J$ H9 c/ Y! w1 q3 w/ w: J31 3 |1 Z1 q3 B( |8 P" T# H% O32 6 U9 S% v3 R1 n" w6 G4 e332 j9 P+ [7 E J: B, j/ b
34 ) W) e, x6 o* [4 D) y355 v; ]. o# C+ h9 |# f4 o
36 4 D" B' l: w+ i0 D# b1 z8 f37 , Z$ c8 j7 k# O* P* ^6 i38. G4 `& B9 G6 q0 M5 D
395 t0 s2 Y. b. H! L7 F/ ~
407 d- j# [1 |+ B! R* \: c
41 ! p- X! `; Y, o! K. V42 y. ~8 x& N( {% g- ]* j432 ^0 O3 h* z1 M% j& o3 {* o0 |
44: I. i& M5 o2 B+ h) B/ |7 S$ I
456 |: u# X5 Y# }* r
46* N7 \: J5 Y. [5 @
47: M) k+ A6 f2 n$ Q+ ~. x- ?: o. P
48 / W7 W/ Y/ `6 Q& y& |* s49+ A, f" f: ~( Q4 a$ u, A/ o7 T$ N/ ^9 C
50 - l8 ?6 k" k; ?51 % z) ?3 F6 L; g& X$ n52 / F' ]" P1 r) l534 \% b% ^1 n7 o0 M& q
54% T: q8 G' Q7 i9 u5 N
55 4 G) q9 e+ L6 F. @% E/ _567 `2 g R' H" w" B' z7 s/ u) n
57 4 k3 Q0 A/ ?+ y58 * P& `- d& S9 G! [2 S593 s& Y0 k8 _6 {
60, ?$ T& \* d: y" a/ a
61( Z" e# H8 y) A( [; p% O h
62 ( V! F8 c: ]2 G- Q2 ^4 S63! I+ L; E4 O+ F- P* w1 ^
64 4 b0 B u/ R2 A) R" i+ J65 ; a% Q% R9 |: F2 c66 , ~4 K7 p e: A+ L+ a& m67 % q8 @4 F6 E1 P1 ~* d68 0 C# A+ d2 S0 l+ v69+ \1 |' `3 B/ y* a9 m
70 & G$ U' m+ L: m1 q0 Q5 ~71 ( g7 ?$ G; P% u3 O722 f4 n$ s* B! Y+ {# M5 }# ]7 [8 g
73 5 \3 ], C h( ?8 {, n' d( a74 4 n7 z% q# q, @& e$ ~将xml文件提取图像信息,主要使用xml和opencv,基于torch提取,代码比较凌乱。 * r) j6 g4 b5 B* l. ?# ^; X V. c) Y, m1 P5 Z
: H/ C6 p }& I8 ~: G/ rimport os 6 ^: \5 B) ~. I& N4 limport numpy as np2 t6 j& c- k5 T" `! x8 h1 n7 i
import cv2 $ w6 g4 D3 X& g* s# m+ @! Yimport torch0 b% H$ k2 Z! }- e! n
import matplotlib.patches as patches3 G9 ?& u% k0 d0 t% h$ p9 l
import albumentations as A h- b4 v) h7 t- n2 r
from albumentations.pytorch.transforms import ToTensorV2- ]9 t! i3 R" g6 v- ~
from matplotlib import pyplot as plt" O! s! `' ]( D# M ]
from torch.utils.data import Dataset # n) _) G5 s* _ K4 R+ c- dfrom xml.etree import ElementTree as et : A! m" s" k2 } x2 [8 hfrom torchvision import transforms as torchtrans * v( ~9 C/ e- V( ?$ Z8 b- S1 C9 T+ u# n% ^+ }) F
% t p2 D' l. P7 R9 M5 j# defining the files directory and testing directory , W& X! K( P. l) X5 B% C: `train_image_dir = 'train/train/image'" K4 e9 _' v, Y, K0 t
train_xml_dir = 'train/train/xml' . L9 N3 D! V$ h8 F# test_image_dir = 'test/test/image'' k7 b2 ]3 _. H/ y# l1 Q9 S* O
# test_xml_dir = 'test/test/xml' , u q5 T. R- v1 b! _- ~2 r& E6 y4 v Y. Y; Q" q( ^
' Y0 q+ H; {+ @: F* x3 D
class FruitImagesDataset(Dataset):$ \7 @; W9 S. P, @ h- S5 w
3 e+ n2 [8 k3 R) j/ H6 z- j3 J6 L3 s1 b( [# v* |& x
def __init__(self, image_dir, xml_dir, width, height, transforms=None):. r2 Q5 Q6 Y" G1 w
self.transforms = transforms * w& ?& p0 M9 V2 G8 A i! u self.image_dir = image_dir / N% ?: A9 D. y! C1 _- T self.xml_dir = xml_dir( P7 Z- h# H0 B2 o! Q, p
self.height = height 2 r6 o- n( ?- M self.width = width - I) `) [( y3 @/ D6 o1 T/ Z* X6 ]4 i9 M- Z
8 I; p0 Q! y" f3 t. p( ? # sorting the images for consistency ' E) i9 b* k. [+ U$ A/ e # To get images, the extension of the filename is checked to be jpg $ Y# ~2 H+ r& A+ j A self.imgs = [image for image in os.listdir(self.image_dir) + u% s% W9 p- g* X if image[-4:] == '.jpg'] 4 r1 a! P4 D" E1 b# K7 A self.xmls = [xml for xml in os.listdir(self.xml_dir)% {( d8 v8 ~7 B! c/ E
if xml[-4:] == '.xml'] 2 M& ?. y4 i/ x6 s# I 0 ^4 j L4 {9 M; K( o0 N8 g% |- V) f% v : g2 W0 @6 Z$ W# d9 D7 _& h8 [ # classes: 0 index is reserved for background 8 g) [# N- [6 @! e& T6 O self.classes = ['apple', 'banana', 'orange']: K( h. r5 p/ X
3 r/ e+ h L- W 6 N$ z+ w/ N/ T% o; b: |2 k8 @ def __getitem__(self, idx):8 R( D1 v2 V! I5 Z1 B$ s. W
/ U2 s ^* t, o + f& L4 q+ Y8 S$ l img_name = self.imgs[idx] d) g4 R# c9 O) S
image_path = os.path.join(self.image_dir, img_name)7 B2 }4 U# F) q$ `0 `
$ }3 g3 T0 v0 I- d: y
6 T0 p, v9 ^; p! ~
# reading the images and converting them to correct size and color+ u, t9 Q. X6 j5 ?
img = cv2.imread(image_path) ' V* s9 _; U6 y" h# D( @: v0 q img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB).astype(np.float32)$ F9 Q1 c( {0 I A
img_res = cv2.resize(img_rgb, (self.width, self.height), cv2.INTER_AREA)$ a! R3 q2 `0 j* @% l
# diving by 255: k$ D$ t; M' p
img_res /= 255.09 T, C+ {9 Q; g& |) y! _
1 B% ?0 \6 Q* r! t boxes = [] 9 ^& o% x& A5 J* e* Z4 m! T+ i labels = []! v: O6 p2 }; ~ y" Q8 ?! P& |" t8 Q
tree = et.parse(annot_file_path) , N: ~2 Q: }3 K. M- Y root = tree.getroot() $ Q3 [9 b* m, A/ _ 5 _" e+ n) [5 J% r" I- ~# a8 O/ Y / I, W3 x5 G% z7 a" O # cv2 image gives size as height x width $ {# W! M0 R- T6 W wt = img.shape[1] ! r! k) q3 K3 U6 x1 y$ f ht = img.shape[0] ; z- i4 O+ W) D5 L1 V- M# {" p5 V% ^5 e3 H3 ]$ K
& a- R5 e% c+ N: B8 \! m$ d1 [
# box coordinates for xml files are extracted and corrected for image size given3 I6 M; p; Y6 k5 Z( {- Y0 y
for member in root.findall('object'): ; O* j* i, r( b: ]: |/ J labels.append(self.classes.index(member.find('name').text)) $ @$ T0 x1 @# p' n8 W; ?( _. |% u3 t
8 s# X4 W5 ~# T% C9 I5 A # bounding box ' m5 Y. V9 `3 Q' f xmin = int(member.find('bndbox').find('xmin').text)0 `3 U/ F) a2 s8 h8 s3 r6 e
xmax = int(member.find('bndbox').find('xmax').text): y) h9 c3 c! l% \: y. L$ R
7 f# L# `* O3 R+ H8 m, Z+ q0 g) h8 z6 k. s6 F( l5 f1 d
ymin = int(member.find('bndbox').find('ymin').text)4 x' K6 B* `( A/ A# G _
ymax = int(member.find('bndbox').find('ymax').text)" Y; } T( g) M6 j* g
8 q) J" t& G6 c
4 G6 P( E, v( a3 r @# e% g8 l
xmin_corr = (xmin / wt) * self.width 7 P( Y' V \& D xmax_corr = (xmax / wt) * self.width 9 h. R' [; @/ {$ N ymin_corr = (ymin / ht) * self.height: O$ c$ i6 B2 J8 S" S
ymax_corr = (ymax / ht) * self.height ) i" ?: i1 Z# K- u3 a/ H boxes.append([xmin_corr, ymin_corr, xmax_corr, ymax_corr]) , N' v7 f* V' N/ n% z! H5 K9 H/ P
+ {! g4 s' s8 m # convert boxes into a torch.Tensor- C6 |( E( x; K4 U: w
boxes = torch.as_tensor(boxes, dtype=torch.float32)2 U! h( v+ c9 ?2 f
8 q+ E& E/ s' K% D- J. E5 b: B/ x
5 Z! H/ D% F7 ~8 X # getting the areas of the boxes9 ^8 S5 U/ Z! q, S
area = (boxes[:, 3] - boxes[:, 1]) * (boxes[:, 2] - boxes[:, 0])" |* X3 P/ Z$ S0 t+ X/ ~+ x- G
& Y8 o! l" Y- K- V. G4 L
* q' a y& |8 k" h # suppose all instances are not crowd3 q* V0 S6 y) g
iscrowd = torch.zeros((boxes.shape[0],), dtype=torch.int64)- D. ~# F& d7 ^4 l D, y
; M. I' C% s) s5 H7 r* V1 `( Y* _+ P- P2 {) \* X# a J; I' d8 R
labels = torch.as_tensor(labels, dtype=torch.int64) v6 H/ o6 H# H4 F 4 z3 k) D8 e4 @) m4 o0 a8 z _6 ?6 b F
target = {} ' X# D' p) d5 `* z$ ^' }3 P; J target["boxes"] = boxes4 l: O; s" U7 Q) t
target["labels"] = labels0 t+ W9 Z# `9 I0 H* p6 g
target["area"] = area " x! F5 |% i7 B% z+ }. n) {& K. | target["iscrowd"] = iscrowd : M" W- _8 K/ d # image_id : J* K |) i) s1 }% D image_id = torch.tensor([idx])/ i0 H4 T1 Q4 n- w \3 C3 b
target["image_id"] = image_id( r$ \6 `6 y7 S1 ]& z
+ Q: E' C. B; A% e4 N$ Q9 j
) H$ G8 ?8 u, s# }5 {4 y& s; V9 b if self.transforms:# L2 ?0 X9 x& s
sample = self.transforms(image=img_res,$ Y# h6 X' ?5 M) m8 D4 c
bboxes=target['boxes'], 5 w- N5 M& \2 l labels=labels)1 {- X' f6 W" l$ Q; G
7 g$ V2 I' i& P2 D" l6 h " z C- l8 U. E" Y' P img_res = sample['image'] 5 ^+ d: `) y4 ~ target['boxes'] = torch.Tensor(sample['bboxes']) 6 r g0 w5 d5 r) B! r 0 v# q5 u7 t- G2 s9 X4 q2 v2 c$ _ c: N0 l, d: r7 l. ^ return img_res, target9 t' g$ U# Z1 Z2 G6 q
( M" P* I) V7 C4 {5 ~+ o 1 r+ z8 B7 |0 u def __len__(self): : U: j! H9 T1 g% P return len(self.imgs)# K% d7 u: Z& i! O( _" |0 {+ o
( @1 b( B7 l* H$ k) u. i
6 x- i. B" q. z g# function to convert a torchtensor back to PIL image$ v9 \, g. ?$ s7 ?3 |
def torch_to_pil(img): 4 {$ o$ r8 |% |' ~& v; a5 m% V# {( c return torchtrans.ToPILImage()(img).convert('RGB')3 c* _+ s9 G/ R! Q
% S; |- N* [0 E
6 F; @4 t. D, e& S8 [ : w. q) h. H$ v: I" W( d* T& h! V) [# G x$ j9 G* o
def plot_img_bbox(img, target): # [4 Z2 _( z, m1 }2 L # plot the image and bboxes: Y( ` N0 }7 ]( T, U) w3 F
fig, a = plt.subplots(1, 1) 1 x- e# E7 s! f7 C% J" I. A fig.set_size_inches(5, 5) , k$ ]3 o+ ` i6 h# D5 E+ e9 w) ` a.imshow(img)5 c. t, X3 S: F3 m$ y
for box in (target['boxes']): ! o3 A1 I+ k5 ]- v/ M4 b x, y, width, height = box[0], box[1], box[2] - box[0], box[3] - box[1] 8 c! `+ |' G9 Z& p4 I( Q1 F0 j rect = patches.Rectangle((x, y),+ B" V! ^0 r; r$ y c# j4 [
width, height, $ s) T" d: W5 j$ m6 X) ] linewidth=2, + _: Q; b) y- Q E3 h3 i D3 Y edgecolor='r', 9 r7 \ k& ` q9 y% i facecolor='none')+ K; ~3 R5 d. L5 B% {
0 I3 I I7 F; H4 n7 W7 Q / L; C/ }& V0 V# j6 P0 l5 |; P # Draw the bounding box on top of the image 1 ~5 f- P5 l2 t% l a.add_patch(rect)1 A. F/ f% `, l" S4 I
plt.show(). F) n# L# M% K
& @1 ~9 x# _) Y$ ?. I" q
/ r2 K& S# J, N( F
, r7 u& J1 V6 |& R/ Z7 J; F
% e7 G% w; b7 M/ a1 p
def get_transform(train):1 e/ s+ T# I7 [) q$ J
if train:" J6 _2 m* ?* d8 m. |" q
return A.Compose([ 5 y# W$ s. |6 v- z% L' I A.HorizontalFlip(0.5), ! c$ I3 ~2 C. q$ U7 r- ] # ToTensorV2 converts image to pytorch tensor without div by 255 2 L0 x: }- T+ Z/ H8 l ToTensorV2(p=1.0) 4 O2 D+ Z% H$ z6 M4 O! ? ], bbox_params={'format': 'pascal_voc', 'label_fields': ['labels']}) 6 w9 A4 w4 q/ N$ k0 z0 H( B else: ( E4 t5 I8 X* m return A.Compose([3 i: }$ Q8 a* D0 g9 P
ToTensorV2(p=1.0)' w% {4 i( |" Y9 |
], bbox_params={'format': 'pascal_voc', 'label_fields': ['labels']}) . z# {8 @8 t8 f2 z: P# N% g0 z/ `9 O6 A# q n
* g2 @7 d9 g3 m- j/ m9 ?- K$ _ ^& K2 V2 u: m! Y
6 T3 c/ v3 p6 a9 u/ _+ g) H$ M/ b$ W5 H/ ~, w# F
# U7 j) ?- w, R) J. v9 [6 ?
dataset = FruitImagesDataset(train_image_dir,train_xml_dir, 480, 480, transforms= get_transform(train=True)) 6 c S3 ^+ } K1 L2 Z+ `3 l T+ A3 o6 e Z2 P$ T
1 w6 P0 R$ |% X U! l1 K, cprint(len(dataset))& p8 U6 q0 O6 `4 h
# getting the image and target for a test index. Feel free to change the index. 4 {" g2 o$ f: [img, target = dataset[29] 0 F1 U, _; H" n) G) ]( x4 tprint(img.shape, '\n', target) : Y% v8 I! J, X% R1 K; }9 \2 _plot_img_bbox(torch_to_pil(img), target) 6 A; s" X; @% F0 }( V7 B" J1 l/ f `2 C; k1 q2& q) h' a+ s; n8 Q9 x* C
3* i- p$ H% V( i4 Z8 r, @/ @" s
4 ; J( n( I0 H9 Q, o5% }, e7 `1 x U# }3 k) ]
6 - Z# ^$ F5 H0 P3 Y! Q7# J c, h/ T$ `% h1 k
8+ X6 ?& v; X+ A
92 z3 x8 y/ ?( L$ x# a% b
10& u" m+ Y! F, q+ z3 I: q: F+ a2 ?. N3 ~
11 ( B! G3 Q- B7 j0 K2 C x$ x% z2 ^7 f12- C* E' M$ O3 ?/ w8 Q
13; M1 `$ r; I4 d- G. X
14 6 N1 w: k- z/ J# H8 F P15 ( z1 U% n8 [% f. t9 k- u R( G166 {3 X" f, u- ]5 `
17 S' a5 E" \ i* `9 ?: G( e1 j18 - X! k5 A0 M0 l1 e; u19* V1 x# e5 Z! p
200 w; ^9 W2 E& B' @7 \( k% [( ]% ?
21: {: g% _& o" |+ J8 G1 C. |
220 l1 F- Z6 L6 _0 |3 m# m& P% Q/ e
231 a5 i; D" D; R* d
24 0 L* [ o1 U) |1 V2 \251 e& X a5 M. j9 d. O
26 & x- Q" O5 X( V% C. [; }+ A6 x27 8 ^" F0 u0 K. h* E& R( C0 `28+ J6 _: k1 p3 t* K7 C7 s4 n0 C8 C
29 ( Q5 Z7 \. |8 w30 7 @& v; c" q* j. U310 |7 E: j; I/ i1 ~/ s2 ~
32 : q" J2 `8 Z _4 H/ @' u) g33 , V3 X7 b3 m8 m* _340 G1 z" t4 r6 N9 G5 P9 F3 d- ~
35$ I2 e$ _0 D) d. h
36 1 ^2 q8 F7 x* x" M& ~37 7 b& S+ ~4 H% K% r' C4 Z38 6 T7 g$ ~. t( Q% Q39 % t8 Z1 _8 ~+ r# Z( W, C9 Y407 H, [7 g+ _' d7 m* B
41 # M2 {* A# X$ e6 F7 i4 }42- M; }6 k; r* V5 a8 p
43 ! F7 Y& K9 P6 J6 t0 h+ ~44' e4 P0 ]0 |( p; Z4 Y) t+ G) ?
45 : w, L( a! }* W. e0 }3 }46 , O( \( k. C( l, R5 I( t; v47' U# Y& l7 h: w. z" @" c6 o8 W
48, q, G3 \* R; u$ R" A/ Q! f
49 2 Z# r7 v2 f$ z3 d2 r50 & J- t, S) [2 u- {7 I- Q' b2 U+ y517 c$ s2 x8 |. P/ C
52 4 {6 a; w4 J3 [0 @( i: b- ~53 5 V6 w' g, z6 a$ W z1 ^+ O542 U8 i" o9 ]- G
55 1 W5 E; R K; L- m56+ O$ ?: G& g& S- q# Z4 ~5 O( k" m
57 $ f0 \8 J$ H0 f+ O0 ^58 * H0 T2 b4 {4 m! n) z59 * w F- N9 h- h; s* S60 $ J8 U% Q+ @. T2 T! d: `611 r! y9 q/ S8 j( O2 t& y
62 ; t* @, J. c7 ~( Q. V* J% O63 7 A, z* g, ~ l0 W64 & s5 N4 ~" W1 j( h65 ( K! c3 \ X4 V8 ?7 f! Y. z' K661 I: ~4 g- J* U! C
67# [2 S7 t5 I$ @
68 # w/ Y5 C' H# u) O, [1 B z K1 J1 f69 % M; r5 r3 w8 q4 ]& ]! y70 # W' f2 U% J V! h: J- G71 1 J% o% G* x/ k7 x" E% r, Z72 ' g6 t1 N, ^: }, _) {73 5 ^3 N$ Z N8 @; a: [+ W! P74( O. q" ?' ]" _1 d* C
75 6 S" \0 ]( N- d1 [/ `76 2 \! ]6 R+ }6 s" }77 9 i7 \% j/ J0 b! h' e781 J! c$ e4 `- o! v2 p. B- t
79 / a4 i% t8 O) Y2 P' Z7 v/ w5 B807 E( a. m+ G. l2 N8 c
81( N* `3 x4 M. n
82 ! c: [5 v7 d2 H) T, O% U83 W6 K* L# }& k& }+ e9 }
84/ E V* K* j4 l2 D, Z
85 , T; o5 S4 A3 N7 M' Z+ k r/ A- }! T869 }/ F2 I0 o! |% i/ x0 P$ q5 @. d
87 , f" f; j4 m. K88 . @8 @8 b# K- E0 E89 3 t% ]$ O* F* e# h1 R/ Y90/ {1 {# i: U4 o1 l E( L8 W* |, Y. k
91 % F; R. t0 \$ L+ Z92" B/ L( w4 h9 D
93$ f5 W, ]$ \4 M$ j9 R" w' a
94 7 K% K8 v$ c" U4 t5 l5 K95/ S+ y$ w5 Z6 a$ y/ Z
96 0 u( e/ b; d0 S F1 t* |97" @+ Z- \4 r; {, k- k
98 & y( j# d. m0 U s6 j99 7 \- ^/ \( {* U- W; L& d" I; p7 ]100 0 G& K3 k/ ^" \. r7 R5 L6 A101) p, [! ^! Q! k# l
1028 w6 ?. C% i. n9 I- l- _* Y
103 $ K) _- \: i, Z4 O) Q1047 R3 \: l$ ~. I9 C: M- q+ r# |
105 . W0 l) Q& d) I; E/ v2 @0 h. \106 ; E' J6 t4 J6 l: Q107( u/ X, \, W$ n: Q
108$ j, I4 A+ v4 H) z7 ]
109 ; ~; }% V# \6 A5 x110 # v! F; y) I4 b1 U" w; F111. P, @! U' O/ H, P, e/ s
112 2 s* J* r5 U I2 \: J+ \113 - \0 n$ b s) ?/ D% j# f114) Z; f; e% Q3 ^, y4 @
115; d* ^! d- l- Y; L
116 - m2 x# ~: Q( i( l, R' ~& J$ h- z2 l1178 t3 m( l, \0 i; D: e& N
118; Z& s* X1 u* P1 c; J) `% t. A
119 . d5 k7 l+ z' s" B/ ^( E3 |6 O' l1203 t3 @% T1 x0 S
121 " q$ l' r: n5 s/ ]# ?! l% s122) W, E) r/ X9 p: Y4 v- h+ q/ h! V: L
123; L5 X) Q8 _( f
124( Y+ G8 f/ Y. j
125 * W {* v- |% p1263 @6 J* }$ J2 O
127$ Z' B, Z/ [ U% D5 i) e
1280 y9 R( I! Q8 x& x1 p
129 9 J5 x9 W8 S4 K8 y/ g7 g1304 J- t3 {% A f; e
131+ J( C2 i7 z. G$ n* Y8 h/ Y& f
132 , {. O6 t& k# S& b! U+ m3 {) z133 : S: _( W8 n: t& i, o: o134; |8 Q4 N) J/ J
135( v: a' n a. ^. q" J! Z
136, P2 p5 G9 z' l1 s, m( m
1379 N4 F4 N" n! O* l
138 # }* R& k' P$ q/ ~ i% L# y139 * J5 N7 ]3 s- V( G& z W140 2 s* q+ A- o3 P! H' n9 {141 . Y5 ^' A X* Q0 d% S142 $ }8 r! H) H6 ?7 w6 M, C143 9 e7 I' @7 Q& P; F" N144# q r) t. \& k% Q* Z0 ^
145 x' q% F- F! }. _- u! e& V146: j5 t+ F6 y* a" \& H
147 1 D0 `% V0 o& e& k148 9 B1 t& B4 e$ J: ^4 T9 s1495 R, x) j9 [8 i7 q0 o4 n6 R
150 8 ]$ i5 t9 u Q151# x+ A7 I0 A1 ^- X& P" o
152 $ _0 m) w4 p, P- t153- o6 Z8 |2 N" b; F3 e: ]
154# a. j' K$ \# A; d3 J9 Q9 x
155" |) c6 c) G K! k( U
1567 L: n5 Q' k7 I% ?2 ]* j& C5 v
输出如下:- p' Q+ [/ K7 b2 U# H2 J