2015-03-04 26 views
8

Wdrażam aplikację, która wykorzystuje przetwarzanie obrazu w czasie rzeczywistym na żywo z aparatu. To działa, z ograniczeniami, używając teraz przestarzałego android.hardware.Camera; dla większej elastyczności & wydajność Chciałbym użyć nowego API android.hardware.camera2. Mam problemy z uzyskaniem danych obrazu surowego do przetworzenia. To jest na Samsung Galaxy S5. (Niestety, nie mam innego urządzenia Lollipop do przetestowania na innym sprzęcie).Dane obrazu z kamery Android2 API przerzucone i zgniecione na urządzeniu Galaxy S5

Mam ogólne ramy (z inspiracji z próbek "HdrViewFinder" i "Camera2Basic"), a obraz na żywo rysowany jest na ekranie za pomocą SurfaceTexture i GLSurfaceView. Muszę jednak uzyskać dostęp do danych obrazu (tylko skala szarości wystarcza, przynajmniej na razie) do niestandardowego przetwarzania obrazu. Zgodnie z dokumentacją pod numerem StreamConfigurationMap.isOutputSupportedFor(class) zalecaną powierzchnią do bezpośredniego uzyskania danych obrazu byłaby ImageReader (poprawna?).

Więc mam skonfigurować moje prośby uchwycić jak:

mSurfaceTexture.setDefaultBufferSize(640, 480); 
mSurface = new Surface(surfaceTexture); 
... 
mImageReader = ImageReader.newInstance(640, 480, format, 2); 
... 
List<Surface> surfaces = new ArrayList<Surface>(); 
surfaces.add(mSurface); 
surfaces.add(mImageReader.getSurface()); 
... 
mCameraDevice.createCaptureSession(surfaces, mCameraSessionListener, mCameraHandler); 

aw onImageAvailable zwrotnego dla ImageReader, mam dostęp do danych w następujący sposób:

Image img = reader.acquireLatestImage(); 
ByteBuffer grayscalePixelsDirectByteBuffer = img.getPlanes()[0].getBuffer(); 

... ale chociaż (jak powiedziano) działa podgląd obrazu na żywo, coś jest nie tak z danymi, które tu dostaję (lub sposobem, w jaki je dostaję). Według

mCameraInfo.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputFormats(); 

... być obsługiwane następujące ImageFormats powinien: NV21, JPEG, YV12, YUV_420_888. Próbowałem wszystkich (podłączony do „formatu” powyżej), wszystkie obsługują rozdzielczość ustawiona zgodnie getOutputSizes(format), ale żaden z nich nie dać pożądanego rezultatu:

  • NV21: ImageReader.newInstance rzuca java.lang.IllegalArgumentException : Format NV21 nie jest obsługiwany
  • JPEG: To działa, ale nie wydaje się, aby aplikacja działająca w czasie rzeczywistym przechodziła kodowanie i dekodowanie JPEG dla każdej klatki ...
  • YV12 i YUV_420_888: to jest najdziwniejszy wynik - widzę obraz w skali szarości, ale jest on odwrócony pionowo (tak, odwrócony, nie obrócony!) i znacząco zgnieciony (skalowany znacznie w poziomie, ale nie pionowo).

Czego mi tu brakuje? Co powoduje, że obraz jest odwracany i zgniatany? Jak mogę uzyskać geometrycznie poprawny bufor skali szarości? Czy powinienem używać innego rodzaju powierzchni (zamiast ImageReadera)?

Wszelkie wskazówki są mile widziane.

+0

Po dodaniu dwóch obiektów Target do obróbki ramek nieprzetworzonych, otrzymujesz nieprzerwanie ramki. Aktualizuję też moją aplikację na Api 2, ale zamarza ona aplikację dodając dwa wyjściowe cele. mPreviewRequestBuilder.addTarget (powierzchnia); mPreviewRequestBuilder.addTarget (mImageReader.getSurface()); – user1154390

Odpowiedz

4

Znalazłem wyjaśnienie (choć niekoniecznie satysfakcjonujące rozwiązanie): okazuje się, że stosunek matrycy matrycy wynosi 16: 9 (znaleziony przez mCameraInfo.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);).

Przynajmniej przy żądaniu YV12/YUV_420_888, streamer wydaje się nie przycinać obrazu w żaden sposób, ale zamiast tego skalować go nierównomiernie, aby osiągnąć żądany rozmiar ramki. Obrazy mają prawidłowe proporcje, gdy żądają formatu 16: 9 (z czego niestety są tylko dwie wyższe). Wydaje mi się to trochę dziwne - wydaje się, że nie ma to miejsca w przypadku żądania plików JPEG lub równoważnych funkcji starego aparatu API lub zdjęć; i nie jestem pewien, na czym nieporównywalnie skalowane ramki byłyby dobre.

Uważam, że nie jest to naprawdę satysfakcjonujące rozwiązanie, ponieważ oznacza to, że nie można polegać na liście formatów wyjściowych, należy zamiast tego najpierw znaleźć rozmiar czujnika, znaleźć formaty o tym samym współczynniku kształtu, a następnie zmniejszyć obraz sam (w razie potrzeby) ...

Nie wiem, czy jest to oczekiwany wynik tutaj, czy "funkcja" S5. Komentarze i sugestie nadal są mile widziane.

+1

To samo dzieje się na Moto X 2014. Wciąż na to patrzę, ale domyślam się, że to zachowanie dla każdego urządzenia, które używa starszej wersji Camera2. –

+0

Dobrze wiedzieć, dzięki. Czy ktokolwiek może potwierdzić, że tak się nie dzieje, na przykład Nexus 6 ...? –

+1

Działa dobrze na Nexusie 5, który ma "ograniczony" poziom wsparcia dla kamery2. –

0

Miałem ten sam problem i znalazłem rozwiązanie. Pierwsza część tego problemu jest ustawienie rozmiaru bufora powierzchni:

// We configure the size of default buffer to be the size of camera preview we want. 
    //texture.setDefaultBufferSize(width, height); 

To jest, gdy obraz zostanie pochylona, ​​a nie w aparacie. Powinieneś to skomentować, a następnie ustawić przeskalowanie obrazu podczas jego wyświetlania.

  int[] rgba = new int[width*height]; 
      //getImage(rgba); 
      nativeLoader.convertImage(width, height, data, rgba); 

      Bitmap bmp = mBitmap; 
      bmp.setPixels(rgba, 0, width, 0, 0, width, height); 

      Canvas canvas = mTextureView.lockCanvas(); 

      if (canvas != null) { 
       //canvas.drawBitmap(bmp, 0, 0, null);//configureTransform(width, height), null); 
       //canvas.drawBitmap(bmp, configureTransform(width, height), null); 
       canvas.drawBitmap(bmp, new Rect(0,0,320,240), new Rect(0,0, 640*2,480*2), null); 

       //canvas.drawBitmap(bmp, (canvas.getWidth() - 320)/2, (canvas.getHeight() - 240)/2, null); 

       mTextureView.unlockCanvasAndPost(canvas); 
      } 

      image.close(); 

Możesz odtwarzać z wartościami, aby dostosować rozwiązanie swojego problemu.

+1

TIL setDefaultBufferSize jest zły –