3 e) N7 x' ?: [% `8 Y<annotation> / p7 d: l( m) D' E6 u <folder>train</folder> ! `3 s" r* ]1 _. q' _ <filename>apple_30.jpg</filename>- r& R/ C3 W% S- J
<path>C:\tensorflow1\models\research\object_detection\images\train\apple_30.jpg</path>; t2 f4 I+ J0 e: J3 P' M3 J
<source> / h1 w( ~# ]# D, U2 ]/ t6 f <database>Unknown</database>. G/ t- _9 M/ |0 ~+ H \* ^% Z
</source> % R( v+ d, o' m( j <size>4 |1 @* S% P! F
<width>800</width>; o( o$ r9 j4 n( D( u
<height>800</height> ; n9 D: b! R' ? <depth>3</depth> \4 \ Y0 ]) R0 w( ^9 ^- t5 k) X5 d </size> , I/ c4 d$ s2 k6 w9 X! ]4 j <segmented>0</segmented>( M( Y! e, _: J, f
<object> 8 E# r/ w5 t$ e( `: |9 q3 j <name>apple</name> 4 v7 ]7 ]. W* [: ?4 \8 _ <pose>Unspecified</pose>9 q3 K+ D9 r& @5 N8 G/ r8 r
<truncated>0</truncated> ]6 e/ [& {' f
<difficult>0</difficult>/ ^8 W5 c( H* Y- k/ \ I' d7 t
<bndbox>8 R f% w! L; x" S
<xmin>254</xmin> 0 o- _- a' z4 w5 Z6 z3 o <ymin>163</ymin> 5 o( v8 @% Y: M1 P& E0 u9 ` <xmax>582</xmax> & T; L; y) }5 r( G9 z7 Y$ n <ymax>487</ymax> ( P& |. ^% R% Z2 D* n& x, Z </bndbox> 4 g! h2 w- D7 Y* m r </object> & Z3 r5 J. l/ ~0 q" Y: K <object> k; k! f9 `/ U0 f# I8 S
<name>apple</name> + j7 v6 \" t' w. }6 e <pose>Unspecified</pose>0 n. b0 c7 G% B: q$ Q
<truncated>0</truncated> , y7 m0 q: D9 U <difficult>0</difficult> % j2 |# G! i, k/ t% E1 u. D" } <bndbox> ( T9 J9 H: k3 R: A <xmin>217</xmin>8 s" `5 C/ a. S: u1 w$ r& b3 j
<ymin>448</ymin>2 r( [+ u1 ~; m. Z* W; M& B8 D# R
<xmax>535</xmax>4 _2 l/ g0 g. F+ J1 |4 K
<ymax>713</ymax>' j9 j% X- a6 ]& G4 P `$ x6 Q
</bndbox>3 Z+ O( [; y+ @* |, G& I3 ~
</object> 7 i! e5 V- X5 n, e+ n1 S! F <object>. {* _$ r8 {" g3 M; |0 V1 X- a
<name>apple</name> u: L+ z( w+ W
<pose>Unspecified</pose>. \% V' O: ^7 z- N5 ` o
<truncated>1</truncated>( c7 q- K3 m4 X7 g" g0 a, w
<difficult>0</difficult>" h1 L' z9 _, V5 h2 U9 @0 L5 `. E# E
<bndbox>1 R- v c2 p6 p/ I" n v. M, V* w. C$ @& R
<xmin>603</xmin># _) Q8 T q0 S- p" E6 x$ p
<ymin>470</ymin> ) ]/ h( N, Q, M3 B; L% h/ v <xmax>800</xmax>+ _- j4 n# j. d: U1 \9 }) I3 L( {6 ?9 u6 e
<ymax>716</ymax>1 c+ b# _! N Q/ Y- Y. x
</bndbox> 9 Z3 V# x8 J$ ] </object>. J& Q" ^. Y7 H; @
<object> 8 a$ D2 M3 ]" A# V; X& ` <name>apple</name> 1 X: v9 }- ~& o; e& l6 z; e <pose>Unspecified</pose> 7 j- n8 Y! E/ E) Z <truncated>0</truncated> ! J f" X9 ` _' ?7 [9 X9 m <difficult>0</difficult># m( q# e, u/ e
<bndbox>! r" q: |2 i* q! n; A
<xmin>468</xmin> 5 U+ t/ @2 d) U+ ^) T: y <ymin>179</ymin> 5 g, d* K$ x4 J0 X% _ <xmax>727</xmax>2 \( H' V! u) K9 w& ~
<ymax>467</ymax>! O4 o5 Z! x: X6 v% k
</bndbox> e* s! l% T& o) N </object> 3 U. K. A9 h8 ^# x <object># Y' M [+ ~4 j! m0 j& w
<name>apple</name> " C) T) } r# A# D0 h <pose>Unspecified</pose> ~. N: _% ?7 Q' a3 x <truncated>1</truncated> 9 E' w$ X7 e7 _* C+ w. |( ~ <difficult>0</difficult> - E b* J# s6 n N& `. o <bndbox> # T& w0 l# u7 B6 B, q <xmin>1</xmin> 4 r4 E* ^3 L5 N5 u <ymin>63</ymin>0 c$ p, D+ {8 X' L) |9 [: }
<xmax>308</xmax> / r% ?. ]% v+ P; d <ymax>414</ymax>1 `4 ~+ Q S2 M1 {$ J
</bndbox> , u: W& |+ `3 q' l </object>0 e% ~2 }: ?! N( n( L4 A) G
</annotation> , Z+ i* e( G8 q8 k1 $ b7 ~- j* B: M* p& U8 r2 8 [8 N8 k2 h" Z' [4 v3 " n2 r. o2 @9 [% N7 q+ s4 % a+ k- p# x j0 P, e1 R2 x5: |4 u3 q; v) Y; s
6! y1 _' j# {# Y/ z
7 2 I+ I; ?* f3 g# t. n/ Y2 q" I7 e83 i4 G( A$ I1 I/ Y$ P9 l
9& b7 P9 G+ K2 N& S y# c
10# j* ^1 l4 v- B3 k N$ H
11 ; U/ T% L. b/ k. r! S12 4 `" \! I2 F+ ^! _1 ]1 r( B13 + k) D6 C' g( X. {14 - q. ^) V9 ]5 S2 _15: K9 x; E& o5 D7 n% A
16$ V) C; q# Q; c. r5 p6 Y5 x u* M
17 & l; I. A8 a7 s18 6 J8 y1 T6 |" ?/ |19 T1 \" c# x8 s& U( _9 Z- f& o* N1 }9 a
20% h) G' z# E8 f: n6 _- t
21. }3 a2 m% u5 q+ C+ D3 ?
22. [6 B% k3 Q6 _% I1 X. V
23+ `4 ?" o+ C9 f6 j# C
24 ( E, t& _) q0 _25 ; s ]5 c0 }& j26 # w: A, @2 Q1 \/ U! k, G27. @" ?# B3 b9 A, ~5 N a2 {
280 L( @( E- m6 z6 {- K9 U$ M
29 " k0 G& y) d( c$ ~30% ]4 F7 M9 J5 \3 F
31( l9 g6 q$ |/ t3 M- ]# e- M( h
32 6 I: Z* R0 N9 T# X- B E7 N33: j/ \9 I2 e5 u8 e3 I6 l( |# R
34" \% o" E: m& @: M
35- I. W1 a, X! p7 D4 `
36 5 a- o0 U+ s- U8 N# [/ A* P5 a37 9 ?/ b9 Y. ~4 Q38 & j0 l' B; m6 H: ?" ?- x$ h' N: D39 ( C& d3 o4 M: Z6 u4 V% w40- `) H5 f, C8 p+ L& U
41 " C# p4 Q6 @6 v* w, S6 w7 h* r( D, Z* D42) k8 I' H; m3 G3 T2 Y- z( O
43 1 P4 j7 A. b" E% X( o5 _5 j444 f" l! U) B! u% R3 ^) `+ ^' g. B
45 1 L. J, {, R- d+ C" G& Z- n46 " c4 v$ q. d0 W47( g! S% L& p+ E6 U0 ]& b l2 l
484 b! f- y' W- q! I7 d7 i7 z- c: B" _
49" \# ], R1 M3 u1 L( x
507 v4 f" F8 L9 \, D6 y$ i$ J
51 3 X1 ]" ~/ o+ Z) F6 p52# ^- u3 r. p5 P$ u8 G
53 : |4 k' p' G( @5 f: E7 i54 ' a8 d5 P) U/ ~/ ~, g' e& Y' \' V551 s5 Y% J4 S8 ]5 O
56 8 B; m6 R9 _9 g+ z) S0 G57 : [$ t# Z6 {& j# P. @# x8 m) c584 c- M. ~8 n3 ^& W$ m
59 : v+ ~8 Z9 ~' O3 {- {) I& o5 E" M0 x60 $ ~7 n- s: T+ Y+ o6 }( k; L61 5 W, g8 B: j n C9 Y2 b62 ) M4 ]. b! y9 ?& @) S' |7 S63 5 z: `( \1 v# _) Q' ~4 i64) M9 a3 C& D+ O! X; A
657 J( ^- }0 N5 e" W
668 j. a j. z3 d% G6 |1 b: d6 U. G4 c
67( G, S2 @1 ^' F, _" g
68& A6 n0 K' d1 j. V+ s4 t) G
69 # f, z- L/ ~1 L$ V7 ]' V- N E70 2 L% r- T- I7 R71* ~0 @0 [# L+ t8 g: H' i
720 l3 M) C) e) F+ d! ~. C
73! l1 a/ M7 b5 |& G3 s
745 z' x5 w1 W6 k# t7 b& j9 M6 K j
将xml文件提取图像信息,主要使用xml和opencv,基于torch提取,代码比较凌乱。 : \ o- U% M7 M% |1 Q) k9 G/ Y$ m4 J( w/ r6 b/ N# q& }
' \8 _+ k @* ?) F9 J# K6 W
import os) r6 Y* E3 b3 F
import numpy as np & ^% Q# b$ a) U! T2 G9 ~$ nimport cv24 x! ]! Q8 _+ j' x# B
import torch9 V* g4 L; I. H* q% [1 \+ ]' {$ r
import matplotlib.patches as patches h) \' R" ~% D, o N
import albumentations as A$ ^ {' G! N" D W" Z
from albumentations.pytorch.transforms import ToTensorV2. K$ i' z9 \) n+ [! A
from matplotlib import pyplot as plt 2 t$ D* q0 q. t9 Y+ ^+ t- Cfrom torch.utils.data import Dataset 0 n& x/ U9 g% bfrom xml.etree import ElementTree as et' h4 s, E+ }2 v9 G/ ]
from torchvision import transforms as torchtrans & ^5 [) c7 T# j% d c6 z* C& K' z; g. I& v3 c, W6 l' F
# \) e" X" Q" q2 l0 `4 a( U
# defining the files directory and testing directory ! \# g$ s5 m# p, |& Wtrain_image_dir = 'train/train/image' " z! m+ ?; R) y$ qtrain_xml_dir = 'train/train/xml' : @2 I- V0 X2 ^7 F. {9 p% I5 ]# test_image_dir = 'test/test/image' 3 J9 L- K' f8 L _% C! i9 T N# test_xml_dir = 'test/test/xml' c, b F$ P$ g7 T! `* p& R9 q# W' F2 P6 S: H* n" \, w4 [' m
3 o3 \1 X5 l# Z3 c: t2 fclass FruitImagesDataset(Dataset):6 U5 n6 J( ^( W1 ^2 U% V+ O
8 n9 R. E2 |8 P& e$ s1 ~. @* H
- Y+ P0 F. B3 \8 v+ B7 n
def __init__(self, image_dir, xml_dir, width, height, transforms=None): 4 D6 b5 I) w# K7 W+ q self.transforms = transforms 9 c: ^: C% l- H, D self.image_dir = image_dir 5 `( k( k$ j7 s2 t A! t self.xml_dir = xml_dir) m/ r- a' J4 G- \( P7 U
self.height = height ( a+ V; `/ z* @, O. p self.width = width4 E2 u# [1 I4 M' |! [
. N# u. v' A H+ `
& V: m1 v) ^4 L5 r" B
# sorting the images for consistency # F0 r; k# @* j4 C+ ]8 Z) j6 X# Z # To get images, the extension of the filename is checked to be jpg2 N2 w+ X- w$ D/ {& C0 U, T# D
self.imgs = [image for image in os.listdir(self.image_dir): E* S" E: ?7 Y. V' t3 A% b
if image[-4:] == '.jpg'] * ]2 l4 l( _( I self.xmls = [xml for xml in os.listdir(self.xml_dir)( L2 H( d9 d2 g# k- O0 U' y
if xml[-4:] == '.xml'] 2 m8 B; B' Y8 U1 R8 ?. u k, ~ 2 k" T9 O* }: Q X. X; b1 k/ y, F+ \1 |3 D$ W4 t$ a9 V% \+ c
# classes: 0 index is reserved for background ( \- S1 k" R+ K1 s( J, m self.classes = ['apple', 'banana', 'orange']5 K3 v6 P+ A: Y' Y/ V
, \/ a1 `! H' R6 e* k
9 K' l) r2 J6 f* |6 }/ R4 I def __getitem__(self, idx): 5 f3 Z$ W* W2 i; E3 ~, g' P z- x4 T- C
- F$ C5 w9 z$ f0 p+ H img_name = self.imgs[idx]* n r T4 L) n6 C& Q3 q9 A
image_path = os.path.join(self.image_dir, img_name): Q- C9 c. f, ]8 x
! c% {8 _( d; ?1 p6 t$ D; P
7 @& N7 X! Z4 G# a( p, d # reading the images and converting them to correct size and color( n+ b; y+ n7 D$ s m
img = cv2.imread(image_path)9 d) a2 p) n+ I6 v
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB).astype(np.float32) : m* J, g& U. N4 u img_res = cv2.resize(img_rgb, (self.width, self.height), cv2.INTER_AREA)- ?, n+ O+ n. A- [$ H
# diving by 255, g; } q8 ]2 n; z. b; a
img_res /= 255.0/ `1 L# K, P1 g3 Z7 ^+ T
, [4 z" u2 ` \8 T$ l! P$ u
9 m1 ]: g2 k9 q: ?9 M) Q) D
# annotation file- [' k( }6 n! o. A. U- f
annot_filename = img_name[:-4] + '.xml' f+ Q+ r$ U7 a d" Q% [) |& F8 o annot_file_path = os.path.join(self.xml_dir, annot_filename) 1 a* y3 q% k3 q- _, o% {( [0 n: ~# N! Q* A: D$ Z0 r
5 s& m5 L: Z0 t" [( A; s# `% v
boxes = [] 3 C2 R# s4 R+ j3 z& N labels = [] " I7 R2 {+ W4 ]- v5 J' i tree = et.parse(annot_file_path) # q+ W' _ n% n" y' V& d) U+ U root = tree.getroot()& @( P: ]4 r4 u p" l
. ~+ Z' a0 H$ t- Z$ V; M
9 I) b' Z& K* i1 ]8 @
# cv2 image gives size as height x width ' c8 ]$ L( ]4 p; _% ]% y1 A wt = img.shape[1]% J' H# {$ {5 a& \
ht = img.shape[0] T" {* p1 b8 l# [6 I, e
3 w0 Z# u) e$ k( C # {, f; X1 w# S4 q # box coordinates for xml files are extracted and corrected for image size given 7 M( g; F5 T/ Y, O5 S for member in root.findall('object'):( H2 R, V6 \: Q! P
labels.append(self.classes.index(member.find('name').text)): }2 R$ H& w0 L' } D$ N; z' Y
# r4 V" j( D0 B* m" r$ d/ a {0 I
6 r7 B# h: l/ B9 _! G& @ # bounding box 4 H Y; Q' @" D xmin = int(member.find('bndbox').find('xmin').text) Y- h* R- I% p( n# Q
xmax = int(member.find('bndbox').find('xmax').text)4 `1 F: k( y! b {/ c4 g [$ n
/ I) s9 n7 l( ~0 l/ C5 s
- _ E" k! X) m: ^
ymin = int(member.find('bndbox').find('ymin').text)" P3 d% B0 g6 B( u% J- A2 M) o
ymax = int(member.find('bndbox').find('ymax').text) 5 U+ _6 y' V9 b% @: \9 I$ V- |; o + I$ L. Z- N* H' ]# [: A' Q. ~7 g , C1 Z! K( I% d xmin_corr = (xmin / wt) * self.width. w, _2 v0 r: f5 E }; M
xmax_corr = (xmax / wt) * self.width 7 O. Q, C6 s/ A ymin_corr = (ymin / ht) * self.height ) o1 V# r7 Z7 I0 _% ]4 O ymax_corr = (ymax / ht) * self.height9 O V! D$ y) d% R
boxes.append([xmin_corr, ymin_corr, xmax_corr, ymax_corr]) 2 |6 k* y/ z$ a5 u, C 3 @! B. W8 s$ `* K( k5 O% V 3 P9 E6 h! U" T& o3 z/ f2 t # convert boxes into a torch.Tensor( w( b" h9 M4 }2 ^
boxes = torch.as_tensor(boxes, dtype=torch.float32) 2 Y2 {/ V# w7 E$ O" W ! Q- T' _# p+ f" W0 V+ b* E. b7 `7 U0 r. e( l
# getting the areas of the boxes2 h2 g" p5 X5 e: g8 e4 E
area = (boxes[:, 3] - boxes[:, 1]) * (boxes[:, 2] - boxes[:, 0]): _* w) j1 e9 J, p5 u: o
: \; h! X3 R! W( ^, w7 \( \3 g, m : h0 a' t9 Z. _2 ^ # suppose all instances are not crowd 2 R* i* E6 l2 c5 ] iscrowd = torch.zeros((boxes.shape[0],), dtype=torch.int64); j4 _' ~8 z$ Y! l. Q9 i! F
1 D! S6 w& H% G0 g @
; V0 F+ D3 Q0 r/ x2 g7 k1 S
labels = torch.as_tensor(labels, dtype=torch.int64)* m' q# o6 D' d* S4 i1 Z8 @
. K/ w. A5 m+ v- n/ I 2 g9 w- { ^' O# ~4 M* X& n$ V target = {} + \/ ?" t* N! r% ^ target["boxes"] = boxes5 G1 w w5 G! B0 |8 @6 ^. g
target["labels"] = labels9 N2 t0 C0 y& P J8 ]* s& k; M' m
target["area"] = area 0 U( I; _1 Q, \- b target["iscrowd"] = iscrowd 7 e1 z! U. Q/ k+ t/ t6 }/ ~ # image_id8 A6 w: Q/ Z/ X+ L- b7 S
image_id = torch.tensor([idx])% H2 K$ l( s4 p# s
target["image_id"] = image_id & y7 z% [2 g- |" n : X- Y1 S8 w/ Q2 l) Z 5 R: h2 L! E5 O G if self.transforms:2 d0 g0 o+ ? n/ ^; }( S* ]
sample = self.transforms(image=img_res, 9 G3 {" ~# z: c* V3 h# z bboxes=target['boxes'],1 S; Z) ^4 o8 H3 B7 D6 `9 C
labels=labels) 5 i- w0 D+ F( Q3 w5 B7 b5 }& q# F% w) z2 Z5 N$ u. |
0 \ F' }- T: B
img_res = sample['image'] 7 P0 k: Q H/ W! K% b+ \ l; o4 V) n% ] target['boxes'] = torch.Tensor(sample['bboxes'])3 X$ O A6 l: J- X$ l9 W" V
" {8 c& z" u4 v' r) _% }5 { / R+ G k( v6 m, ~3 y$ ?4 \, r return img_res, target ! X' G$ }" f) E V3 ?3 @ . s# n$ x5 u5 ~' J$ ]9 g6 H$ v" B: y
def __len__(self):$ f) c1 i3 v, }* w" {3 w. E, c
return len(self.imgs) }+ r& f5 j; @7 i$ R2 G) E6 E& V) ^+ J1 B
7 V0 ~$ A% b+ R6 L% H2 g
# function to convert a torchtensor back to PIL image, [0 C! Q4 V3 h
def torch_to_pil(img):, K8 D/ E4 a# {! [ i7 Y1 v' M
return torchtrans.ToPILImage()(img).convert('RGB') 7 I& m" `6 a) t & Y0 U9 ~/ o/ i/ ]: f/ S 4 h* X5 ?, y, @- R# H4 X9 d/ S: m/ G( Z! |% C
A2 ^2 m* J( [1 H; x- F! _
def plot_img_bbox(img, target): 5 A( {- j) y# l: K # plot the image and bboxes 2 t2 C* `; G, @7 ?* t5 }- j fig, a = plt.subplots(1, 1) ) Y& T$ L, r7 M% {5 o fig.set_size_inches(5, 5)' U0 p2 ^: \7 E9 p2 N0 J
a.imshow(img) 8 l+ ]: K* f& P( Z9 `# W( m( q4 W for box in (target['boxes']): 4 b7 ~9 ]5 R: k! F& B% C, p! \ x, y, width, height = box[0], box[1], box[2] - box[0], box[3] - box[1] * ?7 [8 p) e: p- l/ l- A( y rect = patches.Rectangle((x, y),+ H) f* n$ ?5 T" b% ^
width, height, & E- n) A0 }7 V linewidth=2, + C, e: |' S8 A; x+ P edgecolor='r', 8 ^) i; w( \; o5 ~* O, _! y7 D facecolor='none') # `. j+ c1 g. Y9 B m3 S- \2 ~, @ J
/ C1 W- `% ?0 \0 I, A' m. S5 y
# Draw the bounding box on top of the image 4 \3 i5 f: c/ E% M! q& e a.add_patch(rect) ( W1 i( }9 i: @0 K plt.show() ) d" A3 e. \" z/ [; a1 @9 o! Z7 c2 T* [2 P' I
: \# F9 S4 N( N1 k* ?! s: u . U" ~5 _, Z) Q- y! i' d" [) V4 s! o7 z4 @3 ?! t0 x
def get_transform(train): * A& f- Z) G3 U if train: * \; J! j" V% K% u6 e* X& @ return A.Compose([& ~) ]! _0 R/ m! d: v
A.HorizontalFlip(0.5),' Y3 J( j) y) o; |+ K7 ]) b' L
# ToTensorV2 converts image to pytorch tensor without div by 255+ J, y/ o, O) e9 a5 B
ToTensorV2(p=1.0) . Q; h' Y& B% d' m: a ], bbox_params={'format': 'pascal_voc', 'label_fields': ['labels']})5 E3 U) B+ U/ W- _$ a
else: . d* N/ T% _ \9 e7 c; Y0 @ return A.Compose([ ; ]/ e) Y4 H4 ~% V; T8 i0 o ToTensorV2(p=1.0)9 P2 F4 }1 ?: F, d V2 m2 o
], bbox_params={'format': 'pascal_voc', 'label_fields': ['labels']})2 ~" W: R) | g, T( v8 m