$ q9 T ]# Q/ f) @1 l- \3 C3 \0 f具体的安装查看Github教程:https://github.com/wkentaro/labelme/#installation $ L; S4 E P Z$ F8 u) H% L: K ( @4 g# S. n1 B4 t+ H2 i5 R' x( z$ y, m4 D
在原作者的github下载源码:https://github.com/tzutalin/labelImg' A( C' t4 D9 J* }) s& `$ D3 h8 l
。解压名为labelImg-master的文件夹,进入当前目录的命令行窗口,输入如下语句依次打开软件。- w3 h" b3 R( _# P7 Y/ a% w$ \
- y3 V7 E- \2 P) n# D0 F7 y $ _" b# h9 v: h7 j3 ?$ C; Gpython labelImg.py$ @2 C4 n* c+ a
1 , g; p" Q! [9 `+ h" s! G 5 m, ~% b( |4 J" ^- n4 P2 k M, g3 V; _0 Z3 S5 R
- L8 f' P8 {7 e, D) w$ c
; s. \' ]. _) ?
具体使用( L) ^& M7 h* @+ G
修改默认的XML文件保存位置,使用快捷键“Ctrl+R”,更改为自定义位置,这里的路径一定不能包含中文,否则不会保存。 " f' r( h$ S. k" g 7 W* r* _* H3 L0 U8 u7 Y- ?- d4 l* r8 Y8 m. y$ s
使用notepad++打开源文件夹中的data/predefined_classes.txt,修改默认分类,如person、car、motorcycle这三个分类。% R& ?+ g- `' \
- m+ J, P0 \1 g9 Y. S
" W$ N) { ~* K; t: g“打开目录”打开图片文件夹,选择第一张图片开始标注,用“创建矩形框”或“Ctrl+N”启动框,点击结束框,双击选择类别。完成一张图片点击“保存”保存后,XML文件已经保存到本地了。单击“下一张图片”转到下一张图片。 6 [; T8 v* W k5 n4 h3 u & { P: f v. c* V # E6 E+ a' j# m. i7 n; m贴标过程可以随时返回修改,保存的文件会覆盖上一个。/ ]5 X& E# V) A/ S' I# c9 b
1 r4 A- B' m, [' Q: { 4 z. p( Q/ T- o+ h/ A9 ]完成注解后,打开XML文件,发现和PASCAL VOC格式一样。: P" i* g) a# B7 v2 L) C. T: M) \( }0 i
2 I: q5 U N/ n: Z
" S* d/ r0 o; e$ x; N: [* T
将xml文件提取图像信息) V8 l- f7 q$ h, T/ g/ F
下面列举如何将xml文件提取图像信息,图片保存到image文件夹,xml保存标注内容。图片和标注的文件名字一样的。5 S7 T# D: f Y& J! [
6 `6 E! ?, u) u* n% L2 I. H
' J& P. Y7 b; x% o- H下面是images图片中的一个。 h/ {6 T6 a. P2 k( h; F8 P# `3 J$ n7 d [% d0 Q
8 U6 Y% o- b3 e( a' K- W
下面是对应的xml文件。 * g1 E, ]3 U; F" J; O, M $ H( R3 C5 ^2 l5 ^/ i: u& c" V3 Q6 |5 |+ ^, f4 H! s/ K
<annotation> 5 I# B0 r/ M7 u: a$ F* Z <folder>train</folder>9 [" B$ O1 |- ]$ r4 e. v3 p
<filename>apple_30.jpg</filename>! R* n$ A3 |7 w6 x
<path>C:\tensorflow1\models\research\object_detection\images\train\apple_30.jpg</path>. {# ^) v- u& g+ r8 S) z& M/ @7 O
<source> % y" o3 H+ [; \7 S9 U <database>Unknown</database> ; C% T8 L" `3 W/ F; D' n( z </source>( [! t* y5 ~+ v0 A, p% v" {
<size> 0 s! j. f+ T7 v6 r6 D <width>800</width> 4 b e( a: |2 \2 o- a <height>800</height> : D4 z. R0 }4 C/ {5 z9 v5 m5 g. S <depth>3</depth>6 s# G* C" Y* w; f$ ^. n
</size> ; C8 l" ]! _1 d7 k7 k <segmented>0</segmented>% [: q, Y% N% o4 Y
<object> 9 E1 {! N4 ~. i) R' I8 t' y" v1 `" Q <name>apple</name>0 _( B. f0 C# J2 r! }+ s
<pose>Unspecified</pose>- w9 H3 N9 h( [' [2 W9 o* r" q( K
<truncated>0</truncated>: A& H! e, {, i8 Y1 G
<difficult>0</difficult>5 O- i0 X8 b! h" m2 `
<bndbox>4 ?9 p- [5 R* I0 i: f- P
<xmin>254</xmin># [9 a8 }7 V9 v$ E+ R
<ymin>163</ymin>& B/ o7 }* G6 |) G4 W" q
<xmax>582</xmax> 2 z7 ?$ _ V+ {4 W R" A1 s! u' M <ymax>487</ymax> # \+ Q* W z9 A; R </bndbox> - r# v$ i0 k0 i+ s+ E& ] w </object>- z g5 T4 F+ A& Y I( @
<object> ; _9 d) y8 c1 _9 p0 x <name>apple</name>7 V% C# }4 m. B$ d
<pose>Unspecified</pose> 8 C* n4 }# k. Q, F! E4 y1 Q <truncated>0</truncated> ' Q. C# ~- {0 _; l. \ <difficult>0</difficult> x) R: [+ \2 A <bndbox> ; C: `: A3 d3 f) W( I <xmin>217</xmin>! I$ b2 g% f& ~! j4 d/ l& G( k) h( J
<ymin>448</ymin>' t( N- b+ C. a! b& j: Q
<xmax>535</xmax> 3 Q# s/ w/ b8 M" s$ n7 k! u: V <ymax>713</ymax>) c. |# F; v8 s. ?9 R, ]" e
</bndbox> ) ]6 W: o% b" E# s8 V$ @$ m* t1 H+ C </object># T) p# O# Y' N5 I6 [
<object> " G" y: F6 A$ _5 Z' V <name>apple</name>4 L0 M& ]8 f" V/ I' x
<pose>Unspecified</pose> & [9 x3 A7 c( |- C( H7 R <truncated>1</truncated>* X( D3 G8 ^- ]
<difficult>0</difficult> ! Q; A1 ?- X) _! Q6 E' q <bndbox>3 N4 [( I; r. G$ Y5 i( H3 m
<xmin>603</xmin>/ D8 K8 }5 m9 ^
<ymin>470</ymin>4 O3 z+ ^( _" D. r0 L* m
<xmax>800</xmax> 8 r" f* {6 j) W <ymax>716</ymax>+ c& {7 n$ R: S0 [
</bndbox>) o; @8 T" a: R5 P6 Z
</object>. N; Y( \2 G) w* a) d
<object>/ x4 P3 u+ Q" F- k9 E* K+ i
<name>apple</name> 0 X* ~0 Z1 k. L6 ]( m <pose>Unspecified</pose> $ W( @2 y; I4 {6 e; G6 F, s <truncated>0</truncated>+ A! n9 t$ ^8 q6 {
<difficult>0</difficult>6 ~ J# Q R- ?
<bndbox> 6 E7 J8 t& h% K$ u" t9 T8 N( H <xmin>468</xmin>+ B7 W* O; x; o* H1 \
<ymin>179</ymin>: \+ m3 Z. T) P- y
<xmax>727</xmax> 2 I0 v9 G: ]5 z |8 R. H, b" U <ymax>467</ymax>3 F: R" b9 U2 G) d- }
</bndbox> 1 J: p! ~ S9 [& q, n </object> B7 C) f( A& g7 b* D$ |" @: |
<object> 4 |9 q3 m f3 z, V* ? <name>apple</name> ' y; J _9 n3 y7 \, j <pose>Unspecified</pose> + C: u( h' d+ k <truncated>1</truncated>. J# i0 I* F) _! x$ X" O c
<difficult>0</difficult> 8 y5 M8 s' q* \# a <bndbox> 8 i6 \; e6 G n+ B7 L <xmin>1</xmin> . B6 x4 z3 G0 j" I2 o <ymin>63</ymin> * }3 E$ n6 I( F! Y, T1 z <xmax>308</xmax>* d8 I$ Z1 B3 Y* a: b- z
<ymax>414</ymax> $ ]5 \3 M2 A! G, ] </bndbox>! X. ]4 N9 q' n* J6 R
</object>& c. V* i$ K$ ?1 i
</annotation> ! q5 S8 w! P7 l5 w; f8 u; p15 t# _4 m6 L$ i
29 B7 D# l+ ~) V" C
3- n8 N) I3 v: l ?- ^: t
4 ' m! \0 w: }" A* a) I55 U! K# z' C; Z) w
6 . m) O* T3 r5 @7 H& h" c/ c1 P# o7 2 Q- g: `2 A7 w0 ]- N( H( g8' C# r5 t- A3 A% M5 d6 _( p
9+ x! T9 Q% Y) L) D
10; l$ h2 e2 _/ n- _) G& I
116 v; @+ G: y, U) }) z0 Z
123 h+ u! W8 e3 |& f7 Y0 B! H9 l
13 : V0 {; e# O( Q: K; V! v+ M, W14- R' N4 C# ?2 U4 F+ P r+ v
15 - Z8 f" x; t" \# f) J162 h$ _& l+ Q9 u( ?; F& ^9 m
17 - R5 {5 p* K6 T Q8 v( L& g% Z18 & a" E0 p4 P1 G' e4 x7 ^7 T& @3 M19. b0 ?3 r& ]0 I/ y7 o3 E' z% F
20 ; y) R9 V* N+ S5 j$ M" E3 a21# I8 O# r) j. A9 r" p) d7 _
22- q0 u' H7 X$ \! T) ~
23+ Q! U% x: x/ j
24 5 c' V8 m. D, j1 w1 ]; K' V25; `5 K* U2 K7 v, u; T0 _! T8 g
26. D4 ^' v3 U6 Z( ^+ _ f
27( @6 q; b- B' r& Y1 h
28 ) R% f) W! x7 k% l( L5 J. o/ `& r29 : `2 g+ A3 b! ]( Q9 L30# c5 t2 }8 `+ \
31" \' L* o: E8 L7 n/ P3 B
322 p7 u: m/ D9 r. c( N# T
33( @- x3 x! j4 B" W# B4 c. c
346 p6 X3 [9 s* E/ r% }
35 v4 X. o0 q% c6 W* g5 O
36 4 u* M5 Z8 n$ I1 p371 A8 G' q6 U& i
38) Z+ b5 H+ q$ t U& b1 x5 y' h/ I" s
39 0 j/ z# k/ w9 Q6 [1 l- S9 e40 1 l) o2 f4 N: m( F: _: c0 E41 * P1 q% t& z; U42 _" P- K. s d* H) E9 J437 |7 @) B; S: B0 D
44 7 ^9 s* T0 ~) `% J, T: d2 Y45: C6 D$ \- a7 u' F5 L
46/ g1 n8 m( u4 M7 y* L
47 ! G9 k8 D7 _- k0 g h48 " u2 I* Y$ E# Y( j1 c49 ' Z7 x, R6 l- n3 [506 {6 M; p# H9 g; i7 E3 w: X9 c
51% x' O, J6 ^: n1 F
52! ~7 R% m+ L. @! F3 _
53 + w9 g8 X) ^& g% d) \; Z: g54 ' }/ ~2 l0 s* Z* C9 U+ w) K6 K551 Z/ k5 H& ~+ j; N
56 5 M: A' U$ @) p, @, h7 z0 R# p57 J$ I$ A' e9 G/ _
58 9 b$ v2 Q" E; W l6 d; e59) k9 n" V$ h" c+ t
60 4 l2 h0 z' t V+ B4 U" l61) R: {6 P) i, C/ h" ]) n- J5 j! j
62 # b( f2 q4 r+ C0 |633 Y/ y: }* h& ^3 Y x2 a5 A$ b
64, J1 Q0 d' ~- \3 }. p
65% u' Z" w! n1 f. t
66) ]" {5 B6 m8 Y4 D
67 # s5 S. V/ I- E2 C683 w) e7 F% m+ v( b+ [- u; n
698 B: \: O4 v j' o
70- Q# [/ T8 }. W% p$ H) p' Z9 q& U
718 ^' N8 s" k. e8 r
72 + i* Z& y/ R6 J; v73 7 N4 c& T) w# o6 S, w7 Z: n74" y) w' I* {! R6 l: M5 \
将xml文件提取图像信息,主要使用xml和opencv,基于torch提取,代码比较凌乱。# H* F6 j8 T# Q( T& L! { N0 h% o: L
: L" \( d; b. v( @1 T1 c% Q4 C- v P' n2 Q, q B* z# N; g* b
import os) u3 J" R8 b/ _3 ` A2 R
import numpy as np 2 g8 N S9 ?) C2 }import cv2 0 l2 P( q! ^& }' gimport torch& s( m" k9 Z/ s" D3 l
import matplotlib.patches as patches " S( r7 ]* n8 |. y. K/ ]% d% [import albumentations as A 5 q6 `# Y3 _+ l; Hfrom albumentations.pytorch.transforms import ToTensorV2 ' [0 C( J, h1 H9 a' A4 Zfrom matplotlib import pyplot as plt * i* N4 c5 Z. ?! M! c# N% Vfrom torch.utils.data import Dataset 1 D K1 e& }2 D! e8 Ifrom xml.etree import ElementTree as et4 O6 v8 ?: {1 o, N5 d
from torchvision import transforms as torchtrans 9 T2 G) q& b$ k3 I: Y$ x1 z6 V % K9 ~4 j6 `: L$ R8 M4 I( y5 @3 _0 ~4 a8 L) R R5 T' S
# defining the files directory and testing directory ' V. w9 r6 C* F% {- Utrain_image_dir = 'train/train/image', `0 w$ }8 R( \! m/ ^* a* S
train_xml_dir = 'train/train/xml'$ q3 g' c" h# e% v
# test_image_dir = 'test/test/image' 2 V- X' ~5 K: b1 k, `: T2 @# test_xml_dir = 'test/test/xml'* q2 M" A, B) v. K0 K; @- y( L P
5 L' \0 `7 ~& f1 k8 ?. R" T % ]: j. x7 Q; i5 {class FruitImagesDataset(Dataset): & q6 R+ ~8 j: |, K# @; ]7 U, J$ O6 s Q* O, ]9 c3 V4 N$ ]& d
, E# I9 ~+ o3 l8 x def __init__(self, image_dir, xml_dir, width, height, transforms=None): 7 F8 m0 |' @5 `) W/ t0 X self.transforms = transforms - I/ c$ N4 z6 r r7 N: A' T self.image_dir = image_dir7 X4 k x/ V1 _
self.xml_dir = xml_dir% d# v; j c5 X6 c- r% D! f
self.height = height 5 l9 I! U. Q# \ self.width = width' L, g: k: d( @. w7 g0 C
/ I% c) d/ |# x8 Z. E Q# `8 y3 I" q* S# D8 W3 E' H
# sorting the images for consistency- F/ I! D8 H6 G
# To get images, the extension of the filename is checked to be jpg ( b' b3 O" Z( T8 i self.imgs = [image for image in os.listdir(self.image_dir) 5 d' b u- M4 S; _ if image[-4:] == '.jpg'] 4 \( s+ m5 ~6 r+ R; ]- y! P# P self.xmls = [xml for xml in os.listdir(self.xml_dir)' {2 y* b# X7 S$ y5 g
if xml[-4:] == '.xml']7 F/ |6 N" U' F# K2 G$ k: h
$ X& N" q# F4 b @% I2 i7 ^7 i! h6 o : y4 Z- D- m k) p3 H # classes: 0 index is reserved for background : q' ^7 H+ z' ~% Y3 [7 b9 q self.classes = ['apple', 'banana', 'orange'] $ x2 N5 X) F$ l5 t0 o: j- m1 k4 m- K6 R6 P
1 d- C1 ?) h7 ?+ ?+ M
def __getitem__(self, idx):3 U7 Q D" \: ?: l& o" ^
% w) B" P5 ~9 T0 e3 e! F; A
" u& j& r) s9 P( W$ k img_name = self.imgs[idx]7 ^; C- C& @2 q- q/ H! W
image_path = os.path.join(self.image_dir, img_name)4 \6 [. H$ B1 @! U. e) V, o* O' z
: U) K* ~8 G A% R% g, }8 J 5 H, r2 R# B( X+ k# ?) I # reading the images and converting them to correct size and color$ F+ ~" q. h7 L4 A! C3 F9 P; j+ d
img = cv2.imread(image_path) : ~0 A7 Q7 S; U8 @ img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB).astype(np.float32)" B+ n" H+ x( C. L' ~
img_res = cv2.resize(img_rgb, (self.width, self.height), cv2.INTER_AREA) ( r6 P9 [* f; B' Q$ {0 t5 K # diving by 255( R- G$ g& R) N# l+ X
img_res /= 255.0 " \/ b: `4 j. Y) J$ o% p c$ i; h0 w1 O# ?- @, y2 n; w
. H2 S% B5 F( e( R% O( E$ L # annotation file 6 a2 R' N/ `6 c* a2 P2 a7 N annot_filename = img_name[:-4] + '.xml' ) R2 r" [& i: ^- ^$ M annot_file_path = os.path.join(self.xml_dir, annot_filename)* M6 c; a, |- H5 f
4 }: ]. C& \( D5 x: p* R 6 A: n5 t$ |8 [0 V4 Q: K' f2 t boxes = [] 2 A% n; c3 h8 o labels = [] 5 r# l/ T/ S4 |& g! v tree = et.parse(annot_file_path)# ]4 m- C; r5 C1 l+ l/ w* V
root = tree.getroot()4 o- T; u% A; L% B; V; l; j
+ }7 K* ^ E V& w0 e! G" k( \
6 `+ r. q2 m- `2 d9 M F) G
# cv2 image gives size as height x width ; S0 ?8 M: X5 H# |9 o/ P, K wt = img.shape[1] 3 w# Y( C8 G$ J" [) o1 g ht = img.shape[0]% \* T2 g) V7 R7 _9 n- N S7 e
& U; s: z- t; a- S/ k0 Y 6 g4 P9 B! O" L# ? # box coordinates for xml files are extracted and corrected for image size given 9 h/ D: i e6 G4 } for member in root.findall('object'):( }2 c8 Y4 E5 M- ]; A2 s6 e
labels.append(self.classes.index(member.find('name').text))/ |+ j5 F" D; ]
$ f% t# p" Y2 p2 u 8 v( y& N! `! {4 n2 ~- v" {% h # bounding box ( B v4 o+ T9 T& L3 b xmin = int(member.find('bndbox').find('xmin').text)" C3 I7 a& K4 C M* U* P
xmax = int(member.find('bndbox').find('xmax').text)8 D8 Z& [, |5 V& T. h' b