繁体   English   中英

Android:将位图保存到sdcard时,图像质量真的很差

[英]Android: Really bad image quality when saving bitmap to sdcard

我正在开发一个用于Android的OCR应用,它将对一些文本进行截图,识别并在Google上搜索关键字。 如果您还没有意识到,我正在尝试制作一个“ Google Now on Tap”克隆。

为了使OCR更好地工作,我首先旋转图像,然后过滤图像。 首先,摆脱状态栏和导航栏,然后将其转换为灰度,然后进行锐化。

但是对图像进行滤波后的图像质量非常像素化,这大大影响了OCR的准确性。

这是之前和之后的图片(仅是我收到的IFTTT电子邮件) 过滤之前过滤后

如您所见,之前的图像质量比经过过滤和旋转的图像要高得多。

这是我用于旋转,过滤和保存图像的代码:

首先获取屏幕截图,然后保存屏幕截图。

    public void getScreenshot()
    {
        try
        {
            Process sh = Runtime.getRuntime().exec("su", null, null);

            OutputStream os = sh.getOutputStream();
            os.write(("/system/bin/screencap -p " + _path).getBytes("ASCII"));
            os.flush();

            os.close();
            sh.waitFor();

            onPhotoTaken();

            Toast.makeText(this, "Screenshot taken", Toast.LENGTH_SHORT).show();
        }
        catch (IOException e)
        {
            System.out.println("IOException");
        }
        catch (InterruptedException e)
        {
            System.out.println("InterruptedException");
        }

    }

然后,旋转图像:

 protected void onPhotoTaken() { _taken = true; BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 4; Bitmap bitmap = BitmapFactory.decodeFile(_path, options); try { ExifInterface exif = new ExifInterface(_path); int exifOrientation = exif.getAttributeInt( ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); Log.v(TAG, "Orient: " + exifOrientation); int rotate = 0; switch (exifOrientation) { case ExifInterface.ORIENTATION_ROTATE_90: rotate = 90; break; case ExifInterface.ORIENTATION_ROTATE_180: rotate = 180; break; case ExifInterface.ORIENTATION_ROTATE_270: rotate = 270; break; } Log.v(TAG, "Rotation: " + rotate); if (rotate != 0) { // Getting width & height of the given image. int w = bitmap.getWidth(); int h = bitmap.getHeight(); // Setting pre rotate Matrix mtx = new Matrix(); mtx.preRotate(rotate); // Rotating Bitmap bitmap = Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, false); } // Convert to ARGB_8888, required by tess bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true); } catch (IOException e) { Log.e(TAG, "Couldn't correct orientation: " + e.toString()); } // _image.setImageBitmap( bitmap ); setImageFilters(bitmap); } 

然后,过滤图像:

public void setImageFilters(Bitmap bmpOriginal)
    {
        //Start by cropping image
        Bitmap croppedBitmap = ThumbnailUtils.extractThumbnail(bmpOriginal, 1080, 1420);

        //Then convert to grayscale
        int width, height;
        height = 1420;
        width = 1080;

        Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(bmpGrayscale);
        Paint paint = new Paint();
        ColorMatrix cm = new ColorMatrix();
        cm.setSaturation(0);
        ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
        paint.setColorFilter(f);
        c.drawBitmap(croppedBitmap, 0, 0, paint);

        //Finally, sharpen the image
        double weight = 11;
        double[][] sharpConfig = new double[][]
                {
                        { 0 ,   -2  , 0  },
                        { -2, weight, -2 },
                        { 0 ,   -2  , 0  }
                };

        ConvolutionMatrix convMatrix = new ConvolutionMatrix(3);
        convMatrix.applyConfig(sharpConfig);
        convMatrix.Factor = weight - 8;

        Bitmap filteredBitmap = ConvolutionMatrix.computeConvolution3x3(bmpGrayscale, convMatrix);

        //Start Optical Character Recognition
        startOCR(filteredBitmap);

        //Save filtered image
        saveFiltered(filteredBitmap);
    }

然后,保存过滤并旋转的图像:

public void saveFiltered(Bitmap filteredBmp) {
        try {
            ByteArrayOutputStream bytes = new ByteArrayOutputStream();
            filteredBmp.compress(Bitmap.CompressFormat.JPEG, 20, bytes);

            //You can create a new file name "test.jpg" in sdcard folder.
            File f = new File("/sdcard/SimpleAndroidOCR/ocrgray.jpg");
            f.createNewFile();
            //Write the bytes in file
            FileOutputStream fo = new FileOutputStream(f);
            fo.write(bytes.toByteArray());

            //Remember close the FileOutput
            fo.close();

        } catch (Exception e) {
            e.printStackTrace();

        }
    }

感谢您抽出宝贵的时间为您提供帮助。

它实际上在我的onPhotoTaken方法中。 截取屏幕截图并将其保存在get屏幕截图中之后,我将从文件保存到的位置读取文件,然后对其进行过滤。 我在onPhotoTaken方法中更改了这一行:

options.inSampleSize = 4options.inSampleSize = 1

看起来jpeg压缩确实使图像混乱。 尝试使用更适合于带有锐利边缘的图像(例如文本)的格式。 我会推荐png甚至gif。 您还可以存储未压缩的BMP。

Jpeg压缩通过利用以下事实进行工作:在大多数图片(自然,人,物体)中,人眼看不见锐利的边缘。 这对于存储尖锐的边缘内容(例如文本)确实非常不利。

同样,您的图像滤镜可以有效消除图像的抗锯齿,从而进一步降低可感知的图像质量。 但是,这可能就是您要执行的操作,因为这可能会使OCR变得更容易。

由于您上传的图片与网站上的图片大小相同,因此我也错过了采样大小。 Android文档中

如果设置为大于1的值,则请求解码器对原始图像进行二次采样,返回较小的图像以节省内存。 样本大小是任一维度中与已解码位图中单个像素相对应的像素数。 例如,inSampleSize == 4返回的图像为原始宽度/高度的1/4,像素数目的1/16。 任何小于等于1的值都与1相同。注意:解码器使用基于2的幂的最终值,任何其他值将四舍五入为最接近的2的幂。

设置options.inSampleSize = 4; 改为1将提高质量。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM