diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-03-09 00:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-03-09 00:06:44 +0000 |
commit | 44cf8ec67278bd1ab6c7f83a9993f7a5686a9541 (patch) | |
tree | 5eec4b0d1a3f163d279c3c27c03324ba49fa235a /iphone/doc/optimizing.rst | |
parent | Initial commit. (diff) | |
download | zbar-44cf8ec67278bd1ab6c7f83a9993f7a5686a9541.tar.xz zbar-44cf8ec67278bd1ab6c7f83a9993f7a5686a9541.zip |
Adding upstream version 0.23.93.upstream/0.23.93upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'iphone/doc/optimizing.rst')
-rw-r--r-- | iphone/doc/optimizing.rst | 435 |
1 files changed, 435 insertions, 0 deletions
diff --git a/iphone/doc/optimizing.rst b/iphone/doc/optimizing.rst new file mode 100644 index 0000000..a823fd6 --- /dev/null +++ b/iphone/doc/optimizing.rst @@ -0,0 +1,435 @@ +Optimizing the Reader +===================== + +As good as the iPhone performance is for a mobile device, the reality from an +image processing perspective is that it represents a lower performance target. +While the default configuration of the iPhone reader has been carefully tuned +for the general case, you can often obtain much better results if you optimize +for your specific application. + +.. note:: + + Performance is a complex topic. The only way to tune performance is by + changing settings and comparing measured results. If you are not + comfortable with the concepts presented here, it is recommended that you + leave the settings at the defaults and avoid compromising reliability. + +Performance of the barcode reader is generally evaluated by two factors: + +* The **latency** - how quickly it "recognizes" a barcode. Specifically this + is the time from when the user puts a barcode in the frame or selects an + image until a response is indicated back to the them. + +* The **reliability** - it does not matter how quickly an image is scanned if + an incorrect result is returned. That may seem obvious, but bad decodes + *are* possible and you need to keep this in mind when changing settings that + affect the reliability of the reader. + +Basically our goal is to optimize the latency without sacrificing reliability. +There are several factors that contribue to latency: + +* The **quality** of the barcode image. Quality includes the available + resolution, focus, lighting, noise, etc. We have more control over some of + these than others. + +* The **camera**. When scanning from the camera, the time for the + autoexposure and autofocus to converge on an image that can be decoded is a + significant contribution to the overall latency. + +* The **frame rate** of the reader - this translates to the time it takes the + scanner to process an image. + +* The **effort level** of the reader - some of the available settings control + "how hard" the reader tries to find barcodes in each frame. + +* The **delegate latency** - the time spent in your application after a + barcode has been detected until the user is notified. + +Most of these factors are interrelated. We will discuss those we can control +in detail, as well the settings you use to affect them. Then we will provide +a few specific case examples. + + +Measuring Performance +--------------------- + +Subjective response times are a good place to start (does it "feel" responsive +to you?), and possibly the only way to evaluate the overall experience, but to +compare incremental changes to interrelated settings and have meaningful +performance discussions with others, we need a more quantitative approach. + +The :func:`mach_absolute_time` function is a good tool for accurately +measuring small delays. Research this function and learn how to apply it. As +when measuring any real-world value, keep in mind that some variance is to be +expected - even if you perform exactly the same operation multiple times, you +will not see exactly the same measurement. You should collect several +samples, discard any obvious outliers, and average the remaining measurements. + +One way that the overall reader latency may be evaluated is by manually +marking the time when the barcode is presented to the reader. Add a control +to your overlay that captures the start time when tapped and compare this to +the end time, just before your delegate returns. + +The reader continually monitors the frame rate at which it is running. The +measured value may be displayed for debugging purposes by enabling the +:member:`~ZBarReaderView::showsFPS` property. The readertest example does +this and also provides control over many of the available settings, so you can +quickly test how each setting affects the frame rate. You should target your +optimization efforts to achieve a frame rate of at least 8-10fps, although +12-15fps is preferable. + +You can measure the latency of your delegate using :func:`mach_absolute_time`. +The measured value should be less than about 100ms, the smaller the better, to +avoid noticeable lag. + +The readertest is a good tool for testing the performance of the reader. You +can tune the settings appropriately for your application and evaluate the +effect each change has on the performance. + + +Delegate Latency +---------------- + +This latency contributor is the easiest for you to effect (and sometimes the +easiest to overlook). Your delegate method should update the interface - +dismiss the controller or update your overlay to indicate success - and +*nothing* else. All other processing should be deferred until after the +animations have started. + + +Image Quality +------------- + +Resolution +^^^^^^^^^^ + +One might think that "more is better" in terms of resolution, but this is not +necessarily the case. Given average image quality, the ideal resolution for +scanning is right around three pixels per barcode "module" (the width of the +smallest bar or space). Note that this measure is not an absolute image size +or even a measure of the physical dimensions represented by a pixel sample, it +*only* describes the sampled size of the barcode in the image. + +As the resolution decreases below about two pixels per module, edge fidelity +is lost and the bars and spaces start to merge together, making it impossible +(for this library) to scan. This affects the density (feature size) and +maximum size (data capacity) of the barcodes that can be detected. +Conversely, as the resolution increases above about 4 pixels per module, noise +can interfere with the edge detection and images will take longer to process. + +Other quality factors, such as poor focus, bad lighting or even excessive +noise, can increase (or decrease) the resolution requirement. + +When scanning from the camera, the reader defaults to 640x480, which is good +for most applications. On newer devices, you can increase this using a capture +:member:`~ZBarReaderView::session` preset. Some older devices do not have a +higher resolution option available. + +For scanning images, you can use +:member:`~ZBarReaderController::maxScanDimension` to control the scaled size +of the converted image, or resort to converting them yourself. + +If you want to read long linear barcodes or dense 2-D symbols, you will +probably want to increase the resolution by adjusting these settings. + +Keep in mind that more pixels will take longer to scan, refer to the `frame +rate`_ discussion for ways to compensate. + +Focus +^^^^^ + +Ideally we would fix the focus at a calculated optimum distance and optimize +the aperture selection to maximize the depth of field. Unfortunately the APIs +do not currently give us control over any of these settings, the best we can +do (as of iOS 4) is continuous auto-focus mode - this mode is configured by +the reader automatically. It can still take the device as long as 1-2 seconds +to find the appropriate macro focus setting, but again, there is currently no +way to reduce this delay. + +Lighting and Exposure +^^^^^^^^^^^^^^^^^^^^^ + +An image that is too bright or overexposed can completely wash out any +barcodes. An image that is too dark or underexposed will not provide +sufficient contrast for the scanner. Low light levels also tend to produce +noisier images, possibly because the driver uses a faster "ISO" setting to +compensate for the lighting. + +The camera defaults to continuous automatic exposure and white balance. Since +there are no other useful values, the reader leaves these unchanged from their +default setting. + +For some devices, the "torch" can be enabled to provide additional +illumination for the camera in low-light conditions. The reader sets the +torch to automatic by default, so it should turn on only when needed... +There have been some reports that the torch turns on inappropriately, washing +out the image. If you find that this occurs, you should instead set the +:member:`~ZBarReaderView::torchMode` property of the :class:`ZBarReaderView` +to ``Off``. + +For scanning images from another source, you are again stuck with the +available image quality. If you have any control over the image source, you +should do what you can to fix quality problems there. + +Noise +^^^^^ + +Some level of noise is filtered by the reader, but excessive noise levels +create additional edges in the image which corrupt barcodes and increase +scanning time (decreasing the frame rate). + +As mentioned with `lighting and exposure`_, noise mostly becomes a problem +when the light-level is too low, but high-resolution images may also increase +exposure to sensor noise. + +We compensate for noise by *reducing* the `resolution`_ from the sensor +maximum. Scaling the image down has the effect of averaging several pixels +into one value, filtering out the high-frequency noise component. + + +Frame Rate +---------- + +The time it takes to scan and decode an image/frame is roughly proportional to +the number of pixels that are processed. The number and type of enabled +symbologies and image noise can also affect the processing time. + +We have several knobs available that affect the frame rate. Most of these are +geared toward reducing the number of image pixels that are scanned. + +Decrease the Resolution +^^^^^^^^^^^^^^^^^^^^^^^ + +Adjusting the resolution of the image is an easy way to quickly reduce the +number of pixels. Smaller images also mean there is less data to carry +around, which helps performance in other ways. For example, reducing each +image dimension by 30% (eg, from 640x480 to 448x336) will about double the +speed of the reader (to a point). [FIXME verify!] + +Adjusting the resolution is `described above <resolution>`_. As mentioned +there, reducing the resolution will negatively impact the minimum feature size +and maximum barcode size that can be scanned, but it will help filter noise. + +Crop the Scan Region +^^^^^^^^^^^^^^^^^^^^ + +It may not always be necessary for an application to scan all the way to the +edges of the image. By cropping the scan area, you can get most of the +benefits of reduced resolution without sacrificing the minimum feature size. +Cropping will also not affect image noise, but similar to decreasing the +resolution, it does affect the maximum size barcode that can be scanned. + +For all cases you set the crop rectangle +:class:`~ZBarReaderViewController::scanCrop` property. Note that the +rectangle provided to the controller is *normalized* across image size and +rotation. This means that the coordinates range from 0 to 1 and the axes will +be arranged such that the x-axis of the crop rectangle corresponds to the +major (longer) image axis. + +Your interface will typically need to indicate the cropped scan area to the +user with visual queues. Use the +:class:`~ZBarReaderViewController::cameraOverlayView` to provide this. + +By default, the :class:`ZBarReaderView` recognizes a pinch gesture to +digitally zoom the preview around the center of the image. This zoom does not +affect the resolution of the image, but it does crop the scan region to the +visible area. You can also disable the pinch gesture and set the +:class:`~ZBarReaderView::zoom` programmatically. + +Limit the Scan Density +^^^^^^^^^^^^^^^^^^^^^^ + +The scanner works by making scan passes across the pixel rows and colums of +the image. The density of the passes is configured at the scanner as a pixel +stride for each axis. ``ZBAR_CFG_Y_DENSITY`` (``ZBAR_CFG_X_DENSITY``) +controls the number of pixel rows (columns) that are skipped between +successive horizontal (vertical) scan passes. (Note that "density" is really +not a good name for the configuration settings... "stride" might be more +appropriate.) + +Decreasing the scan density (by increasing the stride setting) is a great way +to limit the processing (increasing the frame rate) without sacrificing scan +resolution - each scan pass is still made at full image resolution, there are +just fewer passes (less redundancy). + +Setting the stride value to 0 completely disables scanning in that direction. +This is very useful when reading linear codes with a visual alignment guide - +scanning parallel to the bars is a waste of cycles which may be better applied +to support higher resolution or increased density of scans across the symbol. +Note that some 2-D symbologies (QR Code) require scans in both directions. + +Setting the stride to a very large value will generate a single scan pass +through the center of the image. Note that some symbologies will not be +detected without multiple successful passes; it is usually better to combine +this setting with cropping to generate a number of closely clustered scan +passes in the target area. + +Note that the density also affects the aspect ratio and rotation that can be +tolerated. If you set it too large, some barcodes will become more difficult +to read. + +In general, 2 to 4 is a good target for the stride setting, unless you have +very high or low resolution images. + +Disable unused symbologies +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Limiting the symbologies to the set of interest should provide a small +performance boost. It also improves decode reliability - it is impossible to +receive an incorrect or unexpected decode result from a symbology that is +disabled. + +The reader does support full auto-discrimination among the supported +symbologies, but with all of them enabled you may need to compensate elsewhere +to get a good frame rate. + +For example, if you are only interested in QR codes, disable the others. The +robust way to do this is by disabling *all* symbologies and then reenabling +only those you want. This helps isolate you from encountering new symbologies +that may be added in future versions of the library until you are ready to +handle them:: + + [scanner setSymbology: 0 + config: ZBAR_CFG_ENABLE + to: 0]; + [scanner setSymbology: ZBAR_QRCODE + config: ZBAR_CFG_ENABLE + to: 1]; + +Even if you would like your application to support multiple symbologies, you +may consider if there is a way to limit the enabled subset based on the +scanning context, etc... + + +Examples +-------- + +These examples demonstrate several scenarios for scanning from the camera with +automatic capture. You can try them yourself using the readertest. For each +example, start with the default settings (by tapping the +``ZBarReaderViewController`` class), then enable continuous mode and the +custom overlay (by disabling +:member:`~ZBarReaderViewController::showsZBarControls`). You should also use +a release build and avoid running in the debugger. + +Frame rates are approximate, measured on an iPhone 3GS running iOS 4.0.1 in a +well lit room. Two measurements are taken for each sample: the rate with the +camera pointed at a blank white page such that it fills the frame, and the +rate while continuously decoding the provided example. For best results, it +is recommended that you print the examples rather than scanning them from the +screen. + +For reference, the base frame rates with default settings are 12fps for a +blank white page, 7.5fps for this `basic EAN symbol`_ and 2.2fps for this +`basic QR symbol`_. + +.. _`basic EAN symbol`: + http://zbar.sf.net/test/ean13/9876543210128.png +.. _`basic QR symbol`: + http://chart.apis.google.com/chart?cht=qr&chs=512x512&chl=http://zbar.sf.net/iphone + +Long Linear Symbols +^^^^^^^^^^^^^^^^^^^ + +For this example, we will use a relatively `long Code 128 barcode`_. + +.. _`long Code 128 barcode`: + http://zbar.sf.net/test/code128/ALPHA.png + +While it should be possible to read this symbol with the default settings, you +may notice that it is not very reliable. You will have to stretch the symbol +across the entire screen, and even then the default settings will only give +you about 1.6 pixels per module, well below the ideal target of 3. To improve +these results, we want to maximize scanning resolution for the long image +axis. + +1. Disable the default zoom/crop - zoom all the way out by hitting "Scan" and + pinching the preview; the frame rate immediately drops to 8fps / 4.8fps. + +We should compensate for this reduction in the frame rate: + +2. Crop the image to a long, skinny rectangle - set the + :member:`~ZBarReaderViewController::scanCrop` setting to + ``{{0, 0.3}, {1, 0.4}}``; The frame rate jumps up to 18fps / 8.7fps. + +3. Disable scans across the short image axis - set the ``CFG_X_DENSITY`` + setting to 0. The frame rate goes all the way to 30fps / 13fps. + +Since we have plenty of margin with the frame rate, we can minimize the total +decode latency by performing more scan passes through the symbol: + +4. Increase the scan density - set the ``CFG_Y_DENSITY`` setting to 1 (13.5fps + / 5fps) or 2 (24fps / 9fps). + +You should now be able to quickly and reliably decode long linear symbols. + +If have a newer device, you may also try increasing the resolution to support +even longer symbols. You may have to compensate elsewhere to bring the frame +rate back to a reasonable level. + +High Density QR Symbols +^^^^^^^^^^^^^^^^^^^^^^^ + +For this example we will use a `version 29 QR Code symbol`_. + +.. _`version 29 QR Code symbol`: + http://www.qrcomic.com/images/5.png + +In this case we still want to maximize the resolution, but we also need to +increase the scan density to reliably pick up the small finder patterns: + +1. Maximize scan density in both directions - set the ``CFG_X_DENSITY`` and + ``CFG_Y_DENSITY`` settings both to 1. You should be able to scan the symbol + now, although the frame rate drops to 4.5fps / 1fps + +2. Disable the default zoom/crop - zoom all the way out by hitting "Scan" and + pinching the preview; the frame rate drops further to 3fps / 0.7fps + +We can compensate somewhat for the reduced frame rate: + +3. Crop the image to a square - set ``scanCrop`` to ``{{0.125, 0}, {.75, 1}}``. + This boosts the frame rate slightly to 3.7fps / 0.75fps. + +4. Disable linear symbologies - set the symbologies such that only QR Code is + enabled (4fps / 1fps) + +Even though the frame rate is still pretty bad, the QR recognition latency +should be acceptable. + +If have an iPhone 4, you may also try increasing the resolution to support +even denser QR symbols. You may have to compensate elsewhere to bring the +frame rate back to a reasonable level. + +Small DataBar Symbols +^^^^^^^^^^^^^^^^^^^^^ + +For this example we will use a `DataBar symbol`_ printed with a small feature +size, typical of the stickers used to tag produce. Scale it when printing +such that the printed dimensions are about 1cm square. This symbol should +scan with the default settings, but we will attempt to optimize the scan +latency for this case. + +.. _`DataBar symbol`: + http://zbar.sf.net/test/databar/0109876543210128-so.png + +As well as high barcode resolution, we also want high density passes in both +directions to minimize sensitivity to rotation: + +1. Maximize scan density in both directions - set the ``CFG_X_DENSITY`` and + ``CFG_Y_DENSITY`` settings both to 1. The frame rate drops to 4.5fps / + 3fps. + +Compensate for the reduction in frame rate by zooming in on the small symbol, +which crops the scanned image. Zooming also helps the user see the small +barcode: + +2. Zoom all the way in - hit "Scan" and un-pinch the preview. The frame rate + recovers to 11fps / 6.2fps. + +3. Crop the image to a square - set ``scanCrop`` to ``{{0.125, 0}, {0.75, 1}}`` + (14fps / 7.5fps) + +4. Disable all symbologies except DataBar and DataBar Expanded (14.5fps / 9fps) + +The reader should now be very sensitive to DataBar, even when scanned at an +angle. |