@@ -2796,12 +2796,15 @@ private class HandPoseEstimator
27962796 //int[] PALM_LANDMARK_IDS = new int[] { 0, 5, 9, 13, 17, 1, 2 };
27972797 int PALM_LANDMARKS_INDEX_OF_PALM_BASE = 0 ;
27982798 int PALM_LANDMARKS_INDEX_OF_MIDDLE_FINGER_BASE = 2 ;
2799+ Point PALM_BOX_PRE_SHIFT_VECTOR = new Point ( 0 , 0 ) ;
2800+ //double PALM_BOX_PRE_ENLARGE_FACTOR = 4.0;
27992801 Point PALM_BOX_SHIFT_VECTOR = new Point ( 0 , - 0.4 ) ;
28002802 double PALM_BOX_ENLARGE_FACTOR = 3.0 ;
28012803 Point HAND_BOX_SHIFT_VECTOR = new Point ( 0 , - 0.1 ) ;
28022804 double HAND_BOX_ENLARGE_FACTOR = 1.65 ;
28032805
28042806 Mat tmpImage ;
2807+ Mat tmpRotatedImage ;
28052808
28062809 public HandPoseEstimator ( string modelFilepath , float confThreshold = 0.8f , int backend = Dnn . DNN_BACKEND_OPENCV , int target = Dnn . DNN_TARGET_CPU )
28072810 {
@@ -2819,12 +2822,54 @@ public HandPoseEstimator(string modelFilepath, float confThreshold = 0.8f, int b
28192822 handpose_estimation_net . setPreferableTarget ( this . target ) ;
28202823 }
28212824
2822- protected virtual Mat preprocess ( Mat image , Mat palm , out Mat rotated_palm_bbox , out double angle , out Mat rotation_matrix )
2825+ protected virtual Mat preprocess ( Mat image , Mat palm , out Mat rotated_palm_bbox , out double angle , out Mat rotation_matrix , out Mat pad_bias )
28232826 {
2827+ // '''
2828+ // Rotate input for inference.
2829+ // Parameters:
2830+ // image - input image of BGR channel order
2831+ // palm_bbox - palm bounding box found in image of format[[x1, y1], [x2, y2]] (top - left and bottom - right points)
2832+ // palm_landmarks - 7 landmarks(5 finger base points, 2 palm base points) of shape[7, 2]
2833+ // Returns:
2834+ // rotated_hand - rotated hand image for inference
2835+ // rotate_palm_bbox - palm box of interest range
2836+ // angle - rotate angle for hand
2837+ // rotation_matrix - matrix for rotation and de - rotation
2838+ // pad_bias - pad pixels of interest range
2839+ // '''
2840+
2841+ // Generate an image with padding added after the squarify process.
2842+ int maxSize = Math . Max ( image . width ( ) , image . height ( ) ) ;
2843+ int tmpImageSize = ( int ) ( maxSize * 1.5 ) ;
2844+ if ( tmpImage != null && ( tmpImage . width ( ) != tmpImageSize || tmpImage . height ( ) != tmpImageSize ) )
2845+ {
2846+ tmpImage . Dispose ( ) ;
2847+ tmpImage = null ;
2848+ tmpRotatedImage . Dispose ( ) ;
2849+ tmpRotatedImage = null ;
2850+ }
2851+ if ( tmpImage == null )
2852+ {
2853+ tmpImage = new Mat ( tmpImageSize , tmpImageSize , image . type ( ) , Scalar . all ( 0 ) ) ;
2854+ tmpRotatedImage = tmpImage . clone ( ) ;
2855+ }
2856+
2857+ int pad = ( tmpImageSize - maxSize ) / 2 ;
2858+ pad_bias = new Mat ( 2 , 1 , CvType . CV_32FC1 ) ;
2859+ pad_bias . put ( 0 , 0 , new float [ ] { - pad , - pad } ) ;
2860+
2861+ Mat _tmpImage_roi = new Mat ( tmpImage , new OpenCVRect ( pad , pad , image . width ( ) , image . height ( ) ) ) ;
2862+ image . copyTo ( _tmpImage_roi ) ;
2863+
2864+ // Apply the pad_bias to palm_bbox and palm_landmarks.
2865+ Mat new_palm = palm . clone ( ) ;
2866+ Mat palm_bbox_and_landmark = new_palm . colRange ( new OpenCVRange ( 0 , 18 ) ) . reshape ( 2 , 9 ) ;
2867+ Core . add ( palm_bbox_and_landmark , new Scalar ( pad , pad ) , palm_bbox_and_landmark ) ;
2868+
28242869 // Rotate input to have vertically oriented hand image
28252870 // compute rotation
2826- Mat palm_bbox = palm . colRange ( new OpenCVRange ( 0 , 4 ) ) . reshape ( 1 , 2 ) ;
2827- Mat palm_landmarks = palm . colRange ( new OpenCVRange ( 4 , 18 ) ) . reshape ( 1 , 7 ) ;
2871+ Mat palm_bbox = new_palm . colRange ( new OpenCVRange ( 0 , 4 ) ) . reshape ( 1 , 2 ) ;
2872+ Mat palm_landmarks = new_palm . colRange ( new OpenCVRange ( 4 , 18 ) ) . reshape ( 1 , 7 ) ;
28282873
28292874 Mat p1 = palm_landmarks . row ( PALM_LANDMARKS_INDEX_OF_PALM_BASE ) ;
28302875 Mat p2 = palm_landmarks . row ( PALM_LANDMARKS_INDEX_OF_MIDDLE_FINGER_BASE ) ;
@@ -2844,10 +2889,6 @@ protected virtual Mat preprocess(Mat image, Mat palm, out Mat rotated_palm_bbox,
28442889 // get rotation matrix
28452890 rotation_matrix = Imgproc . getRotationMatrix2D ( center_palm_bbox , angle , 1.0 ) ;
28462891
2847- // get rotated image
2848- Mat rotated_image = new Mat ( ) ;
2849- Imgproc . warpAffine ( image , rotated_image , rotation_matrix , image . size ( ) ) ;
2850-
28512892 // get bounding boxes from rotated palm landmarks
28522893 Mat rotated_palm_landmarks = new Mat ( 2 , 7 , CvType . CV_32FC1 ) ;
28532894 Mat _a = new Mat ( 1 , 3 , CvType . CV_64FC1 ) ;
@@ -2884,7 +2925,6 @@ protected virtual Mat preprocess(Mat image, Mat palm, out Mat rotated_palm_bbox,
28842925 Point _rotated_palm_bbox_br = _rotated_palm_bbox . br ( ) ;
28852926 Point wh_rotated_palm_bbox = _rotated_palm_bbox_br - _rotated_palm_bbox_tl ;
28862927 Point shift_vector = new Point ( PALM_BOX_SHIFT_VECTOR . x * wh_rotated_palm_bbox . x , PALM_BOX_SHIFT_VECTOR . y * wh_rotated_palm_bbox . y ) ;
2887-
28882928 _rotated_palm_bbox_tl = _rotated_palm_bbox_tl + shift_vector ;
28892929 _rotated_palm_bbox_br = _rotated_palm_bbox_br + shift_vector ;
28902930
@@ -2899,51 +2939,49 @@ protected virtual Mat preprocess(Mat image, Mat palm, out Mat rotated_palm_bbox,
28992939 center_rotated_plam_bbox = new Point ( ( _rotated_palm_bbox_tl . x + _rotated_palm_bbox_br . x ) / 2 , ( _rotated_palm_bbox_tl . y + _rotated_palm_bbox_br . y ) / 2 ) ;
29002940 wh_rotated_palm_bbox = _rotated_palm_bbox_br - _rotated_palm_bbox_tl ;
29012941 Point new_half_size2 = new Point ( wh_rotated_palm_bbox . x * PALM_BOX_ENLARGE_FACTOR / 2.0 , wh_rotated_palm_bbox . y * PALM_BOX_ENLARGE_FACTOR / 2.0 ) ;
2902- _rotated_palm_bbox_tl = new Point ( center_rotated_plam_bbox . x - new_half_size2 . x , center_rotated_plam_bbox . y - new_half_size2 . x ) ;
2903- _rotated_palm_bbox_br = new Point ( center_rotated_plam_bbox . x + new_half_size2 . x , center_rotated_plam_bbox . y + new_half_size2 . x ) ;
2942+ OpenCVRect _rotated_palm_bbox_rect = new OpenCVRect ( ( int ) ( center_rotated_plam_bbox . x - new_half_size2 . x ) , ( int ) ( center_rotated_plam_bbox . y - new_half_size2 . y )
2943+ , ( int ) ( new_half_size2 . x * 2 ) , ( int ) ( new_half_size2 . y * 2 ) ) ;
2944+ _rotated_palm_bbox_tl = _rotated_palm_bbox_rect . tl ( ) ;
2945+ _rotated_palm_bbox_br = _rotated_palm_bbox_rect . br ( ) ;
29042946 rotated_palm_bbox . put ( 0 , 0 , new double [ ] { _rotated_palm_bbox_tl . x , _rotated_palm_bbox_tl . y , _rotated_palm_bbox_br . x , _rotated_palm_bbox_br . y } ) ;
29052947
2906- // Crop and resize the rotated image by the bounding box
2948+ // crop bounding box
29072949 int [ ] diff = new int [ ] {
29082950 Math . Max ( ( int ) - _rotated_palm_bbox_tl . x , 0 ) ,
29092951 Math . Max ( ( int ) - _rotated_palm_bbox_tl . y , 0 ) ,
2910- Math . Max ( ( int ) _rotated_palm_bbox_br . x - rotated_image . width ( ) , 0 ) ,
2911- Math . Max ( ( int ) _rotated_palm_bbox_br . y - rotated_image . height ( ) , 0 )
2952+ Math . Max ( ( int ) _rotated_palm_bbox_br . x - tmpRotatedImage . width ( ) , 0 ) ,
2953+ Math . Max ( ( int ) _rotated_palm_bbox_br . y - tmpRotatedImage . height ( ) , 0 )
29122954 } ;
29132955 Point tl = new Point ( _rotated_palm_bbox_tl . x + diff [ 0 ] , _rotated_palm_bbox_tl . y + diff [ 1 ] ) ;
29142956 Point br = new Point ( _rotated_palm_bbox_br . x + diff [ 2 ] , _rotated_palm_bbox_br . y + diff [ 3 ] ) ;
29152957 OpenCVRect rotated_palm_bbox_rect = new OpenCVRect ( tl , br ) ;
2916- OpenCVRect rotated_image_rect = new OpenCVRect ( 0 , 0 , rotated_image . width ( ) , rotated_image . height ( ) ) ;
2917- Mat crop = new Mat ( rotated_image , rotated_image_rect . intersect ( rotated_palm_bbox_rect ) ) ;
2918-
2919- //
2920- //Core.copyMakeBorder(crop, crop, diff[1], diff[3], diff[0], diff[2], Core.BORDER_CONSTANT, Scalar.all(0));
2921- //Mat blob = Dnn.blobFromImage(crop, 1.0 / 255.0, input_size, new Scalar(0, 0, 0), true, false, CvType.CV_32F);
2922- //
2923- // or
2924- //
2925- int tmpImageSize = ( int ) ( Math . Max ( image . width ( ) , image . height ( ) ) * 1.5 ) ;
2926- if ( tmpImage != null && ( tmpImage . width ( ) != tmpImageSize || tmpImage . height ( ) != tmpImageSize ) )
2927- {
2928- tmpImage . Dispose ( ) ;
2929- tmpImage = null ;
2930- }
2931- if ( tmpImage == null )
2932- {
2933- tmpImage = new Mat ( tmpImageSize , tmpImageSize , image . type ( ) , Scalar . all ( 0 ) ) ;
2934- }
2935- Mat _tmpImage_crop = new Mat ( tmpImage , new OpenCVRect ( 0 , 0 , diff [ 0 ] + crop . width ( ) + diff [ 2 ] , diff [ 1 ] + crop . height ( ) + diff [ 3 ] ) ) ;
2936- Imgproc . rectangle ( _tmpImage_crop , new OpenCVRect ( 0 , 0 , _tmpImage_crop . width ( ) , _tmpImage_crop . height ( ) ) , Scalar . all ( 0 ) ) ;
2937- Mat _tmpImage_crop2 = new Mat ( tmpImage , new OpenCVRect ( diff [ 0 ] , diff [ 1 ] , crop . width ( ) , crop . height ( ) ) ) ;
2938- crop . copyTo ( _tmpImage_crop2 ) ;
2958+ OpenCVRect rotated_image_rect = new OpenCVRect ( 0 , 0 , tmpRotatedImage . width ( ) , tmpRotatedImage . height ( ) ) ;
29392959
2940- Mat blob = Dnn . blobFromImage ( _tmpImage_crop , 1.0 / 255.0 , input_size , new Scalar ( 0 , 0 , 0 ) , true , false , CvType . CV_32F ) ;
2941- //
2960+ // get rotated image
2961+ OpenCVRect warp_roi_rect = rotated_image_rect . intersect ( rotated_palm_bbox_rect ) ;
2962+ Mat _tmpImage_warp_roi = new Mat ( tmpImage , warp_roi_rect ) ;
2963+ Mat _tmpRotatedImage_warp_roi = new Mat ( tmpRotatedImage , warp_roi_rect ) ;
2964+ Point warp_roi_center_palm_bbox = center_palm_bbox - warp_roi_rect . tl ( ) ;
2965+ Mat warp_roi_rotation_matrix = Imgproc . getRotationMatrix2D ( warp_roi_center_palm_bbox , angle , 1.0 ) ;
2966+ Imgproc . warpAffine ( _tmpImage_warp_roi , _tmpRotatedImage_warp_roi , warp_roi_rotation_matrix , _tmpImage_warp_roi . size ( ) ) ;
2967+
2968+ // get rotated_palm_bbox-size rotated image
2969+ OpenCVRect crop_rect = rotated_image_rect . intersect (
2970+ new OpenCVRect ( 0 , 0 , ( int ) _rotated_palm_bbox_br . x - ( int ) _rotated_palm_bbox_tl . x , ( int ) _rotated_palm_bbox_br . y - ( int ) _rotated_palm_bbox_tl . y ) ) ;
2971+ Mat _tmpImage_crop_roi = new Mat ( tmpImage , crop_rect ) ;
2972+ Imgproc . rectangle ( _tmpImage_crop_roi , new OpenCVRect ( 0 , 0 , _tmpImage_crop_roi . width ( ) , _tmpImage_crop_roi . height ( ) ) , Scalar . all ( 0 ) , - 1 ) ;
2973+ OpenCVRect crop2_rect = rotated_image_rect . intersect ( new OpenCVRect ( diff [ 0 ] , diff [ 1 ] , _tmpRotatedImage_warp_roi . width ( ) , _tmpRotatedImage_warp_roi . height ( ) ) ) ;
2974+ Mat _tmpImage_crop2_roi = new Mat ( tmpImage , crop2_rect ) ;
2975+ if ( _tmpRotatedImage_warp_roi . size ( ) == _tmpImage_crop2_roi . size ( ) )
2976+ _tmpRotatedImage_warp_roi . copyTo ( _tmpImage_crop2_roi ) ;
2977+
2978+
2979+ Mat blob = Dnn . blobFromImage ( _tmpImage_crop_roi , 1.0 / 255.0 , input_size , new Scalar ( 0 , 0 , 0 ) , true , false , CvType . CV_32F ) ;
29422980
29432981 // NCHW => NHWC
29442982 Core . transposeND ( blob , new MatOfInt ( 0 , 2 , 3 , 1 ) , blob ) ;
29452983
2946- rotated_image . Dispose ( ) ;
2984+ new_palm . Dispose ( ) ;
29472985
29482986 return blob ;
29492987 }
@@ -2954,15 +2992,16 @@ public virtual Mat infer(Mat image, Mat palm)
29542992 Mat rotated_palm_bbox ;
29552993 double angle ;
29562994 Mat rotation_matrix ;
2957- Mat input_blob = preprocess ( image , palm , out rotated_palm_bbox , out angle , out rotation_matrix ) ;
2995+ Mat pad_bias ;
2996+ Mat input_blob = preprocess ( image , palm , out rotated_palm_bbox , out angle , out rotation_matrix , out pad_bias ) ;
29582997
29592998 // Forward
29602999 handpose_estimation_net . setInput ( input_blob ) ;
29613000 List < Mat > output_blob = new List < Mat > ( ) ;
29623001 handpose_estimation_net . forward ( output_blob , handpose_estimation_net . getUnconnectedOutLayersNames ( ) ) ;
29633002
29643003 // Postprocess
2965- Mat results = postprocess ( output_blob , rotated_palm_bbox , angle , rotation_matrix ) ;
3004+ Mat results = postprocess ( output_blob , rotated_palm_bbox , angle , rotation_matrix , pad_bias ) ;
29663005
29673006 input_blob . Dispose ( ) ;
29683007 for ( int i = 0 ; i < output_blob . Count ; i ++ )
@@ -2973,7 +3012,7 @@ public virtual Mat infer(Mat image, Mat palm)
29733012 return results ; // [bbox_coords, landmarks_coords, landmarks_coords_world, handedness, conf]
29743013 }
29753014
2976- protected virtual Mat postprocess ( List < Mat > output_blob , Mat rotated_palm_bbox , double angle , Mat rotation_matrix )
3015+ protected virtual Mat postprocess ( List < Mat > output_blob , Mat rotated_palm_bbox , double angle , Mat rotation_matrix , Mat pad_bias )
29773016 {
29783017 Mat landmarks = output_blob [ 0 ] ;
29793018 float conf = ( float ) output_blob [ 1 ] . get ( 0 , 0 ) [ 0 ] ;
@@ -3050,7 +3089,10 @@ protected virtual Mat postprocess(List<Mat> output_blob, Mat rotated_palm_bbox,
30503089 center . put ( 0 , 0 , new double [ ] { ( rotated_palm_bbox_arr [ 0 ] + rotated_palm_bbox_arr [ 2 ] ) / 2.0 , ( rotated_palm_bbox_arr [ 1 ] + rotated_palm_bbox_arr [ 3 ] ) / 2.0 , 1.0 } ) ;
30513090 Mat original_center = new Mat ( 2 , 1 , CvType . CV_64FC1 ) ;
30523091 original_center . put ( 0 , 0 , new double [ ] { inverse_rotation_matrix . row ( 0 ) . dot ( center . reshape ( 1 , 1 ) ) , inverse_rotation_matrix . row ( 1 ) . dot ( center . reshape ( 1 , 1 ) ) } ) ;
3053- Core . add ( rotated_landmarks . reshape ( 3 , 21 ) , new Scalar ( original_center . get ( 0 , 0 ) [ 0 ] , original_center . get ( 1 , 0 ) [ 0 ] , 0.0 ) , landmarks . reshape ( 3 , 21 ) ) ;
3092+
3093+ Core . add ( rotated_landmarks . reshape ( 3 , 21 )
3094+ , new Scalar ( original_center . get ( 0 , 0 ) [ 0 ] + pad_bias . get ( 0 , 0 ) [ 0 ] , original_center . get ( 1 , 0 ) [ 0 ] + pad_bias . get ( 1 , 0 ) [ 0 ] , 0.0 )
3095+ , landmarks . reshape ( 3 , 21 ) ) ;
30543096
30553097 // get bounding box from rotated_landmarks
30563098 Point [ ] landmarks_points = new Point [ 21 ] ;
@@ -3220,6 +3262,9 @@ public virtual void dispose()
32203262
32213263 if ( tmpImage != null )
32223264 tmpImage . Dispose ( ) ;
3265+
3266+ if ( tmpRotatedImage != null )
3267+ tmpRotatedImage . Dispose ( ) ;
32233268 }
32243269 }
32253270 }
0 commit comments