2016-09-12 2 views
1

추적 용으로 시각적 API를 사용하고 있습니다. 얼굴 위치 기준으로 마스크를 적용했습니다. 전 카메라에서 사진을 찍을 때 카메라 소스를 호출합니다. 사진()은 이미지를 저장합니다. 저는 삼성과 같은 일부 장치에서 이미지 회전 문제를 겪고 있으며 마스크와 얼굴을 보여줍니다. Exif 클래스를 사용하여 이미지의 방향을 가져 오지만 이미지를 회전시킬 수 없으므로 항상 0을 반환합니다. getOrientation 및 이미지 회전에 다음 클래스를 사용하고 있습니다.camerasource.takePicture() 일부 기기에서 회전 된 이미지 저장

public class ExifUtils { 
public Bitmap rotateBitmap(String src, Bitmap bitmap) { 
    try { 
     int orientation = getExifOrientation(src); 

     if (orientation == 1) { 
      return bitmap; 
     } 

     Matrix matrix = new Matrix(); 
     switch (orientation) { 
      case 2: 
       matrix.setScale(-1, 1); 
       break; 
      case 3: 
       matrix.setRotate(180); 
       break; 
      case 4: 
       matrix.setRotate(180); 
       matrix.postScale(-1, 1); 
       break; 
      case 5: 
       matrix.setRotate(90); 
       matrix.postScale(-1, 1); 
       break; 
      case 6: 
       matrix.setRotate(90); 
       break; 
      case 7: 
       matrix.setRotate(-90); 
       matrix.postScale(-1, 1); 
       break; 
      case 8: 
       matrix.setRotate(-90); 
       break; 
      default: 
       return bitmap; 
     } 

     try { 
      Bitmap oriented = Bitmap.createBitmap(bitmap, 0, 0, 
        bitmap.getWidth(), bitmap.getHeight(), matrix, true); 
      bitmap.recycle(); 
      return oriented; 
     } catch (OutOfMemoryError e) { 
      e.printStackTrace(); 
      return bitmap; 
     } 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 

    return bitmap; 
} 

private int getExifOrientation(String src) throws IOException { 
    int orientation = 1; 

    try { 

     if (Build.VERSION.SDK_INT >= 5) { 
      Class<?> exifClass = Class 
        .forName("android.media.ExifInterface"); 
      Constructor<?> exifConstructor = exifClass 
        .getConstructor(new Class[]{String.class}); 
      Object exifInstance = exifConstructor 
        .newInstance(new Object[]{src}); 
      Method getAttributeInt = exifClass.getMethod("getAttributeInt", 
        new Class[]{String.class, int.class}); 
      Field tagOrientationField = exifClass 
        .getField("TAG_ORIENTATION"); 
      String tagOrientation = (String) tagOrientationField.get(null); 
      orientation = (Integer) getAttributeInt.invoke(exifInstance, 
        new Object[]{tagOrientation, 1}); 

     } 
    } catch (ClassNotFoundException e) { 
     e.printStackTrace(); 
    } catch (SecurityException e) { 
     e.printStackTrace(); 
    } catch (NoSuchMethodException e) { 
     e.printStackTrace(); 
    } catch (IllegalArgumentException e) { 
     e.printStackTrace(); 
    } catch (Fragment.InstantiationException e) { 
     e.printStackTrace(); 
    } catch (IllegalAccessException e) { 
     e.printStackTrace(); 
    } catch (InvocationTargetException e) { 
     e.printStackTrace(); 
    } catch (NoSuchFieldException e) { 
     e.printStackTrace(); 
    } catch (java.lang.InstantiationException e) { 
     e.printStackTrace(); 
    } 

    return orientation; 
} 

}

나는 비전 API에서이 issue 어떤 해결책이 발견했다.

+0

비전 API 문제에 대한 덧글을 참조하십시오. 프레임 메타 데이터에서 방향을 얻을 수 있습니다. – pm0733464

+0

감사합니다. @ pm0733464 예제를 제공해주십시오. –

+0

나는 내 문제를 풀어 내 비전 API를 issue.https : //github.com/googlesamples/android-vision/issues/124에 대한 덧글을 참조하십시오 –

답변

1

나에게 Exif 태그 문제와 같은 소리가납니다. 기본적으로 현대 카메라는 같은 방향으로 이미지를 저장하지만 원본 오리엔테이션이 무엇인지 알려주는 태그도 저장합니다.

java api와 함께 제공되는 Exif Interface을 사용할 수 있습니다. 나는 내 프로젝트에서 안드로이드 EXIF ​​인터페이스를 사용하는 방법

주위에 filepaths을 유지하기 위해 당신을 필요로하지 않는, Alessandro Crugnola's Android-Exif-Interface library을 선호 :

ExifInterface exif = new ExifInterface(); 
Matrix matrix = new Matrix(); 
try { 
    exif.readExif(context.getContentResolver().openInputStream(fileUri), ExifInterface.Options.OPTION_ALL); 
    ExifTag tag = exif.getTag(ExifInterface.TAG_ORIENTATION); 
    int orientation = tag.getValueAsInt(1); 
    switch (orientation) { 
     case 3: /* 180° */ 
      matrix.postRotate(180); 
      break; 
     case 6: /* 90° */ 
      matrix.postRotate(90); 
      break; 
     case 8: /* 270° */ 
      matrix.postRotate(-90); 
      break; 
    } 
} catch (IOException e) { 
    Log.i("INFO","expected behaviour: IOException"); 
    //not every picture comes from the phone, should that be the case, 
    // we can't get exif tags anyway, since those aren't being transmitted 
    // via http (atleast I think so. I'd need to save the picture on the SD card to 
    // confirm that and I don't want to do that) 
} catch(NullPointerException e){ 
    Log.i("INFO","expected behaviour: NullPointerException"); 
    //same as above, not every picture comes from the phone 
} 
+0

나는 더 많은 코드를 시도했지만 때마다 내가 오리엔테이션 0을 얻을 수 없습니다 이미지를 회전하는 삼성 전자 장치 에서이 문제에 직면하고있다. –

+0

방향을 잡는 데 사용하는 코드를 게시 할 수 있습니까? 그것없이 많은 것을 말하기 어렵다 – TormundThunderfist

+0

나는 위의 코드를 언급했다. –

0

것은 내가 삼성 장치와 비슷한 문제가 발생했습니다, ExifInterface하지 않습니다 그 (것)들에 의해 저장된 심상을 사용하여 정확하게 작동하는 것을 보인다. 글라이드 이미지 라이브러리에서 코드를 사용하여 문제를 해결하기 위해 원본 이미지 회전을 올바르게 확인하는 것으로 보입니다. 이 링크 밖으로

확인 : 대부분의 시간을 일을 할 것 같다에서 Glide source

getOrientation 방법.

1

직접 문제를 해결합니다. 바이트 데이터에서 방향을 얻은 다음 방향에 따라 이미지를 회전합니다.

private CameraSource.PictureCallback mPicture = new CameraSource.PictureCallback() { 
    @Override 
    public void onPictureTaken(byte[] bytes) { 
     int orientation = Exif.getOrientation(bytes); 
     Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); 
     switch(orientation) { 
      case 90: 
       bitmapPicture= rotateImage(bitmap, 90); 

       break; 
      case 180: 
       bitmapPicture= rotateImage(bitmap, 180); 

       break; 
      case 270: 
       bitmapPicture= rotateImage(bitmap, 270); 

       break; 
      case 0: 
      // if orientation is zero we don't need to rotate this 

      default: 
       break; 
     } 
      //write your code here to save bitmap 
     } 

    } 

}; 
    public static Bitmap rotateImage(Bitmap source, float angle) { 
    Matrix matrix = new Matrix(); 
    matrix.postRotate(angle); 
    return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, 
      true); 
    } 

아래의 클래스는 byte [] 데이터에서 방향을 가져 오는 데 사용됩니다.

public class Exif { 
private static final String TAG = "CameraExif"; 

// Returns the degrees in clockwise. Values are 0, 90, 180, or 270. 
public static int getOrientation(byte[] jpeg) { 
    if (jpeg == null) { 
     return 0; 
    } 

    int offset = 0; 
    int length = 0; 

    // ISO/IEC 10918-1:1993(E) 
    while (offset + 3 < jpeg.length && (jpeg[offset++] & 0xFF) == 0xFF) { 
     int marker = jpeg[offset] & 0xFF; 

     // Check if the marker is a padding. 
     if (marker == 0xFF) { 
      continue; 
     } 
     offset++; 

     // Check if the marker is SOI or TEM. 
     if (marker == 0xD8 || marker == 0x01) { 
      continue; 
     } 
     // Check if the marker is EOI or SOS. 
     if (marker == 0xD9 || marker == 0xDA) { 
      break; 
     } 

     // Get the length and check if it is reasonable. 
     length = pack(jpeg, offset, 2, false); 
     if (length < 2 || offset + length > jpeg.length) { 
      Log.e(TAG, "Invalid length"); 
      return 0; 
     } 

     // Break if the marker is EXIF in APP1. 
     if (marker == 0xE1 && length >= 8 && 
       pack(jpeg, offset + 2, 4, false) == 0x45786966 && 
       pack(jpeg, offset + 6, 2, false) == 0) { 
      offset += 8; 
      length -= 8; 
      break; 
     } 

     // Skip other markers. 
     offset += length; 
     length = 0; 
    } 

    // JEITA CP-3451 Exif Version 2.2 
    if (length > 8) { 
     // Identify the byte order. 
     int tag = pack(jpeg, offset, 4, false); 
     if (tag != 0x49492A00 && tag != 0x4D4D002A) { 
      Log.e(TAG, "Invalid byte order"); 
      return 0; 
     } 
     boolean littleEndian = (tag == 0x49492A00); 

     // Get the offset and check if it is reasonable. 
     int count = pack(jpeg, offset + 4, 4, littleEndian) + 2; 
     if (count < 10 || count > length) { 
      Log.e(TAG, "Invalid offset"); 
      return 0; 
     } 
     offset += count; 
     length -= count; 

     // Get the count and go through all the elements. 
     count = pack(jpeg, offset - 2, 2, littleEndian); 
     while (count-- > 0 && length >= 12) { 
      // Get the tag and check if it is orientation. 
      tag = pack(jpeg, offset, 2, littleEndian); 
      if (tag == 0x0112) { 
       // We do not really care about type and count, do we? 
       int orientation = pack(jpeg, offset + 8, 2, littleEndian); 
       switch (orientation) { 
        case 1: 
         return 0; 
        case 3: 
         return 180; 
        case 6: 
         return 90; 
        case 8: 
         return 270; 
       } 
       Log.i(TAG, "Unsupported orientation"); 
       return 0; 
      } 
      offset += 12; 
      length -= 12; 
     } 
    } 

    Log.i(TAG, "Orientation not found"); 
    return 0; 
} 

private static int pack(byte[] bytes, int offset, int length, 
         boolean littleEndian) { 
    int step = 1; 
    if (littleEndian) { 
     offset += length - 1; 
     step = -1; 
    } 

    int value = 0; 
    while (length-- > 0) { 
     value = (value << 8) | (bytes[offset] & 0xFF); 
     offset += step; 
    } 
    return value; 
} 
}