Android Camera 2: изображения ImageReader не имеют значений Stride
Я пытался направить изображения с камеры в ImageReader, чтобы я мог манипулировать изображениями напрямую с помощью Camera2 API. Когда у меня есть поток сеанса захвата в SurfaceView, поток работает просто отлично. Затем, когда я устанавливаю поток сеанса захвата на свой ImageReader, я замечаю, что изображения как-то недействительны.
В функции обратного вызова OnImageAvailable моего ImageReader я извлекаю следующее доступное изображение и пытаюсь прочитать его. Вот где у меня проблема. Изображение не является нулевым, и самолеты там, но буферы самолетов сначала равны нулю. Когда я пытаюсь получить буферы, они внезапно становятся не нулевыми, но при попытке чтения из них происходит сбой приложения без трассировки стека. Кроме того, шаг пикселя и строки в плоскостях устанавливаются на 0. Однако ширина и высота изображения установлены правильно.
Поэтому я считаю, что неправильно настраиваю ImageReader. Вопрос в том, что я делаю неправильно?
Код:
public class CompatibleCamera {
private static final int CAMERA2_API_LEVEL = 23;
public static final int FORMAT_RAW = ImageFormat.RAW_SENSOR;
public static final int FORMAT_JPEG = ImageFormat.JPEG;
private static final int MAX_IMAGES = 2;
// Interface for the user to use. User supplies the function to manipulate the image
public interface ImageTransform
{
void doTransform(Image image);
}
//***********Camera 2 API Members***********
// The camera2 API CameraManager. Used to access the camera device
private CameraManager mCamera2Manager;
// The information used by the device to reference the camera. Not a camera object itself
private CameraDevice mCamera2Device;
private String mCamera2DeviceID = "";
// The class that allows us to get the camera's image
private ImageReader mImageReader;
// This listener is where we have the programmer deal with the image. Just edit the interface
private ImageReader.OnImageAvailableListener mListener;
// This is the thread for the handler. It keeps it off the UI thread so we don't block the GUI
private HandlerThread mCameraCaptureHandlerThread;
// This runs in the background and handles the camera feed, activating the OnImageAvailableListener
private Handler mCameraCaptureHandler;
private HandlerThread mImageAvailableHandlerThread;
// This runs in the background and handles the camera feed, activating the OnImageAvailableListener
private Handler mImageAvailableHandler;
// This object is the camera feed, essentially. We store it so we can properly close it later
private CameraCaptureSession cameraCaptureSession;
// DEBUG
private boolean TEST_SURFACE_VIEW = false;
private Surface dbSurface;
// Mutex lock. Locks and unlocks when the ImageReader is pulling and processing an image
private Semaphore imageReaderLock = new Semaphore(1);
//***********Common Members***********
// The context of the activity holding this object
private Context mContext;
// Our ImageTransform implementation to alter the image as it comes in
private ImageTransform mTransform;
private int iImageFormat= FORMAT_RAW;
//==========Methods==========
public CompatibleCamera(Context context, ImageTransform transform, int imageFormat)
{
mContext = context;
mTransform = transform;
mListener = new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader imageReader) {
try {
imageReaderLock.acquire();
Image image = imageReader.acquireNextImage();
//<--------------Problem With Image is Here-------------->
mTransform.doTransform(image);
image.close();
imageReaderLock.release();
}
catch(InterruptedException ex)
{
ex.printStackTrace();
}
}
};
}
private boolean camera2GetManager()
{
//----First, get the CameraManager and a Camera Device----
mCamera2Manager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
if (mCamera2Manager == null) {
System.out.println(" DEBUG: Manager is null");
return false;
}
else {
System.out.println(" DEBUG: Camera Manager obtained");
try {
String[] cameraIDs = mCamera2Manager.getCameraIdList();
for (String cameraID : cameraIDs) {
CameraCharacteristics cameraCharacteristics = mCamera2Manager.getCameraCharacteristics(cameraID);
if (cameraCharacteristics.get(CameraCharacteristics.LENS_FACING) ==
CameraCharacteristics.LENS_FACING_BACK) {
mCamera2DeviceID = cameraID;
break;
}
}
if (mCamera2DeviceID.equals("")) {
System.out.println("No back camera, exiting");
return false;
}
System.out.println(" DEBUG: Camera Device obtained");
// Open the Camera Device
} catch (Exception ex) {
ex.printStackTrace();
return false;
}
return camera2OpenCamera();
}
}
private boolean camera2SetupImageReader()
{
// Get the largest image size available
CameraCharacteristics cameraCharacteristics;
try {
cameraCharacteristics= mCamera2Manager.getCameraCharacteristics(mCamera2DeviceID);
} catch(Exception e) {
e.printStackTrace();
return false;
}
StreamConfigurationMap map = cameraCharacteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
Size largestSize = Collections.max(
Arrays.asList(map.getOutputSizes(iImageFormat)),
new CompareSizesByArea());
// Set up the handler
mCameraCaptureHandlerThread = new HandlerThread("cameraCaptureHandlerThread");
mCameraCaptureHandlerThread.start();
mCameraCaptureHandler = new Handler(mCameraCaptureHandlerThread.getLooper());
mImageAvailableHandlerThread = new HandlerThread("imageReaderHandlerThread");
mImageAvailableHandlerThread.start();
mImageAvailableHandler = new Handler(mImageAvailableHandlerThread.getLooper());
mImageReader = ImageReader.newInstance( largestSize.getWidth(),
largestSize.getHeight(),
iImageFormat,
MAX_IMAGES);
mImageReader.setOnImageAvailableListener(mListener, mImageAvailableHandler);
// This callback is used to asynchronously set up the capture session on our end
final CameraCaptureSession.StateCallback captureStateCallback = new CameraCaptureSession.StateCallback() {
// When configured, set the target surface
@Override
public void onConfigured(@NonNull CameraCaptureSession session) {
try
{
CaptureRequest.Builder requestBuilder = session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
if (TEST_SURFACE_VIEW)
requestBuilder.addTarget(dbSurface);
else
requestBuilder.addTarget(mImageReader.getSurface());
//set to null - image data will be produced but will not receive metadata
session.setRepeatingRequest(requestBuilder.build(), null, mCameraCaptureHandler);
cameraCaptureSession = session;
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
System.out.println("Failed to configure the capture session :(");
}
};
ArrayList<Surface> surfaces = new ArrayList<>();
if (TEST_SURFACE_VIEW)
surfaces.add(dbSurface);
else
surfaces.add(mImageReader.getSurface());
try
{
mCamera2Device.createCaptureSession(surfaces, captureStateCallback, mCameraCaptureHandler);
}
catch(Exception ex)
{
ex.printStackTrace();
}
return true;
}
}
1 ответ
RAW_SENSOR - особый зверь форматов.
Общий необработанный формат изображения датчика камеры, обычно представляющий одноканальное мозаичное изображение Байера. Каждый образец цвета пикселя сохраняется с точностью до 16 бит.
Расположение цветной мозаики, максимальные и минимальные значения кодирования необработанных данных пикселей, цветовое пространство изображения и вся другая необходимая информация для интерпретации необработанного изображения датчика должны запрашиваться из android.hardware.camera2.CameraDevice, который произвел изображение.
Вы не должны пытаться использовать информацию о шагах напрямую, как если бы это был кадр YUV.