【问题标题】:How Can I Capture Multiple Images and send the images to next Activity and display them using CameraX [Android Studio]如何捕获多个图像并将图像发送到下一个活动并使用 CameraX [Android Studio] 显示它们
【发布时间】:2020-10-20 05:54:34
【问题描述】:

我正在使用最新的相机X

def camerax_version = "1.0.0-beta11"

我可以使用以下代码拍照并将图像保存到文件夹中的外部存储

File photoFile = new File(outputDirectory, "Image_" + System.currentTimeMillis() + ".jpg");

            ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions.Builder(photoFile).build();

            imageCapture.takePicture(outputFileOptions, ContextCompat.getMainExecutor(getBaseContext()), new ImageCapture.OnImageSavedCallback() {
                @Override
                public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
                    Uri.fromFile(photoFile);
                    Toast.makeText(getBaseContext(), "Image Saved" + photoFile.getAbsolutePath(), Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onError(@NonNull ImageCaptureException exception) {
                    Toast.makeText(getBaseContext(), "Error Saving Image" + photoFile.getAbsolutePath(), Toast.LENGTH_SHORT).show();
                }
            });

现在的重点是如何在将图像保存到外部存储之前提取图像。我想要实现的是捕获多个图像并将其保存在缓冲区中并将这些图像发送到下一个 Activity 并使用列表或其他方式将它们显示在 imageView 中。

现在这可以在imageCapture 上使用onImageCapturedCallback 来实现,这给了我一个ImageProxy,然后它必须转换为字节数组。但是这个过程只适用于小尺寸和单一图像。 如何才能为更高分辨率和多张图片实现这一目标

下面是我用来捕获ImageProxy 并将 imageCapture 设置为“YUV”的代码,遗憾的是它根本不起作用

    imageCapture.takePicture(ContextCompat.getMainExecutor(getBaseContext()), new ImageCapture.OnImageCapturedCallback() {
        @Override
        public void onCaptureSuccess(@NonNull ImageProxy image) {
            super.onCaptureSuccess(image);
            @SuppressLint("UnsafeExperimentalUsageError") Image cimage = image.getImage();
            Image.Plane[] planes = cimage.getPlanes();
            ByteBuffer yBuffer = planes[0].getBuffer();
            ByteBuffer uBuffer = planes[1].getBuffer();
            ByteBuffer vBuffer = planes[2].getBuffer();

            int ySize = yBuffer.remaining();
            int uSize = uBuffer.remaining();
            int vSize = vBuffer.remaining();

            byte[] nv21 = new byte[ySize + uSize + vSize];

            yBuffer.get(nv21,0,ySize);
            vBuffer.get(nv21,ySize,vSize);
            uBuffer.get(nv21,ySize + vSize,uSize);

            YuvImage yuvImage = new YuvImage(nv21,ImageFormat.NV21,cimage.getWidth(),cimage.getHeight(),null);
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            yuvImage.compressToJpeg(new Rect(0,0,yuvImage.getWidth(),yuvImage.getHeight()),100,out);
            byte[] imageBytes = out.toByteArray();

            Intent intent = new Intent(MainActivity.this,MainActivity2.class);
            intent.putExtra("image",imageBytes);
            MainActivity.this.startActivity(intent);

        }

        @Override
        public void onError(@NonNull ImageCaptureException exception) {
            super.onError(exception);
        }
    });

我可以将图片添加到ArrayList,然后发送过来吗?

提前致谢..

【问题讨论】:

  • 我建议将图像转换为位图,然后使用 ImageProxy.close 获取下一帧并捕获它,然后将所有位图保存到 ArrayList 中,然后您可以显示它们。
  • @mmdrezabaqalpour 那么我可以使用 Intent.putExtra(); 将这些位图发送到新 Activity 吗?
  • 是的,只要位图是一个包裹对象,您就可以按意图发送它。 intent.putParcelableArrayListExtra()
  • @mmdrezabaqalpour 在 ImageCaptureCallback 期间,我必须将 imageCapture 设置为 YUV 格式才能将图像转换为位图。这会显着降低图像质量。有什么办法吗..
  • 如果对您有用,我会发布一些方法作为答案。

标签: java android android-studio android-camerax


【解决方案1】:

我为我的项目做了两种方法。代码是 kotlin 语言。 你可以很容易地理解它。

val image = imageProxy.image
val bitmap = Bitmap.createBitmap(image.width, image.height, 
Bitmap.Config.ARGB_8888)

如果它不起作用,您可以使用 YuvtoRgbConvertor 如果您愿意,我有完整的 kotlin 代码,或者您可以编写自己的代码。然后你可以像这样转换位图。

val convertor = YuvToRgbConvertor
convertor.yuvToRgb(image , bitmap)

这就是我为我的项目所做的。

【讨论】:

    【解决方案2】:

    我建议您存储在数组列表中。然后将数组列表传递给其他活动。

    你要做的是创建一个数组列表并将uri.tostring存储在数组列表中

    String newurl=uri.toString
    `arraylist.add(newurl)`
    

    这样您可以在 ArrayList 中添加多个图像 URL 并在 Picasso 库的帮助下显示。无需从数据库中获取图像。

    【讨论】:

      【解决方案3】:

      我找到的最简单的方法是这个

      preview.setOnClickListener(new View.OnClickListener() {
                  @Override
                  public void onClick(View v) {
                      Bitmap scaledBitmap = null;
      
                      ContextWrapper cw = new ContextWrapper(getApplicationContext());
                      String PATH = Environment.getExternalStorageDirectory() + "/download/";
                      File file = new  File(PATH + "myImage.jpeg");
      
                      if (file.exists()) {
                          myImage.setImageDrawable(Drawable.createFromPath(file.toString()));
                      }
                      else {
                          myImage.setImageDrawable(Drawable.createFromPath(null));
                          Toast.makeText(nextPage.this, "Not found", Toast.LENGTH_LONG).show();
                      }
                  }
              });
      

      您可以根据您的代码更改路径。

      【讨论】:

        【解决方案4】:

        首先你需要在 takepicture 回调中关闭图像。close() 将关闭当前图像。全局创建 ArrayList 并将 imageURL 添加到 arraylist 中。在 theat 之后,您可以按意图将数组列表发送到任何活动。

         imageCapture.takePicture(ContextCompat.getMainExecutor(getBaseContext()), new ImageCapture.OnImageCapturedCallback() {
            @Override
            public void onCaptureSuccess(@NonNull ImageProxy image) {
                super.onCaptureSuccess(image);
                @SuppressLint("UnsafeExperimentalUsageError") Image cimage = image.getImage();
                Image.Plane[] planes = cimage.getPlanes();
                ByteBuffer yBuffer = planes[0].getBuffer();
                ByteBuffer uBuffer = planes[1].getBuffer();
                ByteBuffer vBuffer = planes[2].getBuffer();
        
                int ySize = yBuffer.remaining();
                int uSize = uBuffer.remaining();
                int vSize = vBuffer.remaining();
        
                byte[] nv21 = new byte[ySize + uSize + vSize];
        
                yBuffer.get(nv21,0,ySize);
                vBuffer.get(nv21,ySize,vSize);
                uBuffer.get(nv21,ySize + vSize,uSize);
        
                YuvImage yuvImage = new YuvImage(nv21,ImageFormat.NV21,cimage.getWidth(),cimage.getHeight(),null);
                ByteArrayOutputStream out = new ByteArrayOutputStream();
                yuvImage.compressToJpeg(new Rect(0,0,yuvImage.getWidth(),yuvImage.getHeight()),100,out);
                byte[] imageBytes = out.toByteArray();
        
                Intent intent = new Intent(MainActivity.this,MainActivity2.class);
                intent.putExtra("image",imageBytes);
                MainActivity.this.startActivity(intent);
                image.close();
            }
        
            @Override
            public void onError(@NonNull ImageCaptureException exception) {
                super.onError(exception);
            }
        });
        

        我想这会对你有所帮助,有任何疑问refer here

        这是ImageProxy转位图的函数

         // output of the image capture image proxy to bitmap
        public Bitmap imageProxyToBitmap(ImageProxy image) {
            ByteBuffer buffer = image.getPlanes()[0].getBuffer();
            buffer.rewind();
            byte[] bytes = new byte[buffer.capacity()];
            buffer.get(bytes);
            byte[] clonedBytes = bytes.clone();
            return BitmapFactory.decodeByteArray(clonedBytes, 0, clonedBytes.length);
        }
        

        并将位图保存到本地存储

            // used for save the files internal storage , can view in the gallery or internal storage
        public String saveTOInternamMemory(Activity activity, Bitmap bitmapImage){
        
            File myPath = getInternalStorageDir(internalStorageDir,imageFormat,Environment.DIRECTORY_PICTURES);
        
            Log.d(TAG, "directory: " + myPath.getAbsolutePath());
        
            FileOutputStream fos = null;
            try {
                fos = new FileOutputStream(myPath);
                // Use the compress method on the BitMap object to write image to the OutputStream
                bitmapImage.compress(Bitmap.CompressFormat.PNG, 100, fos);
                Log.d(TAG, "bit exception: Success" );
            } catch (Exception e) {
                Log.d(TAG, "bit exception: " + e.getMessage());
                e.printStackTrace();
            } finally {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    Log.d(TAG, "io exce: " + e.getMessage());
                }
            }
            Log.d(TAG, "absolute path " + myPath.getAbsolutePath());
            return myPath.getAbsolutePath();
        }
        

        【讨论】:

        • 如果您要链接到您的博客(特别是如果您在多个答案中这样做),您必须在您的答案中声明您的从属关系,否则您的帖子可能会被标记为垃圾邮件。请阅读How Not to be a Spammer
        • 嗨查理·里奥。如果您收到类似上述的反馈,然后编辑您的帖子而不对其做出反应(例如,提供或指出与上述怀疑相矛盾的信息),您给人的印象可能是您故意按照向您指出的事情。
        • @DavidBuck 我错过了链接是拥有网络内容的指标。你能启发我吗?
        • 嗨@DavidBuck 感谢您提供的信息。我会在以后的帖子中检查并使用它。
        • 嗨@Yunnosch,对不起,我不明白你在说什么? ..我是在这里给出答案的新手。
        猜你喜欢
        • 1970-01-01
        • 2011-12-15
        • 1970-01-01
        • 1970-01-01
        • 2014-11-29
        • 2014-07-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多