How to get continuous frames from a video file input? - java

I had done with taking video as input. Now decided to get frames with it, so I used MediaMetadataRetriever(). After using this got only first frame. So can anybody suggest me the remedy?
String STR = (String) Environment.getExternalStorageDirectory().getAbsolutePath();
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setDataSource(STR+"/vd.3gpp");
img = (ImageView) findViewById(R.id.imageView1);
img.setImageBitmap(retriever.getFrameAtTime(1000,MediaMetadataRetriever.OPTION_NEXT_SYNC));
Thanks in advance.

At this point:
img.setImageBitmap(retriever.getFrameAtTime(1000,MediaMetadataRetriever.OPTION_NEXT_SYNC));
You are retrieving exactly one frame and setting exactly one bitmap.
What you need is a loop, like:
int videoLength = /* get video length from some where */
for(int i = 0; i < videoLength; i *= 1000000)
{
img.setImageBitmap(retriever.getFrameAtTime(1000, MediaMetadataRetriever.OPTION_NEXT_SYNC));
}

Related

Bitmap "images" pass to another activity (Out of memory)

please read the full question before marking it as duplicate or down-vote it.
i am developing an app what can slice through a picture and run google vision to recognize text in each chunk or slice of picture and run OCR to detect that the circle bubble is filled or not in the chunk. but when i am slicing the Bitmap image in an array and pass it to other activity for the process it crashes for over use of memory. I know i can compress it but i tried that already (though i did not wanted to compress it since i need to run google vision and may not able to extract text accurately) but it did not work since there are 46 slices of image. How can i do so without uploading on cloud fetch it again for process since it might take long. any alternative solution is very welcome as well. i am stuck on this for quite a while.
import android.content.Intent;.....
public class ProcessesdResult extends AppCompatActivity {
TextView tvProcessedText;
Button btnImageSlice;
Bitmap image;
int chunkNumbers =46;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_processesd_result);
Intent intenttakeattendance = getIntent();
String fname = intenttakeattendance.getStringExtra("fname");
String root = Environment.getExternalStorageDirectory().toString();
File myDir = new File(root);
String photoPath = myDir+"/sams_images/"+ fname;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
image = BitmapFactory.decodeFile(photoPath, options);
btnImageSlice=findViewById(R.id.btnimageslice);
btnImageSlice.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
splitImage(image, chunkNumbers) ;
}
});
}
private void splitImage(Bitmap image, int chunkNumbers) {
//For the number of rows and columns of the grid to be displayed
int rows =23;
int cols =2;
//For height and width of the small image chunks
int chunkHeight,chunkWidth;
//To store all the small image chunks in bitmap format in this list
ArrayList<Bitmap> chunkedImages = new ArrayList<Bitmap>(chunkNumbers);
//Getting the scaled bitmap of the source image
Bitmap scaledBitmap = Bitmap.createScaledBitmap(image, image.getWidth(), image.getHeight(), true);
chunkHeight = image.getHeight()/rows;
chunkWidth = image.getWidth()/cols;
//xCoord and yCoord are the pixel positions of the image chunks
int yCoord = 0;
for(int x=0; x<rows; x++){
int xCoord = 0;
for(int y=0; y<cols; y++){
chunkedImages.add(Bitmap.createBitmap(scaledBitmap, xCoord, yCoord, chunkWidth, chunkHeight));
xCoord += chunkWidth;
}
yCoord += chunkHeight;
}
//Start a new activity to show these chunks into a grid
Intent intent = new Intent(ProcessesdResult.this, ChunkedImageActivity.class);
intent.putParcelableArrayListExtra("image chunks", chunkedImages);
startActivity(intent);
}
}
This is the image type i want to slice in pieces
You dont want to pass objects between activities, especially not huge objects like bitmaps. I would suggest saving your bitmaps in the devices file system and then passing a list of URI's. Saving the bitmaps like this and recycling your bitmaps after you are done using them should also reduce the RAM usage during your loop where you slice up the image.
For saving bitmaps as files i would refer to this question: Saving and Reading Bitmaps/Images from Internal memory in Android
So basically your loop should look like this:
for(int x=0; x<rows; x++){
int xCoord = 0;
for(int y=0; y<cols; y++){
Bitmap image = Bitmap.createBitmap(scaledBitmap, xCoord, yCoord, chunkWidth, chunkHeight);
Uri uri = saveBitmapAsFile(image);
image.recycle();
xCoord += chunkWidth;
}
yCoord += chunkHeight;
}
use android:largeHeap="true" in manifest if you still get the same error then try this :
instead of sending "intent.putParcelableArrayListExtra("image chunks", chunkedImages);"
bitmap to another activity, save that image to local storage and use path wherever you want.
I recommended for create another data(Bitmap) store class with static.
Use this class for save bitmaps and call another activity for read.
This link helpful.

Scan, detect and decode UPC code from an image

I am working on Android development where once I get byte array from Google Glass frame, I am trying to scan array using Zxing library and trying to detect 1d barcode(UPC code).
I have tried this code snippet.
BufferedImage image = ImageIO.read(game);
BufferedImageLuminanceSource bils = new BufferedImageLuminanceSource(image);
HybridBinarizer hb = new HybridBinarizer(bils);
BitMatrix bm = **hb.getBlackMatrix();**
MultiDetector detector = new MultiDetector(bm);
DetectorResult dResult = detector.detect();
if(dResult == null)
{
System.out.println("Image does not contain any barcode");
}
else
{
BitMatrix QRImageData = dResult.getBits();
Decoder decoder = new Decoder();
DecoderResult decoderResult = decoder.decode(QRImageData);
String QRString = decoderResult.getText();
System.out.println(QRString);
}
It works fine for QRcode, detects and decodes QR code well. But does not detect UPC code.
I also tried this code snippet,
InputStream barCodeInputStream = new FileInputStream(game);
BufferedImage barCodeBufferedImage = ImageIO.read(barCodeInputStream);
BufferedImage image = ImageIO.read(game);
LuminanceSource source = new BufferedImageLuminanceSource(image);
BinaryBitmap bitmap = new BinaryBitmap(new GlobalHistogramBinarizer(source));
RSSExpandedReader rssExpandedReader = new RSSExpandedReader();
int rowNumber = bitmap.getHeight()/2;
BitArray row = **bitmap.getBlackRow(0, null);**
Result theResult = rssExpandedReader.decodeRow(rowNumber, row, new Hashtable());
and in both I am getting "Exception in thread "main" com.google.zxing.NotFoundException".
Does anyone know how to fix this issue?
getBlackMatrix() -
Converts a 2D array of luminance data to 1 bit. As above, assume this method is expensive and do not call it repeatedly. This method is intended for decoding 2D barcodes and may or may not apply sharpening. Therefore, a row from this matrix may not be identical to one fetched using getBlackRow(), so don't mix and match between them.
getBlackRow()-
Converts one row of luminance data to 1 bit data. May actually do the conversion, or return cached data. Callers should assume this method is expensive and call it as seldom as possible. This method is intended for decoding 1D barcodes and may choose to apply sharpening.

Loading images from URL partially, just like what is implemented in WhatsApp

WhatsApp developers recently improved the image loading in which immediately loading some portion of the image (getting its dimension and some pixels of the images) and then after loading the entire image, replace the placeholder with the full image:
My question is, how did they implement it? Do they read the dimension of the image by reading its header (meta-data)? How about the image content? Or do they have two versions of the image at the server-side, a smaller one with low-quality which is loaded first and a bigger one which is the full image? Note that if it's the second approach then they still need to extract the smaller version of the image at the server side once receiving the image from the sender. Any other approaches?
There is another alternative to the colored placeholder solution, which is to show a thumbnail image (may be only a 100 X 100 px) as the placeholder until loading the real image, which is away more cooler than having only a colored placeholder :) .
I did it in Zingoo and made a blog post about it. Using Picasso, you can do it like this:
Transformation blurTransformation = new Transformation() {
#Override
public Bitmap transform(Bitmap source) {
Bitmap blurred = Blur.fastblur(LiveImageView.this.context, source, 10);
source.recycle();
return blurred;
}
#Override
public String key() {
return "blur()";
}
};
Picasso.with(context)
.load(thumbUrl) // thumbnail url goes here
.placeholder(R.drawable.placeholder)
.resize(imageViewWidth, imageViewHeight)
.transform(blurTransformation)
.into(imageView, new Callback() {
#Override
public void onSuccess() {
Picasso.with(context)
.load(url) // image url goes here
.resize(imageViewWidth, imageViewHeight)
.placeholder(imageView.getDrawable())
.into(imageView);
}
#Override
public void onError() {
}
});
more details in the post itself including the Blur class.
Yet another up-to-date answer for an older post. You could try the progressive JPEG streaming feature of the Fresco library to achieve that effect.
Basically all you'd need to do is calling .setProgressiveRenderingEnabled(true) while creating an ImageRequest. I have included a complete example for Fresco's progressive JPEG streaming into my demo application mentioned in this answer, you might want to try it out to see how it works.
For the lazy ones: when working with Fresco, create a DraweeController as following:
ImageRequest imgReq = ImageRequestBuilder.newBuilderWithSource(Uri.parse(url))
.setProgressiveRenderingEnabled(true)
.build();
DraweeController controller = Fresco.newDraweeControllerBuilder()
.setImageRequest(imgReq)
.setOldController(yourDrawee.getController())
.build();
yourDrawee.setController(controller);
Note: this approach has some restrictions as explained in the docs.
After several experiments, I got the dimensions without downloading the entire image:
String address = "image_url";
URL url = new URL(address);
URLConnection urlC = url.openConnection();
urlC.connect();
InputStream is = urlC.getInputStream();
for(int i = 0; i < 92; i++) is.read();
nt byte1 = is.read();
int byte2 = is.read();
int width = (byte1 << 8) + byte2;
for(int i = 0; i < 10; i++) is.read();
byte1 = is.read();
byte2 = is.read();
int height = (byte1 << 8) + byte2;
System.out.println("width = " + width + " | height = " + height);
is.close();
Using Glide lib:
Glide.with(context)
.load(url)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(imageView);

Relative path using setImageResource

I am trying to display an image in my app that changes everytime I press a button.
The name of the image that should be shown is in my object. I can get the name of the image with
String nameOfImage = myObhect.get(i).getImageName();
Now, I want to display the current image with
iv.setImageResource(R.drawable.notruf);
Using setImageResource , I don´t know how to bring the name of my image in setImageResource because, for example
iv.setImageResource(R.drawable. + aktbild) isn´t possible for sure.
I also tried the way with setImageDrawable but that does not work for me.
I use similar solution in my application :
Context mContext = this; // I supposed you're in Activity
String imgName = fragenkatalog.get(i).getBild();
int resId = mContext.getResources().getIdentifier(imgName,
"drawable", mContext.getApplicationInfo().packageName);
if(resId > 0){
iv.setImageResource(resId);
}
I believe that this code will help u..
String aktbild = fragenkatalog.get(i).getBild();
byte[] decodedString = Base64.decode(aktbild , Base64.DEFAULT);
Bitmap decodedByte = BitmapFactory.decodeByteArray(decodedString, 0,
decodedString.length);
After that, if you want to resize that image use this code.
int width=75;
int height=75;
Bitmap resizedbitmap=Bitmap.createScaledBitmap(decodedByte, width, height, true);
finally set image into ImageView.
Icon.setImageBitmap(resizedbitmap);`

Issue to read multiple barcodes using zxing library

I am trying to read 2D Data matrix barcode using zxing library(GenericMultipleBarcodeReader). I have multiple barcodes on a single image.
The problem is that the efficiency of the zing reader is very low, it
recognizes 1 barcode from image 1.png and no barcode from image 2.png which has 48 barcodes. Is there
any way to get 100% efficiency or any other library which results 100%
My code to read barcode is:
public static void main(String[] args) throws Exception {
BufferedImage image = ImageIO.read(new File("1.png"));
if (image != null) {
LuminanceSource source = new BufferedImageLuminanceSource(image);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
DataMatrixReader dataMatrixReader = new DataMatrixReader();
Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>();
hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
GenericMultipleBarcodeReader reader = new GenericMultipleBarcodeReader(
dataMatrixReader);
Result[] results = reader.decodeMultiple(bitmap, hints);
for (Result result : results) {
System.out.println(result.toString());
}
}
}
And images I used are:
Please help to resolve this issue.
Thanks
It doesn't quite work this way. It will not read barcodes in a grid, as it makes an assumption that it can cut up the image in a certain way that won't be compatible with grids. You will have to write your own method to cut up the image into scannable regions.
It is also the case that the Data Matrix decoder assumes the center of the image is inside the barcode. This is another reason you need to pre-chop the image into squares around the cylinders and then scan. It ought to work fairly well then.
An alternative solution is to consider a barcode engine that can detect multiple barcodes in various orientations on one document. If you're running on Windows, the ClearImage Barcode SDK has a Java API and should be able to handle your needs without pre-processing. You can test if their engine can read your image using their Online Barcode Reader.
Some sample code:
public static void testDataMatrix () {
try {
String filename = "1.png ";
CiServer objCi = new CiServer();
Ci = objCi.getICiServer();
ICiDataMatrix reader = Ci.CreateDataMatrix(); // read DataMatrix Barcode
reader.getImage().Open(filename, 1);
int n = reader.Find(0); // find all the barcodes in the doc
for (i = 1; i <= n; i++) {
ICiBarcode Bc = reader.getBarcodes().getItem(i); // getItem is 1-based
System.out.println("Barcode " + i + " has Text: " + Bc.getText());
}
} catch (Exception ex) {System.out.println(ex.getMessage());}
}
Disclaimer: I've done some work for Inlite in the past.

Categories