- e$ }4 ?0 n' u" @0 y ; R% O, O" p% y/ ]8 i+ c将xml文件提取图像信息: e7 p' R/ t8 a. \- q' r
下面列举如何将xml文件提取图像信息,图片保存到image文件夹,xml保存标注内容。图片和标注的文件名字一样的。+ V) v% G* J% ?9 @) } _" H d
4 F/ R6 d% t7 g1 v% X) [
! V' G0 l$ R$ }! I& @ ! M, b2 ^( U1 W8 Y% R5 L 0 r& M' }0 r- w1 w8 X下面是images图片中的一个。 $ [0 G' x# Y4 `* \4 n' a ! J1 X, e1 e r4 P3 O; `6 | ! R+ K% G2 ~ ^下面是对应的xml文件。1 B1 a/ x' J' H- U: o
( H. u( Z( H& V6 ~
9 u7 z9 A3 h3 ?+ R1 K1 q
<annotation>0 m! a+ C& `4 z+ ~+ z, A) p7 a
<folder>train</folder>$ S1 ^/ {+ z. u) ?# Q S
<filename>apple_30.jpg</filename> ) T y9 ?6 J( M <path>C:\tensorflow1\models\research\object_detection\images\train\apple_30.jpg</path> # K: L) T- c3 K. ~ T8 c <source>% n; x/ C9 V N5 [3 X2 K
<database>Unknown</database> + h0 s' s9 C9 m, l9 l% Q </source>, z' l4 c, ]3 c1 a: G
<size>2 S u5 ~" a+ D
<width>800</width>; T% y- ?* m0 G i- s/ l3 ~
<height>800</height>/ _( f2 A* c* O" P/ j
<depth>3</depth>2 ^ [( S) _! w$ i4 T& [% H; M
</size># a" f) z. T* X+ a
<segmented>0</segmented> 5 F5 E1 }1 q/ _4 a* V9 L <object> % ~& w' d/ N3 o4 p7 ?- I# ]+ Y5 I4 U) L <name>apple</name> . f% Y9 b0 p; |5 d( ?: P& q, S& T <pose>Unspecified</pose> - j- K3 I o0 I8 F! J <truncated>0</truncated> 7 V2 V8 Q' m/ p! g2 z <difficult>0</difficult> f% y* U0 p2 I- x U2 L
<bndbox>& J5 q, ~, t' l: F! Q. J7 Y
<xmin>254</xmin> 2 m; h( C7 o# f$ S, f <ymin>163</ymin>) z, |9 r1 l V& k
<xmax>582</xmax> 8 m$ \4 d) i3 P <ymax>487</ymax> 2 E; K, O; a6 ~: O </bndbox> 1 Q# ]; z* N' z; r </object>" a% \2 _: ?' r: B2 d ]
<object>* {+ h! l; ~0 T0 W O" r4 ]
<name>apple</name> % O5 P# i7 h2 }" {* y: w# q <pose>Unspecified</pose> " p# C# X8 M+ E( U9 A* h3 F! Q <truncated>0</truncated> ( i( ~- O! ]* b6 |8 E1 u; v& B <difficult>0</difficult> H! Z2 Z1 e/ t" @ <bndbox> G: w. G9 J% t7 ]* v <xmin>217</xmin> 9 c6 q' e; g! x/ k4 g+ T7 Y9 r& P <ymin>448</ymin> ! U, L/ n( i5 D( v% J <xmax>535</xmax> 5 d+ {4 P! O0 ^6 f) k <ymax>713</ymax>& O# ?" x/ s$ [! @( y
</bndbox> 1 n q3 k" V$ r </object> 7 J0 [& k- X: K9 \% U0 X <object> 6 j% H1 W; g' n <name>apple</name>9 r n/ B0 h% q( ~& ?+ R' f' M4 F- |2 h
<pose>Unspecified</pose>2 K. F9 `5 T: o0 L) V: D0 M8 M
<truncated>1</truncated>" Y) o2 a& f( x: p; ^
<difficult>0</difficult> + f$ m7 F! ^% L <bndbox>6 W# P. _. {7 V$ z5 h, M
<xmin>603</xmin> ; ]6 c/ X8 A! E8 }! y" g! b9 g3 ~ <ymin>470</ymin> / S$ t! V3 D5 H: k6 L <xmax>800</xmax>1 L7 v3 F9 s- |; z7 ~
<ymax>716</ymax># Y5 n) o6 X/ d- _2 T
</bndbox> M/ g( \% D4 T& l. ^3 } </object> 6 m2 O9 M5 _' `5 i3 z) c <object>% Z" B9 d- H- @* r
<name>apple</name># x$ }/ z) i/ \% r, a% f2 ~
<pose>Unspecified</pose>; |* f# J7 O! [# z5 v6 D
<truncated>0</truncated> ! k+ X# K5 l( S% x/ B4 c <difficult>0</difficult> + j5 I( V, ]* a; t6 D; ^0 N @; [ <bndbox> $ Y! Y: v8 a9 A; C$ o) R5 O L <xmin>468</xmin> 3 S) M9 ^) e' Y+ K! B) X9 D <ymin>179</ymin> 7 c9 S2 \, e# W$ c/ G6 I: [ <xmax>727</xmax>! V0 S1 y+ l5 g5 r
<ymax>467</ymax> $ c9 a( S4 ~4 ^! @ j3 b/ L </bndbox> ) M, N, x2 l6 X* m </object>) e5 X+ ^+ |4 j9 T
<object>- q4 {1 Y. `6 _; ^- O& I9 P
<name>apple</name> $ w- B. M/ A* U4 p. {3 D <pose>Unspecified</pose>) X# M! ?& K Z2 S& d
<truncated>1</truncated>9 Q8 s3 O2 \* x- {7 `# }1 R
<difficult>0</difficult> 0 n1 G! F" b+ e1 P$ e8 O8 l <bndbox> 6 F2 L* u0 z. T: A1 ^ <xmin>1</xmin> ; m5 Z* {' ?# K8 I- o <ymin>63</ymin>: \+ ?1 \5 D: O4 j$ z
<xmax>308</xmax>% S1 ]/ z+ i9 h3 e- Q
<ymax>414</ymax> 8 E0 Z, S9 \3 A3 T5 J+ g </bndbox> 6 s- J1 z% l! u5 m) ? </object>0 ^: E' X* w9 Z& Z2 h$ E
</annotation> 3 |5 h; g6 z' s( H10 I' V6 G# f( f# ]( |
2 % x) f: E9 `' Y4 I3 X, P m3 % ?$ q$ E! _7 X* W$ R8 f4 # G6 A0 O9 m- Z; F; ^7 g( B5 ) {3 x# H1 @! e: b+ X! r6 \67 M$ _- a: ~9 \
7 : q( F3 U# m& L- j8 T8 ( D2 N2 J% f+ `% f P9 & {0 p7 m- [3 C: R10 ; U. g5 U* X3 L' b- V' U11. C5 u/ G. H7 S- [/ \: S! Q
12 : A" U3 f4 t9 Y) l* _, B7 L13 ! p) m- W: n2 D4 h/ p14 $ L7 {* P0 O' K# {! J158 f7 U2 `5 ?% m8 h) h, v P
16 ) K+ T% v, R" R3 `! @' J17 / e( n1 s! Q$ i4 s ^+ k18 V" D& c0 W! d1 y4 M3 Z! Y9 y
19 : t3 t* c6 S* v I3 m20 7 q$ F, p4 B8 V# e, v% b21 6 W: F% _& F$ P$ o22 & V( I/ `# R! [23 7 s' ]1 \5 P9 u: ], O9 p24 0 G* U. I2 y! g! J/ t9 D251 |1 i# L- t. M
26 ( |; [( j* p% U% I+ M27 9 u" |( T/ Z1 V: w# c9 s28 & h: i! u# r1 w7 h! @" ^29 # n9 I8 _) p" g7 R: L1 S1 S30 9 W4 m. b4 b3 O" G: T3 h31% e4 C0 [. M% ^7 |3 ?9 }! d5 {7 B( [
32 0 `9 C% d5 w- } H33: ~7 w1 r7 N0 _$ b* P
34 ; g( v8 E& @5 s1 f2 w8 {/ m( i35 - Y2 a( I+ o- J& w36; _5 f/ p" a+ g$ _% f
37 ' T) x7 E# v. {6 t% I38 9 l% }$ m# h) }/ n$ f' ^4 y. ^39% |! ~- `/ T2 E- o/ I3 I: q7 c
40- l) H" T5 k# ]" x7 Z
41 ! \! M' X+ }, K, `2 O* D429 ]$ ^5 a8 H7 o! @" S3 i
43 3 c; O' }7 M9 e7 v44. y5 }$ d% h8 `' |& Y% T6 j
45 & v: G: j! O7 r' l3 I; V/ y, l46' L: N' F8 d- L7 w" \
479 c$ U$ b; J/ F2 R) t
48 ; h# }& e% L+ q9 P' h/ i. ^49/ y! R2 M9 G: ^. R4 o* l) R# `7 q
50 # q9 \) w J6 e, R9 z$ r* c L0 b, w51! C7 p+ f9 T* I
52 ( r2 v8 u! S% r- L4 y) t53- w& Q* {# n3 Z5 j/ g" X9 @# N$ n
54, {+ ], T( a) R, V
55 p! R/ c. R7 R* N. i! v# _
56 ) ?: f! N* j# W. ~0 G. a! p( V# p57 7 _4 X- L; E/ b* n9 ?6 T584 j! ^3 K& d4 u( x5 t7 [
59: M$ @) _5 K! G+ t6 j% J; K
60$ \) w; X5 o1 z! d$ q
617 R1 U# h, O! [0 o( N
62) x9 O0 P( w U: ~
63 + L) b# w9 `9 D0 i64 . j# T0 Z$ t( n% c9 z656 [. D- n) p9 N I- z
66 s8 N6 e9 w1 A) C, @67 6 g7 z8 D+ Z$ Y2 G* r/ c! U" O68 ( r: L' D1 ` v/ M+ ]4 [) \69 : L) R2 ?( r4 x2 U: e6 Q70- H+ v* \+ t; L8 |3 L
715 C: K2 Q! ?/ p# U1 }
72 + C: k. x1 s$ I4 ^6 P73 , H6 d- T# O7 o1 i74; h% Y" Y! T* s' I
将xml文件提取图像信息,主要使用xml和opencv,基于torch提取,代码比较凌乱。, m4 i4 l' ~$ C$ r f; j0 f! j
" j2 H1 p* b9 X, y$ M# K5 L5 B* e; p3 ^
import os ! S3 k3 h- z3 i1 A4 {0 _8 F8 Yimport numpy as np/ ]9 `$ k+ b% z1 I& k: w% L
import cv2 & B. k9 R% M$ `& T5 t" ?& {( V" mimport torch7 l; {- j* Q( I( ~% a( {+ u
import matplotlib.patches as patches 2 S$ a0 D" k" X& h k1 M5 Gimport albumentations as A n/ o" Y# q, D2 j' \
from albumentations.pytorch.transforms import ToTensorV2' f" I% E7 g6 u" ~/ x, Y9 [
from matplotlib import pyplot as plt . {+ t/ L" a8 U; n5 ffrom torch.utils.data import Dataset! i$ \; X% b# N$ P6 Z2 ^; T# f; }
from xml.etree import ElementTree as et 3 Z5 D. F% F) _# P- C' v3 Kfrom torchvision import transforms as torchtrans 4 I. j9 H7 P6 f( a% T6 ^' g$ B1 f: I" D& ^. Y0 X
5 K) X; ^$ y' x1 [, ]$ [9 }
# defining the files directory and testing directory # ^6 K5 H7 i! e X0 }train_image_dir = 'train/train/image': _) V' c( B) l$ H9 r' R4 q
train_xml_dir = 'train/train/xml' 7 U' X) S; W. G% Z. j& D, q/ g# test_image_dir = 'test/test/image'+ |6 h' Z; D! \: `5 k
# test_xml_dir = 'test/test/xml' 7 o' O' h$ y3 v+ v# W4 r, W4 W5 g. X$ g+ z9 g: n
7 e7 h2 o! V$ A7 }
class FruitImagesDataset(Dataset):/ s: e. T; Z0 A7 q ~# k/ P
. o# y& x! i3 n
. m! [4 _) h h/ N, q" C
def __init__(self, image_dir, xml_dir, width, height, transforms=None):9 D6 j e8 m- d; v
self.transforms = transforms / R: R5 @: E. Z( O. r self.image_dir = image_dir 6 c$ ~5 M# ~& ^5 u l self.xml_dir = xml_dir/ \! G5 \4 g8 N4 v
self.height = height ; u3 z2 C2 N7 _' P2 ]4 W self.width = width ( W- h( Y2 Y5 v+ y, ?0 J4 C3 W1 i _' B
) D) M' @. t1 [2 L n: U # sorting the images for consistency' r6 M; z0 b1 o& I" c
# To get images, the extension of the filename is checked to be jpg ) M: p* e5 c, p' c$ t: _ self.imgs = [image for image in os.listdir(self.image_dir) 9 k S4 C( e: j8 K1 f' p if image[-4:] == '.jpg'] / i2 A% Z9 h6 \2 a/ J. C! U self.xmls = [xml for xml in os.listdir(self.xml_dir) 1 K" U0 ?4 ?& m2 ?2 {# ?; E if xml[-4:] == '.xml'] $ w9 `. z: R* X 1 C( I5 ^9 \$ e5 p" O+ D1 e" w0 o, ~% v
# classes: 0 index is reserved for background* `' {0 x; N7 `4 x7 g7 \
self.classes = ['apple', 'banana', 'orange'] 4 N( Q% v9 ^) d5 j1 { 7 d: [' n; P0 K8 B: k ! ], t4 L8 G" ~; G) X& O6 @ def __getitem__(self, idx):5 H4 I; E1 D2 M0 A, p
% x# R+ _$ f8 j4 t0 r9 W, P
( [- d! b, |3 ^( E6 @" V img_name = self.imgs[idx] $ B4 N( a. |) e0 v- P image_path = os.path.join(self.image_dir, img_name)1 m9 `, y& v7 P
: @( i6 D; I3 m) |* Q" J- W0 z+ m6 F
# reading the images and converting them to correct size and color ' d: j" B# I$ x1 Z& j E" v( R img = cv2.imread(image_path) : y, i6 ^3 w+ I; p3 f; @3 X img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB).astype(np.float32)4 V& W4 B8 O3 m; E9 L
img_res = cv2.resize(img_rgb, (self.width, self.height), cv2.INTER_AREA) / H' m/ @* Q9 }3 q # diving by 2552 Z+ K7 E" s* A' u% W
img_res /= 255.0 ( k" K+ D4 o+ O ! L6 i; f" [8 k) L" p 8 E$ {2 p4 I5 H # annotation file , g( B5 m1 w$ N$ P+ { annot_filename = img_name[:-4] + '.xml' ( }. x9 F! d! x" d! _5 o4 S- C annot_file_path = os.path.join(self.xml_dir, annot_filename) 5 `1 M5 d# D% Y" w0 h, b6 h " ?! `$ @! [+ Y : C# R$ l+ H3 b boxes = []6 E( V/ K" H) ^1 B8 w
labels = [] " I ?1 A! M6 z# A tree = et.parse(annot_file_path)% O, W* g, [" f. m6 t- \% G. d" t
root = tree.getroot()' Q2 e& d6 b1 Z9 d) ^
. u, g" F$ B; @2 `# b- U1 i5 P
/ m: P. j3 Z" D5 G5 B7 S
# cv2 image gives size as height x width , i4 r6 L" y% n& z; X wt = img.shape[1] % G0 G. ^# M8 `' T$ C2 k ht = img.shape[0]- n; }1 }9 {; F* ^4 y: |( a' C
4 x# F! }+ [3 ^+ l8 e( p! x3 C' L ) T% N. w: H) C5 ?5 ^% g! G; U" R # box coordinates for xml files are extracted and corrected for image size given 3 y# Q L+ y5 b4 F for member in root.findall('object'):# [( D( g S& K* U- ^) a+ F# N+ T
labels.append(self.classes.index(member.find('name').text)) 1 h& ?6 f X7 H4 G! f" O7 m; V" X0 k. l G! U& B1 B/ a
# ?# s0 A6 W' d9 g. j1 X0 ]/ j # bounding box " |+ D$ E% P8 ?7 r" C8 g# f' b; l5 M1 R xmin = int(member.find('bndbox').find('xmin').text)+ k1 k* l: o, L# w L
xmax = int(member.find('bndbox').find('xmax').text) ) E0 e$ ]/ u: r - V/ i: H2 ?+ M# i- s 7 m" u" U! E% p! r; x# @ ymin = int(member.find('bndbox').find('ymin').text)5 c; q3 ]9 a: q, P" L
ymax = int(member.find('bndbox').find('ymax').text)7 V# f( w0 D. r; F) B8 U
J4 j0 X. U( g7 d: _ x4 |, v$ {7 H
, N7 B7 A6 G* G" e4 G Y4 h" i xmin_corr = (xmin / wt) * self.width % z$ n# I) {- Q6 R' W( c) c xmax_corr = (xmax / wt) * self.width( x, f8 z4 m5 u5 F# l
ymin_corr = (ymin / ht) * self.height 5 b0 S. A7 O `% _. \/ A ymax_corr = (ymax / ht) * self.height& s) x) X" \$ Q- J# B. Z* g) ^
boxes.append([xmin_corr, ymin_corr, xmax_corr, ymax_corr]) ( z! |6 h; ]5 m. }' R3 {1 @ , P1 R! P$ Q( x8 ^5 D 8 h1 j- E6 C' m7 }( h; c( ?* P # convert boxes into a torch.Tensor* X! e4 D: D- A4 }* ~
boxes = torch.as_tensor(boxes, dtype=torch.float32)9 [7 |( [9 e) `6 z) w# q
3 J4 [* ]( n5 |+ w9 f$ L
" t3 p* _* X+ g9 \3 v/ ]8 h # getting the areas of the boxes * ^" e6 i; O7 }7 L e q: m area = (boxes[:, 3] - boxes[:, 1]) * (boxes[:, 2] - boxes[:, 0]) 7 J9 D( |$ `/ Z0 V* u: h- S. y7 G d' x E) |2 W5 F9 ?) ~; I* e7 _+ F& _, S9 q V' S# v% M# R
# suppose all instances are not crowd 3 g/ J A/ e! O iscrowd = torch.zeros((boxes.shape[0],), dtype=torch.int64)2 f; Z' [; B6 N
' g! ?: x. }" S, R8 ? i
+ u0 Q1 F0 i/ c; w" k" P5 |
labels = torch.as_tensor(labels, dtype=torch.int64)8 o9 {( m* }8 E2 ~; C
- i! @! m/ F8 _8 Z: ~% M* Z T. |' O$ }4 v, }
target = {}0 [1 u Z5 C' I5 ~
target["boxes"] = boxes + q: k5 B, E5 F; ]) }) k9 ^ target["labels"] = labels $ s3 i+ Z! j, N8 X e target["area"] = area + {3 W, W. T F5 F target["iscrowd"] = iscrowd- V+ X9 ]" Q1 p" p
# image_id * a& q' E0 Y. W7 i" B$ o image_id = torch.tensor([idx]) 1 P! w* P/ k/ h$ h0 a- V target["image_id"] = image_id & S, z; [ D; b0 K* X - D c, z( c, x9 p+ _; \; M7 W3 o " s" x L& A/ t1 P' r! v0 O if self.transforms:: l6 |" I8 o5 J, C$ o
sample = self.transforms(image=img_res, 2 J5 S* N" N- }2 G+ R5 T bboxes=target['boxes'],( Z5 N/ [# d- @, A c! @! S! J
labels=labels)7 U3 d+ J6 h5 n4 Q% y: _7 r% X
9 S/ w" b7 T% q( C
+ X# D# u2 l) W- r
img_res = sample['image'] 0 i! B$ J0 S1 b target['boxes'] = torch.Tensor(sample['bboxes']) - _) z) h3 s# K6 \5 \) {5 C" e$ }, j( T7 W