How to check if Image Quality is Low - java

I am developing a PhotoBook app where I need to notify the user if they add a low-resolution image. I just need to show a "Low-Resolution Image, Printing may be affected" warning as chatbooks app do.

int file_size = Integer.parseInt(String.valueOf(file.length() / 1024));
if (file_size < 100){
Log.v(TAG, "Low resolution image");
}else{
Log.v(TAG, "");
}

you can convert image into bitmap and check its height and width and with this its help you to check the image resolution.
if image is from drawable,
Bitmap bmp = BitmapFactory.decodeResource(res, R.drawable.back);
bmp.getWidth(), bmp.getHeight();
if image from uri
Uri imageUri = data.getData();
Bitmap bitmap =
MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageUri);
bitmap.getWidth(), bmp.getHeight();
make a validation if image height and width less than your need than show your alert

If you have a Bitmap object, you can check for bitmap.getWidth() and getHeigth()

You can check the width and height of the image and thus you can decide which resolution is appropriate to classify it as low quality.
public void checkQuality() {
String filePathTmp = new File("").getAbsolutePath();//getCanonicalPath();
//notice you must use you image path
Path filePath = Paths.get(filePathTmp, "\\YOUR\\PARTH\\IMAGE.png").normalize();
ImageIcon imageIcon = new ImageIcon(filePath.toString());
int height = imageIcon.getIconHeight();
int width = imageIcon.getIconWidth();
System.out.println("HEIGHT: " + height + "--" + "WIDTH" + width);
//change values, consider your own criteria low quality
if (height <100 || width <100){
System.out.println("Low quality");
}
}

Related

how to get runtime width and height of a compundDrawable

I want to know the runtime width and height of a compoundDrawble.
I have tried to use layout inspector, but it shows the height of the text box + drawable.
ViewObserverTree won't help to separate the frawble and the text
to get only the drawable height.
I have also tried drawable.getBounds()
but it will give me the compile time height and width.
Drawable[] compoundDrawablesRelative = TextViewCompat
.getCompoundDrawablesRelative(targetTextView);
drawable.getBounds().
How would you get the runtime values (in pd and pxl)
Drawable[] drawables = textView.getCompoundDrawables();
Bitmap myBitmap = ((BitmapDrawable)drawables[1] ).getBitmap();
//Bitmap myBitmap = ((BitmapDrawable )imageView.getDrawable()).getBitmap();
int width = myBitmap .getWidth();
int height = myBitmap .getHeight();
try this code

Android bitmap - out of memory

I have a problem with a function that I implemented. On some phones I get a out of memory error.
private Bitmap getIconMarkerOfPlayer(Player p) {
Drawable drawable = getIconOfPlayer(p);
Bitmap img = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_4444);
Canvas canvas = new Canvas(img);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
drawable.draw(canvas);
final float scale = this.getResources().getDisplayMetrics().density;
int heigthPixels = (int) (24 * scale + 0.5f);
int widthPixels = (int) (24 * scale + 0.5f);
return Bitmap.createScaledBitmap(img, widthPixels, heigthPixels, false);
}
The getIconMarkerOfPlayer(Player p) function gives a "programmed" drawable depending on the player's status (dead, alive, offline, ...) and its color. Each player has a unique color assigned to it in the early games.
How can I resize my bitmap from a Drawable object without having a out of memory error?
I suggest you to use some ImageLibraries to load Bitmaps efficiently.
Some of them are Fresco, Glide, Piccasio.
I suggest you to go with Glide. Have a look at it here

Android: Really bad image quality when saving bitmap to sdcard

I am making an OCR app for Android, that will take a screenshot of some text, recognise it and search a key word on Google. If you haven't already realized, I'm trying to make a "Google Now on Tap" clone.
To make the OCR work better, I am first rotating the image, then filtering the image. First by getting rid of the status bar and the navigation bar, then converting it to grayscale, then sharpening.
But the image quality after filtering the image is extremely pixelated, and this greatly effects OCR accuracy.
Here are the images, before and after (just of an IFTTT email I got)
As you can see, the before image is much higher quality than the filtered and rotated one.
Here is my code for rotating, filtering and saving the image:
Firstly taking screenshot, then saving the screenshot.
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");
}
}
Then, rotate the image:
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);
}
Then, filter the image:
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);
}
Then, saving the filtered and rotated image:
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();
}
}
Thanks heaps for anyone taking the time to help.
It was actually in my onPhotoTaken method. After taking and saving the screenshot in get screenshot, I am reading the file from the location it was saved to, then filtering it. I changed this line in the onPhotoTaken method:
options.inSampleSize = 4 to options.inSampleSize = 1
It does look like the jpeg compression is messing the image up. Try using a format better suited for images with sharp edges, such as of text. I would recommend png or even gif. You could also store the uncompressed BMP.
Jpeg compression works by exploiting the fact that in most pictures (nature, people, objects), sharp edges are not that visible to the human eye. This makes it really bad for storing sharp edged content, such as text.
Also, your image filter is effectively removing the anti-aliasing of the image, which further decreases the perceived image quality. That might be what you want to do, however, since it might make OCR easier.
I also missed the sampling size due to the images you uploaded being the same size here on the site. From the Android documentation:
If set to a value > 1, requests the decoder to subsample the original
image, returning a smaller image to save memory. The sample size is
the number of pixels in either dimension that correspond to a single
pixel in the decoded bitmap. For example, inSampleSize == 4 returns an
image that is 1/4 the width/height of the original, and 1/16 the
number of pixels. Any value <= 1 is treated the same as 1. Note: the
decoder uses a final value based on powers of 2, any other value will
be rounded down to the nearest power of 2.
Setting options.inSampleSize = 4; to 1 instead will increase the quality.

Decode a part of Bitmap from file in Android

I have a file with a very large image: for example 9000x9000.
I can't load the Bitmap in memory because the heap size. But I only need to display a small part of this bitmap for example the rect width=100-200 and height =200-400 (resulting size of the sub-bitmap =100x200)
How can I retrieve this bitmap from the file?
Note: I dont want to lose quality in the 100x200 image
Thanks
is it possible that there is a solution for this?
for example , BitmapRegionDecoder .
It should work for API10 and above...
Usage:
BitmapRegionDecoder.newInstance(...).decodeRegion(...)
It can easily be done using RapidDecoder.
I actually generated a 9000x9000 png which its file size is about 80MB and the 200x400 sized region was successfully loaded.
import rapid.decoder.BitmapDecoder;
Bitmap bitmap = BitmapDecoder.from("big-image.png")
.region(145, 192, 145 + 200, 192 + 400)
.decode();
imageView.setImageBitmap(bitmap);
It works for Android 2.2 and above.
I think that you can use the BitmapFactory method that allows you to specify the Rect that you want to decode.
public static Bitmap decodeStream (InputStream is, Rect outPadding, BitmapFactory.Options opts)
Try this code:
public static Bitmap decodeSampledBitmapFromFile(String path, int reqWidth, int reqHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
final int height = options.outHeight;
final int width = options.outWidth;
options.inPreferredConfig = Bitmap.Config.RGB_565;
int inSampleSize = 1;
if (height > reqHeight) {
inSampleSize = Math.round((float) height / (float) reqHeight);
}
int expectedWidth = width / inSampleSize;
if (expectedWidth > reqWidth) {
inSampleSize = Math.round((float) width / (float) reqWidth);
}
options.inSampleSize = inSampleSize;
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(path, options);
}
I don't think you can. Not even on a PC, I fail to see how you could do that without loading the entire image: most image formats, for example PNGs, have the pixel data zipped, so you need to at least unzip the IDAT chunk before you can start doing anything else and that will basically decode the whole image.
In your shoes I would try to have a server do it for me. Where do you get the image anyway? Not from a server? Then try to make a WS request that will give you the proper part of the image. If the image does NOT come from the server you can nevertheless send it to your server to get back only the part of the image that you want.
try this code:
private Bitmap decodeFile(File f) {
Bitmap b = null;
try {
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
FileInputStream fis = new FileInputStream(f);
b=Bitmap.createBitmap(BitmapFactory.decodeStream(fis, null, o), 100, 200, 200, 400, null, null);
fis.close();
} catch (IOException e) {
}
return b;
}
Am not sure, but this may give some idea to you

Android, Java, Creating a thumbnail keeping aspect ratio

I'm trying to create a thumbnail of a certain height but maintain the aspect ratio. I'm using the code below but the problem arises when say if an image is somewhat small the image generated will not fill the thumbnail area. imageURI is just the path to the image.
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imageURI, o);
final int REQUIRED_SIZE=70;
int width_tmp=o.outWidth, height_tmp=o.outHeight;
int scale=4;
while(true){
if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
break;
width_tmp/=2;
height_tmp/=2;
scale++;
}
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
Bitmap bitmap = BitmapFactory.decodeFile(imageURI, o2);
Your code is always scaling the bitmap to have at least 1/4 of width or heigth. If the original image is already large enough it will be even smaller.
I assume you display the image in an ImageView (your thumbnail area?. If the image does not fill the ImageView you have to configure the ImageView to resize the image correctly. If your ImageView and the image to display have different aspect ratios, the only way to make the image fill the ImageView will distort the image.
What I do: I use the BitmapFactory to decode the image into a size thats larger, but nearly the size I want the thumbnail to have. Its better to use powers of two as scaling parameter, so I do that. And then I set the android:scaleType parameter of ImageView to make the image display as I like:
public static Bitmap decodeBitmap(Uri bitmapUri, ContentResolver resolver, int width, int height) throws IOException{
InputStream is = resolver.openInputStream(bitmapUri);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is,null,options);
is.close();
int ratio = Math.min(options.outWidth/width, options.outHeight/height);
int sampleSize = Integer.highestOneBit((int)Math.floor(ratio));
if(sampleSize == 0){
sampleSize = 1;
}
Log.d(RSBLBitmapFactory.class, "Sample Size: " + sampleSize);
options = new BitmapFactory.Options();
options.inSampleSize = sampleSize;
is = resolver.openInputStream(bitmapUri);
Bitmap b = BitmapFactory.decodeStream(is,null,options);
is.close();
return b;
}
<ImageView android:scaleType="fitXY"></ImageView>

Categories