2016-12-22 1 views
5

J'ai essayé Google Cloud Vision api (TEXT_DETECTION) sur une image pivotée à 90 degrés. Il peut toujours renvoyer le texte reconnu correctement. (Voir l'image ci-dessous)Obtenir l'orientation correcte de l'image par Google Cloud Vision api (TEXT_DETECTION)

Cela signifie que le moteur peut reconnaître du texte même si l'image est pivotée de 90, 180 ou 270 degrés. Cependant, le résultat de la réponse n'inclut pas d'informations sur l'orientation correcte de l'image. (document: EntityAnnotation)

Y at-il de toute façon non seulement obtenir du texte reconnu mais aussi obtenir l'orientation ?
Google pourrait-il soutenir semblable à (FaceAnnotation: getRollAngle)

enter image description here

+0

I Si vous souhaitez que cette fonctionnalité existe, envisagez de publier une demande de fonctionnalité sur le programme de suivi des problèmes de google-cloud-platform à l'adresse https://code.google.com/p/google-cloud-platform/issues/list. – Adam

+0

Merci. Je ne savais pas qu'il existe une telle liste de problèmes. Je viens de poster la demande. https://code.google.com/p/google-cloud-platform/issues/detail?id=194 –

Répondre

3

Comme décrit dans le Public Issue Tracker, notre équipe d'ingénieurs est maintenant au courant de cette demande de fonctionnalité, et il n'y a actuellement aucune date pour sa mise en œuvre. Remarque: il est possible que les informations d'orientation soient déjà disponibles dans les métadonnées de votre image. Remarque Un exemple de comment extraire les métadonnées peut être vu dans ce Third-party library.

Une solution de contournement étendue serait de vérifier les "vertices" "boundingPoly" renvoyés pour les "textAnnotations" renvoyés. En calculant la largeur et la hauteur du rectangle de chaque mot détecté, vous pouvez déterminer si une image n'est pas à droite si le rectangle 'height'> 'width' (alias l'image est latéralement).

+0

curieux de savoir comment la vision de Google Cloud peut obtenir le texte correct d'une image même si l'image n'est pas horizontale aligné et doit être tourné. Comment l'API sait-elle combien tourner l'image? Si cette information ne figure pas dans les métadonnées de l'image, comment l'API cloud la découvre-t-elle? – Omnipresent

1

Je poste ma solution de contournement qui fonctionne vraiment pour les images 90, 180, 270 degrés tournés. Veuillez consulter le code ci-dessous.

GetExifOrientation(annotateImageResponse.getTextAnnotations().get(1));
/** 
* 
* @param ea The input EntityAnnotation must be NOT from the first EntityAnnotation of 
*   annotateImageResponse.getTextAnnotations(), because it is not affected by 
*   image orientation. 
* @return Exif orientation (1 or 3 or 6 or 8) 
*/ 
public static int GetExifOrientation(EntityAnnotation ea) { 
    List<Vertex> vertexList = ea.getBoundingPoly().getVertices(); 
    // Calculate the center 
    float centerX = 0, centerY = 0; 
    for (int i = 0; i < 4; i++) { 
     centerX += vertexList.get(i).getX(); 
     centerY += vertexList.get(i).getY(); 
    } 
    centerX /= 4; 
    centerY /= 4; 

    int x0 = vertexList.get(0).getX(); 
    int y0 = vertexList.get(0).getY(); 

    if (x0 < centerX) { 
     if (y0 < centerY) { 
      //  0 -------- 1 
      //  |   | 
      //  3 -------- 2 
      return EXIF_ORIENTATION_NORMAL; // 1 
     } else { 
      //  1 -------- 2 
      //  |   | 
      //  0 -------- 3 
      return EXIF_ORIENTATION_270_DEGREE; // 6 
     } 
    } else { 
     if (y0 < centerY) { 
      //  3 -------- 0 
      //  |   | 
      //  2 -------- 1 
      return EXIF_ORIENTATION_90_DEGREE; // 8 
     } else { 
      //  2 -------- 3 
      //  |   | 
      //  1 -------- 0 
      return EXIF_ORIENTATION_180_DEGREE; // 3 
     } 
    } 
} 

Plus d'info
J'ai trouvé que je dois ajouter indice de langue pour faire annotateImageResponse.getTextAnnotations().get(1) toujours suivre la règle.

Exemple de code pour ajouter indice de langue

ImageContext imageContext = new ImageContext(); 
String [] languages = { "zh-TW" }; 
imageContext.setLanguageHints(Arrays.asList(languages)); 
annotateImageRequest.setImageContext(imageContext); 
0

Parfois, il est impossible d'obtenir l'orientation de métadonnées. Par exemple si l'utilisateur a fait une photo en utilisant l'appareil photo de l'appareil mobile avec une mauvaise orientation. Ma solution est basée sur la réponse de Jack Fan et pour google-api-services-vision (disponible via Maven).

ma classe TextUnit

public class TextUnit { 
     private String text; 

     // X of lowest left point 
     private float llx; 

     // Y of lowest left point 
     private float lly; 

     // X of upper right point 
     private float urx; 

     // Y of upper right point 
     private float ury; 
    } 

méthode de base:

List<TextUnit> extractData(BatchAnnotateImagesResponse response) throws AnnotateImageResponseException { 
      List<TextUnit> data = new ArrayList<>(); 

      for (AnnotateImageResponse res : response.getResponses()) { 
       if (null != res.getError()) { 
        String errorMessage = res.getError().getMessage(); 
        logger.log(Level.WARNING, "AnnotateImageResponse ERROR: " + errorMessage); 
        throw new AnnotateImageResponseException("AnnotateImageResponse ERROR: " + errorMessage); 
       } else { 
        List<EntityAnnotation> texts = response.getResponses().get(0).getTextAnnotations(); 
        if (texts.size() > 0) { 

         //get orientation 
         EntityAnnotation first_word = texts.get(1); 
         int orientation; 
         try { 
          orientation = getExifOrientation(first_word); 
         } catch (NullPointerException e) { 
          try { 
           orientation = getExifOrientation(texts.get(2)); 
          } catch (NullPointerException e1) { 
           orientation = EXIF_ORIENTATION_NORMAL; 
          } 
         } 
         logger.log(Level.INFO, "orientation: " + orientation); 

         // Calculate the center 
         float centerX = 0, centerY = 0; 
         for (Vertex vertex : first_word.getBoundingPoly().getVertices()) { 
          if (vertex.getX() != null) { 
           centerX += vertex.getX(); 
          } 
          if (vertex.getY() != null) { 
           centerY += vertex.getY(); 
          } 
         } 
         centerX /= 4; 
         centerY /= 4; 


         for (int i = 1; i < texts.size(); i++) {//exclude first text - it contains all text of the page 

          String blockText = texts.get(i).getDescription(); 
          BoundingPoly poly = texts.get(i).getBoundingPoly(); 

          try { 
           float llx = 0; 
           float lly = 0; 
           float urx = 0; 
           float ury = 0; 
           if (orientation == EXIF_ORIENTATION_NORMAL) { 
            poly = invertSymmetricallyBy0X(centerY, poly); 
            llx = getLlx(poly); 
            lly = getLly(poly); 
            urx = getUrx(poly); 
            ury = getUry(poly); 
           } else if (orientation == EXIF_ORIENTATION_90_DEGREE) { 
            //invert by x 
            poly = rotate(centerX, centerY, poly, Math.toRadians(-90)); 
            poly = invertSymmetricallyBy0Y(centerX, poly); 
            llx = getLlx(poly); 
            lly = getLly(poly); 
            urx = getUrx(poly); 
            ury = getUry(poly); 
           } else if (orientation == EXIF_ORIENTATION_180_DEGREE) { 
            poly = rotate(centerX, centerY, poly, Math.toRadians(-180)); 
            poly = invertSymmetricallyBy0Y(centerX, poly); 
            llx = getLlx(poly); 
            lly = getLly(poly); 
            urx = getUrx(poly); 
            ury = getUry(poly); 
           }else if (orientation == EXIF_ORIENTATION_270_DEGREE){ 
            //invert by x 
            poly = rotate(centerX, centerY, poly, Math.toRadians(-270)); 
            poly = invertSymmetricallyBy0Y(centerX, poly); 
            llx = getLlx(poly); 
            lly = getLly(poly); 
            urx = getUrx(poly); 
            ury = getUry(poly); 
           } 


           data.add(new TextUnit(blockText, llx, lly, urx, ury)); 
          } catch (NullPointerException e) { 
           //ignore - some polys has not X or Y coordinate if text located closed to bounds. 
          } 
         } 
        } 
       } 
      } 
      return data; 
     } 

méthodes d'assistance:

private float getLlx(BoundingPoly poly) { 
     try { 
      List<Vertex> vertices = poly.getVertices(); 

      ArrayList<Float> xs = new ArrayList<>(); 
      for (Vertex v : vertices) { 
       float x = 0; 
       if (v.getX() != null) { 
        x = v.getX(); 
       } 
       xs.add(x); 
      } 

      Collections.sort(xs); 
      float llx = (xs.get(0) + xs.get(1))/2; 
      return llx; 
     } catch (Exception e) { 
      return 0; 
     } 
    } 

    private float getLly(BoundingPoly poly) { 
     try { 
      List<Vertex> vertices = poly.getVertices(); 

      ArrayList<Float> ys = new ArrayList<>(); 
      for (Vertex v : vertices) { 
       float y = 0; 
       if (v.getY() != null) { 
        y = v.getY(); 
       } 
       ys.add(y); 
      } 

      Collections.sort(ys); 
      float lly = (ys.get(0) + ys.get(1))/2; 
      return lly; 
     } catch (Exception e) { 
      return 0; 
     } 
    } 

    private float getUrx(BoundingPoly poly) { 
     try { 
      List<Vertex> vertices = poly.getVertices(); 

      ArrayList<Float> xs = new ArrayList<>(); 
      for (Vertex v : vertices) { 
       float x = 0; 
       if (v.getX() != null) { 
        x = v.getX(); 
       } 
       xs.add(x); 
      } 

      Collections.sort(xs); 
      float urx = (xs.get(xs.size()-1) + xs.get(xs.size()-2))/2; 
      return urx; 
     } catch (Exception e) { 
      return 0; 
     } 
    } 

    private float getUry(BoundingPoly poly) { 
     try { 
      List<Vertex> vertices = poly.getVertices(); 

      ArrayList<Float> ys = new ArrayList<>(); 
      for (Vertex v : vertices) { 
       float y = 0; 
       if (v.getY() != null) { 
        y = v.getY(); 
       } 
       ys.add(y); 
      } 

      Collections.sort(ys); 
      float ury = (ys.get(ys.size()-1) +ys.get(ys.size()-2))/2; 
      return ury; 
     } catch (Exception e) { 
      return 0; 
     } 
    } 

    /** 
    * rotate rectangular clockwise 
    * 
    * @param poly 
    * @param theta the angle of rotation in radians 
    * @return 
    */ 
    public BoundingPoly rotate(float centerX, float centerY, BoundingPoly poly, double theta) { 

     List<Vertex> vertexList = poly.getVertices(); 

     //rotate all vertices in poly 
     for (Vertex vertex : vertexList) { 
      float tempX = vertex.getX() - centerX; 
      float tempY = vertex.getY() - centerY; 

      // now apply rotation 
      float rotatedX = (float) (centerX - tempX * cos(theta) + tempY * sin(theta)); 
      float rotatedY = (float) (centerX - tempX * sin(theta) - tempY * cos(theta)); 

      vertex.setX((int) rotatedX); 
      vertex.setY((int) rotatedY); 
     } 
     return poly; 
    } 

    /** 
    * since Google Vision Api returns boundingPoly-s when Coordinates starts from top left corner, 
    * but Itext uses coordinate system with bottom left start position - 
    * we need invert the result for continue to work with itext. 
    * 
    * @return text units inverted symmetrically by 0X coordinates. 
    */ 
    private BoundingPoly invertSymmetricallyBy0X(float centerY, BoundingPoly poly) { 

     List<Vertex> vertices = poly.getVertices(); 
     for (Vertex v : vertices) { 
      if (v.getY() != null) { 
       v.setY((int) (centerY + (centerY - v.getY()))); 
      } 
     } 
     return poly; 
    } 

    /** 
    * 
    * @param centerX 
    * @param poly 
    * @return text units inverted symmetrically by 0Y coordinates. 
    */ 
    private BoundingPoly invertSymmetricallyBy0Y(float centerX, BoundingPoly poly) { 
     List<Vertex> vertices = poly.getVertices(); 
     for (Vertex v : vertices) { 
      if (v.getX() != null) { 
       v.setX((int) (centerX + (centerX - v.getX()))); 
      } 
     } 
     return poly; 
    }