1
1
import * as tf from '@tensorflow/tfjs-core' ;
2
2
3
+ import { Point } from '../Point' ;
4
+ import { CELL_SIZE , CELL_STRIDE } from './config' ;
3
5
import { PNet } from './PNet' ;
4
6
import { PNetParams } from './types' ;
5
7
6
8
function rescaleAndNormalize ( x : tf . Tensor4D , scale : number ) : tf . Tensor4D {
7
9
return tf . tidy ( ( ) => {
8
- const [ height , width ] = x . shape
9
- const resized = tf . image . resizeBilinear ( x , [ height * scale , width * scale ] )
10
10
11
- return tf . mul ( tf . sub ( resized , tf . scalar ( 127.5 ) ) , tf . scalar ( 0.0078125 ) )
12
-
13
- // TODO: ?
14
- // img_x = np.expand_dims(scaled_image, 0)
15
- // img_y = np.transpose(img_x, (0, 2, 1, 3))
11
+ const [ height , width ] = x . shape . slice ( 1 )
12
+ const resized = tf . image . resizeBilinear ( x , [ Math . floor ( height * scale ) , Math . floor ( width * scale ) ] )
13
+ const normalized = tf . mul ( tf . sub ( resized , tf . scalar ( 127.5 ) ) , tf . scalar ( 0.0078125 ) )
16
14
15
+ return ( tf . transpose ( normalized , [ 0 , 2 , 1 , 3 ] ) as tf . Tensor4D )
17
16
} )
18
17
}
19
18
20
- export function stage1 ( x : tf . Tensor4D , scales : number [ ] , params : PNetParams ) {
21
- return tf . tidy ( ( ) => {
22
19
23
- const boxes = scales . map ( ( scale ) => {
24
- const resized = rescaleAndNormalize ( x , scale )
25
- const { prob, convOut } = PNet ( resized , params )
26
- } )
20
+ function extractBoundingBoxes (
21
+ scores : tf . Tensor2D ,
22
+ regions : tf . Tensor3D ,
23
+ scale : number ,
24
+ scoreThreshold : number
25
+ ) {
27
26
28
- } )
29
- }
27
+ // TODO: fix this!, maybe better to use tf.gather here
28
+ const indices2D : Point [ ] = [ ]
29
+ for ( let y = 0 ; y < scores . shape [ 0 ] ; y ++ ) {
30
+ for ( let x = 0 ; x < scores . shape [ 1 ] ; x ++ ) {
31
+ if ( scores . get ( y , x ) >= scoreThreshold ) {
32
+ indices2D . push ( new Point ( x , y ) )
33
+ }
34
+ }
35
+ }
36
+
37
+ if ( ! indices2D . length ) {
38
+ return null
39
+ }
40
+
41
+ return tf . tidy ( ( ) => {
30
42
31
- /*
43
+ const indicesTensor = tf . tensor2d (
44
+ indices2D . map ( pt => [ pt . y , pt . x ] ) ,
45
+ [ indices2D . length , 2 ]
46
+ )
32
47
33
- for scale in scales:
34
- scaled_image = self.__scale_image(image, scale)
48
+ const cellsStart = tf . round (
49
+ indicesTensor . mul ( tf . scalar ( CELL_STRIDE ) ) . add ( tf . scalar ( 1 ) ) . div ( tf . scalar ( scale ) )
50
+ ) as tf . Tensor2D
51
+ const cellsEnd = tf . round (
52
+ indicesTensor . mul ( tf . scalar ( CELL_STRIDE ) ) . add ( tf . scalar ( CELL_SIZE ) ) . div ( tf . scalar ( scale ) )
53
+ ) as tf . Tensor2D
35
54
36
- img_x = np.expand_dims(scaled_image, 0)
37
- img_y = np.transpose(img_x, (0, 2, 1, 3))
55
+ const scoresTensor = tf . tensor1d ( indices2D . map ( pt => scores . get ( pt . y , pt . x ) ) )
38
56
39
- out = self.__pnet.feed(img_y)
57
+ const candidateRegions = indices2D . map ( c => ( {
58
+ left : regions . get ( c . y , c . x , 0 ) ,
59
+ top : regions . get ( c . y , c . x , 1 ) ,
60
+ right : regions . get ( c . y , c . x , 2 ) ,
61
+ bottom : regions . get ( c . y , c . x , 3 )
62
+ } ) )
40
63
41
- out0 = np.transpose(out[0], (0, 2, 1, 3))
42
- out1 = np.transpose(out[1], (0, 2, 1, 3))
64
+ const regionsTensor = tf . tensor2d (
65
+ candidateRegions . map ( r => [ r . left , r . top , r . right , r . bottom ] ) ,
66
+ [ candidateRegions . length , 4 ]
67
+ )
43
68
44
- boxes, _ = self.__generate_bounding_box(out1[0, :, :, 1].copy(),
45
- out0[0, :, :, :].copy(), scale, self.__steps_threshold[0])
69
+ const boxesTensor = tf . concat2d ( [ cellsStart , cellsEnd , scoresTensor . as2D ( scoresTensor . size , 1 ) , regionsTensor ] , 1 )
46
70
47
- # inter-scale nms
48
- pick = self.__nms(boxes.copy(), 0.5, 'Union')
49
- if boxes.size > 0 and pick.size > 0:
50
- boxes = boxes[pick, :]
51
- total_boxes = np.append(total_boxes, boxes, axis=0)
71
+ return boxesTensor
72
+ } )
73
+ }
52
74
75
+ // TODO: debug
76
+ declare const window : any
53
77
78
+ export function stage1 ( x : tf . Tensor4D , scales : number [ ] , scoreThreshold : number , params : PNetParams ) {
79
+ return tf . tidy ( ( ) => {
54
80
81
+ const boxes = scales . map ( ( scale , i ) => {
82
+ let resized = i === 0
83
+ // TODO: debug
84
+ ? tf . tensor4d ( window . resizedData , [ 1 , 820 , 461 , 3 ] )
55
85
56
- numboxes = total_boxes.shape[0]
86
+ : rescaleAndNormalize ( x , scale )
57
87
58
- if numboxes > 0:
59
- pick = self.__nms(total_boxes.copy(), 0.7, 'Union')
60
- total_boxes = total_boxes[pick, :]
88
+ const { prob, regions } = PNet ( resized , params )
61
89
62
- regw = total_boxes[:, 2] - total_boxes[:, 0]
63
- regh = total_boxes[:, 3] - total_boxes[:, 1]
90
+ const scores = tf . unstack ( prob , 3 ) [ 1 ]
91
+ const [ sh , sw ] = scores . shape . slice ( 1 )
92
+ const [ rh , rw ] = regions . shape . slice ( 1 )
64
93
65
- qq1 = total_boxes[:, 0] + total_boxes[:, 5] * regw
66
- qq2 = total_boxes[:, 1] + total_boxes[:, 6] * regh
67
- qq3 = total_boxes[:, 2] + total_boxes[:, 7] * regw
68
- qq4 = total_boxes[:, 3] + total_boxes[:, 8] * regh
69
94
70
- total_boxes = np.transpose(np.vstack([qq1, qq2, qq3, qq4, total_boxes[:, 4]]))
71
- total_boxes = self.__rerec(total_boxes.copy())
95
+ const boxes = extractBoundingBoxes (
96
+ scores . as2D ( sh , sw ) ,
97
+ regions . as3D ( rh , rw , 4 ) ,
98
+ scale ,
99
+ scoreThreshold
100
+ )
72
101
73
- total_boxes[:, 0:4] = np.fix(total_boxes[:, 0:4]).astype(np.int32)
74
- status = StageStatus(self.__pad(total_boxes.copy(), stage_status.width, stage_status.height),
75
- width=stage_status.width, height=stage_status.height)
102
+ // TODO: debug
103
+ if ( ! boxes ) {
104
+ console . log ( 'no boxes for scale' , scale )
105
+ return
106
+ }
107
+ // TODO: debug
108
+ i === 0 && ( window . boxes = boxes . dataSync ( ) )
76
109
77
- return total_boxes, status
78
- */
110
+ } )
111
+
112
+ } )
113
+ }
0 commit comments