2011/3/11 Anil <gan...@gmail.com>:
> Hi:
>
> I am trying to build a custom QR Scanner using the ZXing for Android
> and I hit a few roadblocks that I cannot get past:
Unless you're trying to do something very unorthodox, consider using
Scanning-Via-Intent method.
http://code.google.com/p/zxing/wiki/ScanningViaIntent
> 1. I like how Barcode Scanner client captures a QR without clicking a
> button and I want to replicate it but I cannot understand from the
> code how this was accomplished. Since I don't want the button for
> capturing QR, the takePicture() method is ruled out. But, I can't
> understand how the Camera.Preview reads the QR without any user
> interaction.
The application uses Camera.startPreview() and then
Camera.setOneShotPreviewCallback().
The camera driver generates preview frames and sends them to the
preview call-back.
Take a look at:
http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/graphics/CameraPreview.html
> 2. Also, how do I display the results back after the QR was read? I
> understand onActivityResult is expected to do that but I am not sure
> how to code it. I guess I am struggling because I don't see the
> methods linked to one another.
The onActivityResult() is called when using Scanning-Via-Intent method.
If you decide to replicate the scanning method you will have to feed
the preview frame to an instance of a Reader hierarchy.
> 3. Finally, should I look at creating each UI screen as an individual
> Intent? Is that a better a design?
This is pretty much general Android question, and Activity is the
equivalent of a Window/Frame. Exceptions to this general rule do
exist.
> Thank you.
>
> Best,
> Anil.
2011/3/12 Anil <gan...@gmail.com>:
> Thank you for your response.
>
> Unfortunately, scanning via intent is not an option because that would
> mean dependency on the Barcode Scanner. I'd love to just use Barcode
> Scanner and not reinvent the wheel.
I don't exactly understand your point of view, although I am also
using just the library.
In my case I needed a bulk scanner with interactivity on every scan,
that was not achievable with the Scanning-Via-Intent method.
> If I understand you correctly, setOneShotPreviewCallback() sends
> single frames without any user interaction. Let me play around with
> that.
Well... You need to put a SurfaceView in your Activity, commonly at
the background plane. Then connect the camera to the surface to enable
preview.
The one-shot preview shoots ONLY ONE frame, and de-registers the
call-back. You will need to continuously poll for frames.
An alternative method is to set a long-term preview call-back with
the setPreviewCallback(...) method, but this shoots tens of frames per
second, and you may end up with a severe resource depletion if you're
unable to process frames fast enough, not to mention battery drain.
> But, when is a frame considered complete and how do I know that so
> that I can process that frame like, send it to a decoder?
The frame that you get IS complete, meaning it represents a full
frame of the preview. The call-back should send it to the decoder
immediately, and request a new One-Shot preview immediately after
processing the frame, or if you choose to do so, with a small delay.
Do not forget to call Camera.autoFocus(...) from time to time. While
running auto-focus you may or may not get preview frames. After the
auto-focus completes the call-back you provided should start
requesting frames again.
2011/3/14 Anil <gan...@gmail.com>:
> Well, if I have to have my app leverage Scanning Via Intent then,
> Barcode Scanner has to be pre-installed and unfortunately, that is not
> an option that my company is willing to live with.
Well... That's one way of putting it.
There is an Android Integration project, that handles whether the
Scanner is installed, and directs the user to install it if needed.
http://zxing.googlecode.com/svn/trunk/android-integration/
Take into consideration, that if you decide to do it yourself you
will have to write much code, that the ZXing project has already done.
> Per your suggestions, after using setOneShotPreviewCallback() I am
> able to get a single frame but I am running into a NotFoundException
> when the frame is sent for decoding when I execute the code using the
> G1 which as 480X320 resolution. I used DecodeHintType as well but no
> luck.
Getting a NotFoundException is very much expected.
The preview-based scanning is built around a brute-force approach.
This means, that the scanner relies on trying many times with
relatively bad quality frames and relatively low success rate, rather
than trying once with a higher success rate and better quality.
That said, you should use a GlobalHistogramBinarizer, because it is
faster although provides less quality. Also ditch the TRY_HARDER hint,
it makes things slower.
I think your problem is lack of focus. Call Camera.autoFocus(...).
As you may have noticed the scanner application does some continuous
auto-focusing.
Also... I don't understand why you are cropping the frame
(PlanarYUVLuminanceSource arguments). Use the full size.
> Of course, when I use the Barcode Scanner app, I am able to decode the
> QR but not with my app. Would you be able specify what is that I am
> doing wrong in my code?
That is one of the very serious reasons to use the Scanner
Application to do the job for you.
2011/3/14 Anil Bhargav <gan...@gmail.com>:
> Yes, I understand and hence I mentioned, I am reinventing the wheel.
>
> I am not sure where to call the camera.autofocus() in my code because
> I have an Activity1, once my App is launched, I click "Start Scan" in
> Activity1 which calls Activity2 (where onPreviewFrame exists) that
> sets up the camera. I looked at some examples but all of them call
> autofocus in onClick but I can't do the same in my app.
Auto-focus is an asynchronous process.
You could call auto-focus every 2 seconds for instance. The else
case in the preview listener should do the trick: if it's more than
two seconds since last auto-focus, then do auto-focus, otherwise
request a new frame.
For instance, you may enhance your Preview Listener to implement
Autofocus Call Back:
//now that we have the result
if (result != null) {
mCamera.stopPreview();
mCamera.release();
Log.i(TAG, "Result not null in onPreviewFrame");
onValidDecodeResult(result, source.renderCroppedGreyscaleBitmap());
} else if ((this.lastAutoFocus + 2000) < System.currenTimeMillis())
// Request an Auto-Focus
this.lastAutoFocus = System.currentTimeMillis();
mCamera.autoFocus(this);
} else {
mCamera.setOneShotPreviewCallback(this);
} //end of if-else
...
//
public void onAutoFocus(boolean success, Camera camera) {
this.lastAutoFocus = System.currentTimeMillis();
// After auto-focusing request a new frame.
mCamera.setOneShotPreviewCallback(this);
}
Easy as 3.14.
> Also, I cooked up those numbers in PlanarYUVLuminanceSource
> considering that my G1 has 480x320 resolution and also to pass the if
> condition, "if (left + width > dataWidth || top + right >
> dataHeight)".
These are not conditions, but sanity checks.
2011/3/14 Anil Bhargav <gan...@gmail.com>:
the camera is constantly scanning until it finds the lines that
match a barcode edge
qr stands for quick response note the edges but once zebra identifies
the edge of the bit map then it reads the lines where there is
on or off pixel which translates into a bitmap value
no just define you barcode reader encoder and add it to
the types make your own encoder decoder
2011/3/14 Anil Bhargav <gan...@gmail.com>:
> No luck, continue to get the NotFoundException. Unlike, barcode
> scanner, my app doesn't wait for the user to focus on the barcode in
> order to capture the QR. My app reads a frame, sends that to decode
> and returns to home screen.
No, that's not how it should work!
You need to constantly pull frames! You are NOT going to be able to
scan the first frame, unless you're extremely lucky!
You wait for either a successful read indefinitely.
Also handle the onPause() in your activity to disconnect from the camera.
> The camera is capturing the image, as I see the image size as 230400
> bytes. However, the app is failing to detect the QR in this raw image.
> The image quality cannot be bad because Barcode Scanner is able to
> read it. I am assuming that my app will fail to process the QR even if
> I saved the image on the device and sent it for decoding.
By bad quality I do not mean only bad picture quality, but also
over-exposures, under-exposures, focus blur, motion blur, etc. These
all contribute to the image being poorly analysable.
Initially when you start the camera, it commonly is either
over-exposed, or under-exposed, and I'm pretty sure it's out-of-focus.
Do continuous scanning.