U.S. patent application number 09/394340 was filed with the patent office on 2002-10-17 for correlation and stitching techniques in a bar code scanning system.
Invention is credited to ATWATER, CHARLES F., BRANDT, JONATHAN R., DAVIS, GLEN W..
Application Number | 20020148899 09/394340 |
Document ID | / |
Family ID | 26797002 |
Filed Date | 2002-10-17 |
United States Patent
Application |
20020148899 |
Kind Code |
A1 |
BRANDT, JONATHAN R. ; et
al. |
October 17, 2002 |
CORRELATION AND STITCHING TECHNIQUES IN A BAR CODE SCANNING
SYSTEM
Abstract
In a bar code scanning system, correlation and stitching
techniques, both at the character and element level are utilized to
assemble complete label information from partially scanned label
segments. Correlation may require the same characters to be
identified a fixed number of times in the same position before
acceptance. Alternatively, quality and confidence measures may be
implemented to determine the number of times a particular character
must be decoded before being accepted. In a preferred
implementation, a decoded character that is determined to be of
poor quality may be required to be decoded as that same character a
greater number of times than if it were of good quality. Identified
correlation techniques may be combined with identified stitching
techniques to enhance decodability and efficiency of assembling
complete label information.
Inventors: |
BRANDT, JONATHAN R.;
(EUGENE, OR) ; DAVIS, GLEN W.; (JUNCTION CITY,
OR) ; ATWATER, CHARLES F.; (EUGENE, OR) |
Correspondence
Address: |
LYON & LYON LLP
633 WEST FIFTH STREET
SUITE 4700
LOS ANGELES
CA
90071
US
|
Family ID: |
26797002 |
Appl. No.: |
09/394340 |
Filed: |
September 13, 1999 |
Related U.S. Patent Documents
|
|
|
|
|
|
Application
Number |
Filing Date |
Patent Number |
|
|
60100288 |
Sep 14, 1998 |
|
|
|
Current U.S.
Class: |
235/462.12 |
Current CPC
Class: |
G06K 7/14 20130101; G06K
7/1486 20130101 |
Class at
Publication: |
235/462.12 |
International
Class: |
G06K 005/04; G06K
007/10; G06K 009/00 |
Claims
What is claimed is:
1. In a bar code scanning system, a method for assembling label
information from partial scans of label data which may comprise
some undecodable characters, the method comprising the steps of:
receiving scans of label data comprising character information;
sequentially decoding characters in each scan of label data
received; storing decoded character information in association with
corresponding position information; and, merging decoded character
information from multiple scans provided that each decoded
character so merged has been stored in association with the same
corresponding position a fixed number of times.
2. The method of claim 1 further comprising the step of verifying
that the merged decoded character information comprises a complete
and valid label segment.
3. The method of claim 2 further comprising the step of repeating
the steps of receiving, sequentially decoding, and merging for
further scans of label data until a complete label is obtained.
4. The method of claim 1 wherein the step of sequentially decoding
characters in each scan of label data received further comprises
the steps of: skipping character information that can not be
decoded as a valid character; storing an undecodable character
identifier in association with position information with respect to
the skipped character information; and, advancing to the next
character information using expected character boundary
information.
5. The method of claim 1 wherein the fixed number of times that
each decoded character has been stored in association with the same
corresponding position is two (2).
6. In a bar code scanning system, a method for assembling label
information from partial scans of label data which may comprise
some undecodable characters, the method comprising the steps of:
receiving scans of label data comprising character information;
sequentially decoding characters in each scan of label data
received; storing decoded character information in association with
corresponding position information; identifying and associating a
confidence measure with each decoded character stored in
association with corresponding position information; and, merging
decoded character information from multiple scans provided that
each decoded character so merged has been stored in association
with the same corresponding position a number of times that is
determined in relation to the corresponding confidence measure
associated with that decoded character.
7. The method of claim 6 wherein the step of merging decoded
character information comprises stitching partial scans of label
data.
8. The method of claim 6 wherein the step of merging decoded
character information comprises correlation of character
information across multiple scans of label data.
9. The method of claim 8 wherein the step of merging decoded
character information comprises stitching of multiple scans of
label data.
10. The method of claim 9 wherein thresholds for element ranges are
utilized with respect to decoding characters and further comprising
the step of adjusting thresholds to reduce the acceptable range of
element widths.
11. In a bar code scanning system, a method for assembling label
information from partial scans of label data which may comprise
some undecodable characters, the method comprising the steps of:
receiving scans of label data comprising decodable and undecodable
character information: decoding decodable character information;
storing decoded character information for decodable characters in
association with position information; storing an undecoded
character identifier for undecodable characters in association with
position information; repeating the receiving and storing steps for
additional scan lines; tracking the number of times each decoded
character information has been stored in association with the same
position information; merging stored information from multiple scan
lines when each decoded character information has been stored in
association with the same position information a specified number
of times; and, verifying merged label information.
12. The method of claim 11 wherein the tracking step further
comprises the step of decrementing the number of times a particular
decoded character information has been stored in association with
the same position information upon decoding a different decoded
character information in association with the same position
information.
13. The method of claim 12 further comprising the step of replacing
the stored decoded character information in association with
position information with a new decoded character information in
association with the same position information when the number of
times the stored decoded character information has been stored is
decremented to zero.
14. In a bar code scanning system, a method of assembling label
information from partial scans of label data which may comprise
some undecodable characters the method comprising the steps of:
receiving scans of label data comprising character information;
decoding the scans of label data and storing decoded character
information in association with position information; and, merging
the new scan of label data with the stored scan of label data.
15. The method of claim 14 further comprising the step of
performing a merge check prior to merging in order to determine if
a specified percentage of decoded characters in a new scan of label
data match in value and position to those of a stored scan of a
label to be merged.
16. The method of claim 14 further comprising the step of verifying
and accepting the merged label data.
17. The method of claim 16 wherein the step of verifying and
accepting merged label data is performed in accordance with
preestablished rules.
18. The method of claim 16 wherein the step of verifying and
accepting merged label data requires less stringent criteria with
respect to scans of label data decoded from consecutive scans than
with respect to scans of label data decoded from non-consecutive
scans.
Description
RELATED APPLICATION
[0001] This application claims the benefit of U.S. Provisional
Application No. 60/100,288, filed Sep. 14, 1998.
COPYRIGHT NOTICE/AUTHORIZATION
[0002] A portion of the disclosure of this patent document contains
material which is subject to copyright protection. The copyright
owner has no objection to the facsimile reproduction by anyone of
the patent document or the patent disclosure, as it appears in the
Patent and Trademark Office patent file or records, but otherwise
reserves all copyright rights whatsoever.
SOFTWARE APPENDIX
[0003] This application includes a Software Appendix section at
pages 81 through 193.
FIELD OF THE INVENTION
[0004] The field of the present invention relates to data reading
devices and, in particular, to optical code scanners or other label
scanning and decoding systems of the type that are designed to read
labels having information which may be presented in any one of a
number of different codes commonly in use. More particularly, it
relates to a system and methodologies for reconstructing complete
bar code label information from partial scan information obtained
under of variety of non-ideal situations.
BACKGROUND OF THE INVENTION
[0005] Existing labels encode information in a variety of formats
and are commonly employed in applications such as inventory control
systems and, most familiarly, affixed to consumer goods for retail
store check-out, among others. Typically, the information encoded
on each label uniquely identifies the product or product line. Such
information, once decoded, can be used to identify other
information, e.g., price, associated with the labeled object.
[0006] Optical scanning systems use various apparatus and methods
for the purpose of reading such labels, identifying the particular
label format, and decoding the information stored in the label. In
the case of bar code scanners, for example, a typical system has
one or more light sources, such as a laser or laser diode, which
are used to scan the label. Traditional labels are ordinarily
composed of a series of parallel dark and light areas, e.g., bars
and spaces. A collection subsystem detects at least a portion of
the light reflected from the label, distinguishes between dark and
light areas, and converts the optical information into an
electrical signal that can be recognized by a computer or other
electronic system.
[0007] Labels, e.g., bar codes or other such symbols, commonly
include characters (which can, e.g., be alphanumeric) defined by a
number of elements, e.g., bars and spaces. For any given symbology,
individual characters within a label are comprised of a given
number of elements, and the width of each of these elements is
expected to be within a known range, thus allowing the character to
be reliably decoded. Exemplary of this is the Universal Product
Code (UPC) label in which each character is made up of two bars and
two interleaved spaces. The width of each character is measured in
units called "modules" with each character being seven modules in
width. The width of any particular bar or space within the
character representation is between one and four modules. The
character value depends on the relative width in modules of the two
bars and two spaces it comprises. For example, indicating bars with
a 1 and spaces with a 0, a sequence of 111 would represent a bar
that is three modules in width.
[0008] If either of the above characteristics is violated (i.e.,
number of elements per character and/or width of elements in known
range), typically the character in question will be considered to
be undecodable and the entire scan of data will be discarded.
Factors that could cause this are: if an individual element has
been split into multiple pieces; multiple elements have been merged
into a single piece; or, if the width of an element has been
distorted beyond specified boundaries. In any of these instances,
some existing systems may require a new scan--discarding the entire
scan as unusable--even though only one character may be affected by
the degradation.
[0009] Some codes make use of parity formats to form alternative
representations for the digits 0 through 9. These alternate formats
may be utilized in different locations on a label thus providing
means for verifying accuracy of data. For example, UPC labels, with
the exception of UPC-E labels, are comprised of right and left
segment halves. Characters in the left segment are of odd parity
and, when scanned from left to right, all begin with spaces.
Characters in the right segment are of even parity and, when
scanned from left to right, all begin with bars. Thus, the
character value 5 may be represented as 0 110001 using odd parity
or 1 00 1110 using even parity. Likewise, the character 3 may be
represented as 0111101 using odd parity or 1000010 using even
parity.
[0010] Additionally, many labels utilize feature characters, such
as center or guard characters, as delimiters or to separate
segments of the label. Most UPC labels, as noted above, have left
and right segment halves. These segment halves are separated by a
center band character that typically comprises two single module
bars and three interleaved single module spaces. The beginning and
end of the label are delimited by a pair of guard characters, each
of which typically comprises two single module bars and one
interleaved, single module space. The bar/space representations of
these feature characters are unique from that of data characters to
enhance detection and decoding capability. Furthermore, an
unprinted margin area or white space is typically located outwardly
of the two guard characters.
[0011] In addition to the UPC formats, a variety of other label
formats exist which vary, among other ways, in structure, content,
parity requirements, and type of feature characters. Code 39 and
Code 128, for example, are both non-segmented label formats, i.e.,
they have no center feature characters separating two or more
segments of bars. Other label encoding schemes have been developed
which have differing pattern structures for the dark and light
areas. Exemplary of these latter code types are the stacked bar
code formats referred to as Code 49 and PDF 417.
[0012] As a practical matter, recovering information from optical
code labels poses many difficulties that must be overcome by a
scanning system. For example, in order to read a label completely,
i.e., from left guard character or margin to right guard character
or margin, in a single optical pass, the label must be properly
oriented with respect to the scanning beam. Failure to read in a
single pass, e.g., when a label is mis-framed or read diagonally
across a top or bottom border, results in the reading of incomplete
or degraded character data and yields partial scans of the label
which must be assembled properly in order to formulate valid label
information, otherwise the object must be re-positioned and
re-scanned until a successful read is obtained. In such cases, data
on either end of an input string may be inaccurately read, yet may
appear to be an otherwise structurally valid character.
[0013] Even where a single optical pass does traverse the entire
label from left to right, problems in decoding the label may occur,
for example, when the label is folded, split, torn or similarly
damaged, thus making it difficult to recover label information.
Likewise, differences in package configurations, label sizes and
locations, and scanner positions, among other factors, serve to
exacerbate these problems. As a result, partially read labels are
both more likely to occur and more difficult to decipher. In many
applications, such as store check-out stands, this translates to a
need for high operator concentration and dexterity yet results in
non-optimum speed or efficiency, since the operator must take care
to ensure that the object to be scanned is properly positioned (or
must reposition and rescan repeatedly for a valid reading). As
well, the multitude of optical code formats currently in use may
require differing methodologies to be used in order to realize
ideal (i.e., optimum speed and efficiency) decoding. In settings
where multiple formats may be encountered by the same operator,
additional effort and skill may be required to ensure that the
system is set for the ideal decoding methodology to be utilized for
a particular symbology.
[0014] Certain methods of assembling or concatenating data read on
partial scans have been proposed to address these difficulties.
However, existing methods are inherently limited in their ability
to detect and correct for inaccurate and, particularly, missing
data reads within partial scans. As well, to the extent that some
existing systems have devised more aggressive methods of decoding
poor quality or damaged labels, such methods are typically employed
at the expense of speed and efficiency in processing good quality,
clean labels.
SUMMARY OF THE INVENTION
[0015] To address the above and many other problems that may be
encountered in order to accurately decode a bar code label, the
present system provides for a variety of complementary
reconstruction methodologies that may be selectively and
systematically employed. Aside from known standard decoding
algorithms which provide for direct decoding of clean label
information obtained from a single scan, the system and method of
the preferred embodiment further provides for implementation of
known stitching techniques to combine multiple partial scan
fragments into complete labels.
[0016] In addition, the system provides novel reconstruction
methods, which are capable of reconstructing label information such
as undecodable characters or elements where label defects may
otherwise prevent full information from being decoded. Such
reconstruction methods allow for undecodable characters or elements
to be reconstructed from partial information based upon known or
expected structural characteristics for the particular label
symbologies being decoded, as well as through the use of
correlation techniques utilizing information obtained from multiple
scans of a label. As well, the preferred embodiment offers
stitching techniques at the character and element level to aid in
the reconstruction of label information.
[0017] A means of providing for correction of information at the
leading and trailing ends of a label, which might otherwise be
distorted and unreadable due to mechanical aspects of the scanning
line mechanism, is further provided in a preferred embodiment
herein to assist in obtaining complete label information in an
efficient and accurate manner. In conjunction with such system and
methods as indicated above, the preferred embodiment further
provides unique features, such as the use of edge strength
indicators and quality measures to enhance label readability and
bar code scanner decoding capabilities.
[0018] In another aspect, a preferred embodiment herein provides
for systematic selection of the decoding techniques to be employed
in the process of decoding particular label symbologies. To this
end, any number of differently aggressive decoding techniques may
be selected, either manually or automatically, to decode label
symbologies.
[0019] A preferred embodiment provides for decoding of a digital
representation of an input signal to be attempted at first with
decoding of the part or all of the analog signal being undertaken
only after a number of attempts at the digital signal prove
unsuccessful. In this manner, system resources and decoding time
may be saved.
[0020] The type of decoding techniques to be employed may also be
set, for example, based on aggressiveness, in a preferred
embodiment. In one approach, the system may be set up to attempt
less aggressive, more secure, techniques (such as standard decoding
techniques) first with more aggressive, less secure techniques
(such as character/element reconstruction) being implemented
sequentially and systematically should a label fail to be
successfully decoded after a number of attempts with less
aggressive techniques. Alternatively, beginning and/or ending
aggressiveness level to be used may be set, by the user or
otherwise, based upon the symbology to be read.
[0021] In another approach, the system may be programmed as to
aggressiveness levels to be used. In this regard, a starting
aggressiveness level and/or maximum aggressiveness level, or both
may be programmed. It is envisioned that such programming may,
e.g., be based upon user entry by of information regarding the
symbology to be read.
[0022] In yet another approach, the system may be programmed to
learn the aggressiveness level (e.g., starting level, maximum
level, or both) to be utilized with respect to a particular group
of labels. Such learning may be accomplished, for example, through
scanning of an exemplary label with the scanner set in a learning
mode whereby the system may assess the appropriate level of
aggressiveness required to successfully decode labels of that type.
As an alternative to a discrete learning mode, an ongoing learning
mode approach may be implemented whereby information about the
aggressiveness levels needed to decode would be constantly
accumulated as the scanner operates. In accordance with such latter
approach, the scanner would adjust itself automatically as label
quality changed.
[0023] In a still further aspect of the present system and methods,
feedback from decoding may also be used to adapt various signal
processing parameters. For example, gain, threshold and other
signal processing parameters may be automatically adjusted within
the scanner based upon feedback from decoding in order to enhance
future decodability of label information.
[0024] Through the use of the systems and methods detailed herein,
the most efficient means of decoding particular labels may be
identified and utilized. In turn, less time is required for the
decoding process since the time otherwise required to attempt
decoding which is not likely to be successful may be
eliminated.
[0025] Accordingly, the present system and methodologies provide
one or more of the following objects and advantages:
[0026] to accurately recognize and decode optical labels;
[0027] to provide multiple methodologies for reconstructing
complete bar code information from partial bar code information
obtained from either a single scan or multiple partial scans;
[0028] to provide such multiple methodologies for reconstructing
complete bar code information in such a manner that the
methodologies are implemented in an order from most efficient to
less efficient until complete bar code information is obtained;
[0029] to provide accurate assembly of label information from
multiple partial scans with confidence that the entire label has
been scanned, no data has been duplicated, and the data has been
put into the correct order;
[0030] to have the capability and versatility to reconstruct labels
of various formats including multi-block labels as well as
single-block labels and others;
[0031] to improve reconstruction performance by using symbology
characteristics and detected label information to build up labels
with a valid high level structure;
[0032] to allow a bar code scanner to stitch label fragments that
have some undecodable characters present;
[0033] to stitch symbologies configured for variable length;
[0034] to allow less stringent stitching requirements for fragments
that are decoded from consecutive scans compared to fragments that
are decoded from non-consecutive scans;
[0035] to perform reconstruction of label information in a speedy
and efficient manner while alleviating pressure on scanner operator
to accurately align the labeled object;
[0036] to increase read successes and improve accuracy of
reconstruction in situations where label condition is degraded by
tears, splits, folds, spots, voids, etc.;
[0037] to provide a system and methodologies for decoding labels
whereby more aggressive decoding techniques may be implemented only
after less aggressive techniques fail; and,
[0038] to provide a system and methodologies whereby the
appropriate aggressiveness level to be used for decoding particular
symbologies may be learned by the system.
[0039] Other objects and advantages of the present system and
methodologies will become apparent from a review of the
accompanying drawings and the detailed description that
follows.
BRIEF DESCRIPTION OF THE DRAWINGS
[0040] FIG. 1 is a graphical representation illustrating exemplary
Element Width Histograms in accordance with an aspect of the system
and methodologies herein.
[0041] FIG. 2 is a flow chart diagram illustrating exemplary
functional blocks for decoding with character reconstruction in
accordance with the system and methodologies herein.
[0042] FIG. 3 illustrates an exemplary poor quality label upon
which an aspect of the character reconstruction methodologies
herein may be advantageously implemented.
[0043] FIG. 4 is a flow chart diagram illustrating further
exemplary functional blocks of one implementation of character
reconstruction in accordance with system and methodologies
herein.
[0044] FIG. 5 pictorially represents exemplary processing of scan
lines using correlation and stitching techniques in accordance with
the system and methodologies herein.
[0045] FIG. 6 is a flow chart diagram illustrating the functional
blocks of exemplary merge and stitching aspects of the systems and
methodologies herein.
[0046] FIG. 7 is a flow chart diagram illustrating a portion of the
functional blocks of an exemplary element level processing with
quality measuring routine in accordance with the system and
methodologies herein.
[0047] FIG. 8 is a flow chart diagram illustrating a second portion
of the functional blocks of an exemplary element level processing
with quality measuring routine in accordance with the system and
methodologies herein.
[0048] FIG. 9 is a flow chart diagram illustrating a portion of the
functional blocks of an exemplary increased aggressiveness level
decoding through time process implemented in accordance with the
system and methodologies herein.
[0049] FIG. 10 is a flow chart diagram illustrating a second
portion of the functional blocks of an exemplary increased
aggressiveness level decoding through time process implemented in
accordance with the system and methodologies herein.
[0050] FIG. 11 is a flow chart diagram illustrating a third portion
of the functional blocks of an exemplary increased aggressiveness
level decoding through time process implemented in accordance with
the system and methodologies herein.
[0051] FIG. 12 is a flow chart diagram illustrating a fourth
portion of the functional blocks of an exemplary increased
aggressiveness level decoding through time process implemented in
accordance with the system and methodologies herein.
DETAILED DESCRIPTION OF THE PREFERRED EMBODIMENT
[0052] The preferred system and methodologies provided herein
utilize Element Level Processing as well as Character Level
Processing as a basis for the reconstruction and decoding
techniques provided.
[0053] Element Level Processing
[0054] Element Level Processing is accomplished in an aspect of the
preferred embodiment through the use of an Element Width Histogram,
as illustrated in FIG. 1 and described hereinbelow, wherein the
widths of the elements of a bar code are captured in a data store
on a width basis. The bar code scanner may be enabled to maintain
histogram information for a number of potential labels. Such
information may, for example, be utilized in order to aid in the
decoding of poor quality labels. It is envisioned that separate
histogram information may be kept for bars and spaces of each
potential label and that information may be collected and
maintained for a number of label scans. As further detailed
throughout this specification, such histogram information may be
used to determine the number of element widths in the label as well
as average element widths. In addition, such histogram information
may be helpful in determining symbology, i.e., for example, whether
a particular label being scanned comprises a binary or a
multi-width symbology.
[0055] Optionally, the scanner may further capture edge confidence
levels along with element edge times. Typically, bar code scanners
collect only edge timing information that may then be utilized to
determine, for example, element widths. However, use of edge timing
information alone may limit the ability of such scanners to decode
poor quality labels whose edges may be distorted. While other
scanners may exist that collect edge strength information as well,
these scanners typically involve making multiple passes through the
data at different threshold levels using standard decoding
algorithms.
[0056] As provided further hereinbelow, label reconstruction
decoders may include an edge-matching algorithm, which may be
invoked when attempting to decode poor quality labels. When bar
code data is not decodable using a standard decoding algorithm,
this algorithm will attempt to determine the encoded character
based upon the edge timing information. In a further aspect of the
preferred systems and methods herein, edge strength information may
be collected for use in conjunction with the reconstructive
decoding algorithms and may be made available to the edge-matching
algorithm, thus increasing the probability of correctly decoding
the character in question. Such technique would require only a
single pass through the data, using more sophisticated
reconstructive decoding algorithms, thus being more efficient and
increasing the probability of correctly decoding the bar code with
fewer scans of data. In turn, the ability of the bar code scanner
to decode label data that may not be decodable using standard
decoding algorithms may be improved.
[0057] Edge strength, or confidence levels, for each element may be
determined through many methods. One confidence indicator is the
first derivative strength of the return laser signal. Edge
confidence level information can also be used to calculate an
average edge confidence level for the common elements of the label.
The average edge confidence level may be calculated for binary and
multi-width symbologies using the edge confidence levels of the
element widths selected for binary and multi-width symbologies,
respectively.
[0058] It is noted that edge confidence level information may be
advantageously utilized at different points in the scanning and
decoding process. Such edge confidence level information may
further advantageously be generated in different ways at the
different points in the process. For example, when generating the
histogram, the confidence level of an element might be simply the
comparison of that element's edge strength with average element
edge strength. In the decoders, though, the confidence level of an
element might be the product of the deviation of an element's width
from a target and the deviation of an element's edge strength from
a target. In the correlation and stitching process, the confidence
level of a character might, in turn, be the sum of the confidence
levels of the individual elements. Still further variations of
generating confidence levels may be envisioned by one skilled in
the art.
[0059] Further in regard to the use of information that may be
obtained through the histogram analysis as set forth herein, the
number of element widths may, for example, be utilized in
determining the symbology that is being scanned so that the correct
symbology specific decoder may be executed. Alternatively, the
number of element widths may provide the means for rating enabled
symbologies to be executed in order as further detailed herein. The
average element widths may, for example, be utilized to help find
characters and/or start/stop patterns in poor quality labels and/or
to set acceptable ranges for element widths within the label. The
average edge confidence level may, for example, be utilized to help
identify the significant edges of the label and to filter out noise
edges in the label.
[0060] The number of elements in a given range of widths is stored.
The total sum of the widths in a given range may also be stored. In
establishing the histogram parameters, a minimum range for element
widths may be determined, for example, by using 1/4 of a narrow
element in the start/stop pattern. As indicated previously,
histogram information may be maintained for a number of potential
labels. In such case, a separate histogram is kept for bars and
spaces of each potential label. Upon commencement of collection,
histogram information is collected for sets of label scans, e.g.,
each set of four label scans.
[0061] In accordance with a preferred embodiment, the histogram
analysis comprises three primary steps: gathering the element width
data and, optionally, confidence level information for the element
edges; finding the peaks in the histogram; and, decoding the peaks
in the histogram. A representative overview of the histogram
information that may be maintained in accordance with a preferred
embodiment herein may be understood as follows. As noted, histogram
information may be maintained for a number of potential labels. The
histogram may be envisioned as having a series of buckets wherein
each bucket represents elements of a particular range of element
widths. It is intended that the series of buckets in the histogram
cover the possible element widths for a particular potential
scanned label. Separate histograms may be kept for bars and spaces
of each potential label. Several scans of a potential label may be
combined in the histograms to provide a larger set of elements for
the histograms.
[0062] With respect to the first step of gathering element width
data, the quiet zones of a potential label are first identified,
e.g., in accordance with known methods. Then, when the elements of
a potential label have been identified, the element width data is
gathered and the element widths are added to the histogram. If
enabled, as indicated above, optional confidence levels may also be
added to the histograms. The histogram information is updated with
the number of elements in each bucket of the histogram, as well as
the total sum of all elements in the bucket. Thus, the histogram
information may include, for example, the number of elements in
each bucket, the total sum, optionally the edge confidence level of
the elements in each bucket, and the element width range for each
bucket.
[0063] In addition to application as detailed above, confidence
level information may further be utilized as a filter to help
determine which data is accepted into the histogram. For example,
elements of a potential label may be identified and the average
edge strength of such elements may then be determined. If the edge
strength of any particular individual element being examined for
addition to the histogram is not within a calculated tolerance of
the average edge strength, that element would not be included into
the histogram. In this manner, the confidence that the histogram
would be generating accurate information for use in later
processing is increased.
[0064] FIG. 1 provides an exemplary graphical representation for an
Interleaved 2 of 5 Label histogram 5 along with an exemplary
graphical representation for a UPCA Label histogram 10. The
histograms 5 and 10 record information regarding the number of
elements 15 within enumerated ranges of element widths 20. It is
noted that the histograms 5 and 10 illustrate the low end of
element width ranges and that additional ranges that are not shown
may include additional information. Further, the values that are
indicated for the range of element widths 20 represent the lower
value of that corresponding range (thus, the value 156 is shown
below the range which is from 156 through 232). As may be seen from
FIG. 1, separate bar information 25 and space information 30 is
gathered, maintained and recorded. By way of example, it may be
seen that the space information 30 for the Interleaved 2 of 5 label
histogram 5 shows that with respect to the 1244 range 35 the number
of elements 15 is recorded as a 10 value 40. Thus, 10 space
elements falling within the 1244 range 35 have been recorded and
identified in relation to Interleaved 2 of 5 label scans by the
system.
[0065] With respect to the second step of finding peaks in the
histogram, a first preferred method is to generate 2-bucket sums of
the number of elements in the buckets for the bar and space
histograms. The 2-bucket sums are then searched to find all peaks
and an average element width is calculated for each peak. Peaks may
then be selected by choosing all 2-bucket sums that are greater
than both neighboring 2-bucket sums. If there is a set of 2-bucket
sums that are equivalent but greater than the 2-bucket sums
neighboring the set, the middle bucket of the set may be selected
as a peak. Alternatively, a second method utilizes the confidence
levels of elements as indicated above, instead of the number of
elements, and follows the same steps described above in relation to
2-bucket sums to identify peaks in the histogram information.
[0066] While alternate preferred methods for finding peaks in the
histogram are set forth above, it is noted that many other possible
methods for finding histogram peaks may be envisioned and
implemented without departing from the spirit and scope of the
systems and methods as set forth herein.
[0067] With respect to the third step of decoding peaks of the
histogram, the average element width for each peak is calculated
and stored. Element averages of the peaks and their relative
spacing, the number of elements in the peak, and the similarities
between bars and spaces may be utilized to determine which peaks
could represent the element widths for the label. Based on the
results obtained, the type of symbology may be identified as
binary, multi-width, or unknown. Thus, the peaks may be decoded to
determine the ones that represent binary and/or multi-width
symbologies.
[0068] Peaks of the histogram may be decoded by matching element
widths of the peaks with potential element widths for either binary
or multi-width symbologies. Wide to narrow ratios of element widths
may, for example, be used to find such match. A further component
of such match may be which element widths are the most common in
the histogram or which element widths have the largest confidence
level. A still further component of such match may be which element
widths are common to both the bar and space histograms. The
consistency of bar and space element widths and the number of
unused histogram peaks may be used to determine the quality of the
identified element widths as either binary element widths or
multi-width element widths. The quality of the element widths may,
in turn, help to determine the type of symbology.
[0069] With reference back to FIG. 1, the manner in which the
histogram information may yield a determination of the type of
symbology (binary or multi-width) may be understood through the
following example. To determine if a binary symbology is
represented by a histogram, the biggest peaks for bars and spaces
are considered.
[0070] The Interleaved 2 of 5 Label histogram 5 of the top graph of
FIG. 1 represents a binary symbology. Considering the two biggest
peaks of the Interleaved 2 of 5 Label histogram 5 of FIG. 1, the
biggest bar peaks are approximately at widths 349 and 816. The
biggest peaks for spaces are at widths 582 and 1049. By observing
that the 349 bar peak is close to the 582 space peak and the 816
bar peak is close to the 1049 space peak, it may be determined that
the 4 peaks are very good candidates of a binary symbology. In
addition, the difference in widths of the bars (816-349=467) is
very similar to the difference in widths of the spaces
(1049-582=467). Another observation is that the wide to narrow
ratio of the bars (816/349=2.3) and spaces (1049/582=1.8) are
similar to each other and are within acceptable tolerances (i.e.,
1.5 to 5.0) for binary symbologies.
[0071] The consideration of multi-width symbologies follows a
similar approach. However, for multi-width symbologies there are
normally 4 widths that have width ratios of 1:2:3:4 for
width1:width2:width3:width4. The comparison between two widths in a
binary symbology must be extended to three or four widths in a
multi-width symbology. At least the first 3 widths of a multi-width
symbology are normally required to be represented by peaks in the
histogram for a multi-width symbology to be detected.
[0072] If only a binary symbology is detected, a binary symbology
is the result. If only a multi-width symbology is detected, a
multi-width symbology is the result. If both a multi-width
symbology and a binary symbology are detected, a multi-width
symbology would be the result because width1 and width2 of a
multi-width symbology looks just like a binary symbology.
[0073] In a further aspect, the use of variable element congruence
may allow a range to be set for each element size, may be utilized
with respect to either binary or multi-level codes, and may allow
the decoder to be adjusted for aggressiveness vs. adherence to
specification. The use of variable element congruence may better be
understood as detailed hereinbelow.
[0074] A typical method of decoding bar codes is to compare each
element width with a set of thresholds to create a normalized set
of element widths that may then be compared against tables of valid
characters for that symbology. The thresholds for each normalized
element size determine the degree of congruence of the elements
accepted as that width. By varying these thresholds, it is possible
to allow the decoders to be more aggressive at the risk of
increased misreads, or to be more conservative but at the risk of
not reading some labels of marginal quality. For example, when
decoding Code 39, possible narrow element widths for one character
could be 77, 85, 98, 105, 110 and 122, while wide elements widths
could be 273, 298 and 312. Thresholds that would correctly decode
this character could be 70 to 130 for narrow elements, and 270 to
330 for wide elements. However, this character has a wide to narrow
ratio that is greater than allowed according to the specification
for this symbology. Therefore, adjusting the thresholds such that
this character would decode also increases the likelihood of
decoding errors. Because of this, the option of adjusting the
thresholds for aggressiveness versus adherence to specification, as
further detailed herein, could be made accessible to the user, and
implemented as needed according to knowledge of the quality of
labels being scanned.
[0075] Upfront Symbology Determination
[0076] Determining the correct symbology or eliminating symbologies
up front can result in minimization of the decoding and
reconstruction time. The preferred embodiment attempts to determine
the symbology type as the label data is being collected. To this
end, one or more of the techniques identified below may be used to
determine the symbology type after leading and trailing quiet zones
have been identified. It is envisioned that the likelihood of a
specific symbology type(s) may also be configured by the customer
or otherwise to aid in symbology determination.
[0077] 1. Looking at the start and stop pattern of potential labels
and comparing such patterns to those of known enabled
symbologies.
[0078] 2. Using the element width histogram to determine if the
symbology is binary or multi-width as detailed hereinabove.
[0079] 3. Looking at the number of elements in potential labels to
determine if it is a possible length for specific enabled
symbologies.
[0080] 4. Determining which symbologies could have a label of the
length, e.g., in time, observed in the potential label.
[0081] 5. Using the element counts determined by the histogram and
the total count for the entire label to calculate the length for
comparison to a specific enabled symbology.
[0082] 6. Looking at the number of characters that were decoded in
previous scans (in which case characters from some symbologies may
be assigned more weight than others, or symbologies with the most
decoded characters may be assigned a higher weighting than other
symbologies).
[0083] 7. Using the average element widths determined by the
histogram to determine if the time count of the entire label
accommodates the start, stop, and a number of character widths for
a specific enabled symbology.
[0084] 8. Using historical reading patterns to weight the probable
symbology to read.
[0085] 9. Identifying the number of labels historically decoded for
each enabled symbology.
[0086] 10. Utilizing character equality checks.
[0087] In accordance with the preferred system and methods herein,
the bar code scanner attempts to determine the symbology type after
leading and/or trailing bars of a label or label segment have been
identified. Potential symbologies of the label data are identified
and ordered, e.g., with the most probable ones first, using a
variety of the above and other indicators as further described
hereinbelow. The potential symbologies are ordered with the most
probable ones first so that the symbology decoders with the highest
chance of success may be executed first. It is envisioned that in
some cases the symbology decoders for the lowest probable
symbologies may optionally not be executed at all. Such operation
allows the scanner to spend more time decoding the label data for
specific symbologies compared to previous scanners where decoding
of each enabled symbology was attempted for every set of label
data. Particularly with respect to poor quality labels, the
determination of the symbology allows the scanner to spend more
time decoding the poor quality label with the correct decoder and
skip some of the decoders that have a minimal chance of success.
Such operation further allows the scanner to discard some label
data if none of the indicators show a probable symbology.
[0088] In accordance with the preferred embodiments herein, the bar
code scanner determines ratings from each indicator for each
symbology type. The ratings are then accumulated for each symbology
and are put in order (e.g., highest ratings to lowest ratings). The
decoders from the symbologies with the highest ratings are executed
first. The decoders from symbologies with the lowest ratings are
executed last or, as indicated previously, may not be executed at
all.
[0089] The indicators envisioned by the present system and methods
include: start/stop pattern, element width histograms, number of
elements in label, length of label in time, number of labels
decoded for each symbology, number of characters decoded in
previous scans for each symbology, and character equality checks.
The manner in which each indicator may be utilized in accordance
with a preferred embodiment herein is further described below. It
is noted that multiple indicators may be used to determine the
symbology of poor quality labels.
[0090] With respect to the start/stop pattern, the templates for
the start and/or stop patterns of enabled symbologies are compared
against the leading and trailing bar and space elements of the
label. The template comparison may allow for missing elements,
extra elements, and elements that may be the wrong size. The
symbologies with start/stop patterns that match the best will have
the highest rating.
[0091] With respect to element width histograms, ratings from the
element width histogram, as detailed above, may be utilized to
provide an indication of which symbologies are the most
probable.
[0092] With respect to the number of elements in the label, the
number of elements in the label may be matched against the set of
possible numbers of elements for each enabled symbology. A rating
for each symbology results. It is noted that this indicator will be
accurate when there are no spots or voids in the label.
[0093] With respect to the length of the label in time, the element
width histogram may be utilized to determine the element widths of
the label. The character length and start/stop pattern length for
each symbology may also be determined using the element widths from
the histogram. The length of the label in time will be compared
against the possible combinations of character lengths and
start/stop pattern lengths for each enabled symbology to determine
if the label is a correct length for each symbology. The closeness
to a correct length may be used to determine the rating of each
symbology for this indicator.
[0094] With respect to the number of labels decoded, the number of
labels that have been decoded for each symbology may be used to
determine a rating of each symbology.
[0095] With respect to the number of characters decoded in previous
scans, such number of characters decoded may be used to cause a
rating to be generated for each enabled symbology indicating the
most probable symbology for future scans of the correct label. To
this end, as the scanner decodes data from scan lines it will keep
track of the number of characters decoded in each enabled
symbology.
[0096] With respect to character equality checks, the bar code
scanner may check for character equality across a portion or all of
the label data for each enabled symbology. A rating for each
enabled symbology may be generated based on the character equality
results.
[0097] One method of implementing indicator ratings for symbology
detection is to set each indicator to generate a result from 0 to
99 for each symbology wherein, for example, highest numbers
indicate highest probabilities and lowest numbers indicate lowest
probabilities. In addition, each indicator will have a weight, for
example, from 1 to 10 for each symbology. To determine the
symbology with the highest probability of success, a result will be
generated for each symbology by obtaining the sum of the products
of each indicator result and its corresponding indicator
weight.
[0098] Implementation of indicators to determine symbology type may
be better understood through the following exemplary illustration.
For purposes of such example, a system utilizing start/stop
patterns, the histogram, and number of elements as indicators of
symbology type may operate as follows. First, with respect to each
indicator that is utilized, a weighting factor is established and
set for that indicator in relation to each potential enabled
symbology, respectively. Thus, with respect to start/stop patterns,
a weight of 2 for a UPCA symbology and 10 for a Code39 symbology
may be assigned. With respect to the histogram, a weight of 8 for a
UPCA symbology and 5 for a Code39 symbology may be assigned. With
respect to the number of elements, a weight of 4 for a UPCA
symbology and 2 for a Code39 symbology may be assigned. It is
further assumed that both the UPCA and Code39 symbologies are
currently enabled in the system of this example.
[0099] When a section of label data is being considered, the
results of the various indicators are generated and analyzed. The
following results are assumed to have been generated for the
various indicators in relation to the UPCA symbology and the Code
39 symbology. With respect to UPCA: start/stop pattern=40,
histogram=75, and number of elements=20. With respect to Code 39:
start/stop pattern=60, histogram=40, and number of elements=40.
Accordingly, the sum of products for UPCA is: 760 (i.e.,
2*40+8*75+4*20) and the sum of products for Code39 is: 880 (i.e.,
10*60+5*40+2*40). Such symbology detection would indicate that the
Code 39 symbology is the best choice with the UPCA symbology being
the second choice for a symbology. It may be readily seen that the
above example may be expanded to include additional indicators, as
identified above, and/or that additional symbologies may be enabled
and included in the symbology determination.
[0100] Character Level Processing
[0101] In accordance with the systems and methods herein, the
scanner decodes as many characters of a bar code as possible from a
single scan of the label. However, some characters may not be
decodable due to a poor quality or damaged label, or as a result of
the laser beam exiting the area of the label during scanning. If
the scanner cannot decode a character, it advances to the next
decodable character in the scan line to continue decoding.
[0102] As utilized herein, the following terms are defined as:
[0103] A Full Length Label is one that has been decoded over its
entire, known length.
[0104] A Fragment is a label that has been decoded over part of the
entire length.
[0105] A Label comprises either a Full length label or a
Fragment.
[0106] A Decoded Character is a character that has been
successfully decoded within a Label.
[0107] An Undecodable Character is a character which has not been
successfully decoded, e.g., due to defects in the label at the
location of such character that prevent decoding.
[0108] An Undecodable Character Identifier is a special identifier
that is set with respect to an Undecodable Character(s).
[0109] Stored Labels are Fragments and Full Length Label characters
that are stored during the processing of Labels. Additionally, a
store is established for each character position to store the
number of scans that have included the stored character.
[0110] A Correlation Store is a store for all Full length labels
and Fragments that are candidates for correlation when new labels
are processed. In one embodiment, a separate correlation store may
be established for a left Fragment and a right Fragment in each
symbology. Alternatively, a list of Labels could be implemented
such that the list comprises Labels that could be merged with a new
Label. In such latter instance, sufficient storage is provided for
Labels in the list that won't merge.
[0111] Merging Length is the number of characters that will be
merged when Fragments and Full length labels are merged.
[0112] Variable Length is an attribute of some symbologies that
have Labels with lengths in a certain range. This set also includes
variable length symbologies that have been configured in the
scanner to have a limited range of lengths.
[0113] Fixed Length is an attribute of some symbologies where there
is only one possible length of the label. This set also includes
the variable length symbologies that are configured in the scanner
to read only a certain number of lengths.
[0114] Overlapping Region is the section at the end of each
Fragment that overlap in the stitched label when two Fragments are
being considered for stitching.
[0115] Matching Decoded Characters are the characters of the
Overlapping Region that match in value and position in each
Fragment when two Fragments are being considered for stitching.
[0116] Non-Matching Decoded Characters are the characters of the
overlapping region that are not Matching Decoded Characters in each
Fragment when two Fragments are being considered for stitching.
[0117] Character Equality, Reconstruction, Correlation and
Stitching
[0118] CHARACTER EQUALITY (i.e., does character have correct
width?)
[0119] Character equality is further utilized by a preferred
embodiment in the process of reconstructing Undecodable Characters.
When decoding a label, the decoder steps through the label data a
character at a time. In accordance with one aspect of the system
and methodologies herein, the character width, instead of the
number of elements, is used to find the next character. The
expected character width can be determined, e.g., by using the
previous character width, or a multiple of a previous element
width, or a multiple of the widths identified by the histogram. If
there is not a bar-to-space or space-to-bar transition at the
expected location, the decoder may be set to assume a transition
and attempt to decode a character. Alternatively, the decoder may
skip to the next expected character boundary and look for a
transition prior to attempting a character decode or
reconstruction.
[0120] When checking for character equality, the number of elements
required to match the previous character width is determined. If
this number is not correct, then it is determined that some of the
elements are corrupted and the character cannot be decoded as it
is. For example, a Code 39 label requires nine (9) elements to
match the width. Thus, if the number of elements identified with
respect to the undecoded character is not nine (9), then the
character cannot be decoded as it is and some reconstruction
technique must be utilized to determine the value of the undecoded
character.
[0121] At an element level, the system and methodologies herein may
determine whether or not the pattern of bars and spaces in a
particular character being decoded match a pattern in the valid
character set.
[0122] Character Reconstruction
[0123] In accordance with a further aspect of the system and
methodologies herein decoding of poor quality labels through
reconstruction of normally undecodable characters is provided. To
this end, scans in which an individual character containing a
corrupted element(s) are identified, and which might otherwise
result in the entire scan being discarded, may be identified and
decoded by reconstructing the originally intended element widths
and structure from the corrupted data. Thus, in situations wherein
either the expected number of elements for a character, or the
expected range of widths for each element of a character, is
violated (e.g., as a result of an individual element being split
into multiple pieces, multiple elements being merged into a single
piece, or the width of an element being distorted beyond specified
boundaries), the system and methodologies accept such undecodable
character among other decodable characters and, through knowledge
of the width of the total character, and the specifics of the
symbology, determines expected widths for the elements in the
character. By comparing the actual element widths against the
expected widths, it may be possible to determine which elements may
be in error, and what the most likely intended widths and structure
of those elements may be. The element widths and structure may then
be reconstructed and the reformed character decoded. One advantage
of this technique over others is that it allows a label to be
decoded from a single scan of data, while other similar concepts
require multiple scans of data for comparison.
[0124] Character reconstruction is accomplished, e.g., by ordering
the width of the elements of a character. The number, placement,
and size of wide and narrow elements may be used to determine which
elements should be combined or adjusted to make a valid character
for a specific symbology. Alternatively reconstruction may be
accomplished through comparison of the bar-space pattern of the
undecodable character against all possible characters for the
symbology. A measurement of the comparison identifies the closest
match. This measurement is then stored across scan lines with the
character correlation information. When the closest character is
seen a number of times, it is accepted. The measurement method
could be the total count error in the comparison of the character's
bar-to-space and space-to-bar transitions to that in the collected
data. If there are extra transitions in the collected data, they
are ignored because they are probably spots or voids.
[0125] The flow diagram of FIG. 2 illustrates exemplary functional
blocks for decoding with character reconstruction in accordance
with the system and methodologies herein. As illustrated in FIG. 2,
the system first checks, at step 1 45, to determine if a character
in question has the correct number of elements. If it does, then
the system checks, at step 2 50, whether the pattern of those
elements match a character. If so, then the system proceeds to step
7 55 to store the character value and complete the processing at
step 8 60. If the correct number of elements is not identified at
step 1 45, then category thresholds are set based on the character
width at step 3 65, elements are sorted into the categories at step
4 70, and the elements are reconstructed according to specified
rules at step 5 75. After such processing, the system then checks
whether the new element pattern matches a character at step 2 50.
If so, that character value is stored at step 7 55 and processing
is completed at step 8 60; if not, an Undecoded Character
Identifier is stored at step 6 80 and processing is completed at
step 8 60. Further exemplary aspects of possible reconstruction
methodology operation are detailed hereinbelow.
[0126] It is further envisioned that many different rules may be
applied to a reconstruction character with the different rules
being weighted for later choosing. Alternatively, one kind of
reconstruction may be assigned to be performed on a given label
based upon an assumption that such label is likely to have a single
type of problem, or to be amenable to a particular rule of
reconstruction. For example, if one character can not be decoded
but a check digit is available, the check digit may be utilized to
reconstruct the missing character. As well, moving edges may be
classified at a different level than eliminating or adding
edges.
[0127] With reference to reconstruction of a Code 39, an exemplary
reconstruction methodology includes a first step of determining
which elements in the character are corrupted. To this end,
category thresholds may be calculated and set, based on character
width, to allow the elements to be categorized as valid or invalid.
For example, and with reference to FIG. 3 which illustrates a
sample low density thermal printed Code 39 label 85 with gaps and
voids 90, to allow the wide to narrow ratio to be a value between
1.7 and 4.0, the thresholds for a label element would be set at
CW/18-CW/11 for a narrow element and CW/11*1.7-CW/18*4 for a wide
element, where CW=character width. Elements are then sorted into
the categories by comparing each element in the character with the
thresholds; the elements are then sorted into the different
buckets. For example, in Code 39 the different buckets could be
established as: TN=Too Narrow; N=Narrow; NNE=Not Narrow Enough;
NWE=Not Wide Enough; W=Wide; and TW=Too Wide. The appropriate rule
set may then be applied to the results of the sorting to
reconstruct the elements. For example, TN+TN+NWE=W. If the
reconstructed element does not match a valid character then an
Undecodable Character Identifier marker, as further described
hereinbelow, is stored in the buffer and processing continues.
[0128] For the character outlined in FIG. 3, the element values
with respect to the label section 95 are:
[0129] 594 592 590 1449 1410 625 210 237 1009 576 570
[0130] and the Character Width is 7862. Using the thresholds
defined above for Narrow and Wide elements, the following
thresholds are calculated to be:
Narrow=436-714
Wide=1215-1747
[0131] Sorting the eleven "elements" (i.e., "element" a 100,
"element" b 105, "element" c 110, "element" d 105, "element" e 120,
"element" f 125, "element" g 130, "element" h 135, "element" i 140,
"element" j 145, and "element" k 150, of the label section 95)
using the above thresholds yields:
[0132] N N N W W N TN TN NWE N N
[0133] Applying the rule TN+TN+NWE=W the character is reconstructed
as:
[0134] N N N W W N W N N
[0135] which can then be correctly decoded. Thus, it may be seen
that the above character reconstruction process results in
combining "element" g 130, "element" h 135, and "element" i 140 as
a single bar element that has been reconstructed to ignore the gap
155 which would otherwise have erroneously been identified as
"element" h 135.
[0136] In accordance with further aspects of the system and
methodologies herein, edge matching, element filling, and element
splitting may be utilized in character reconstruction of poor
quality labels. As indicated previously, reconstruction allows the
scanner to read poor quality labels with data from one scan line so
the reading speed is faster. The decoder attempts to decode each
label of a character. If a character cannot be decoded using
standard decoding techniques, e.g., as a result of a poorly
printed, distorted or worn label, then the following exemplary
methodology may be utilized to reconstruct the character. The steps
of the exemplary reconstruction methodology include: identifying
the character elements, finding matches between element edges and
character templates, filling appropriate elements, and splitting
appropriate elements. The steps are described in the following
pages. The flow diagram of FIG. 4 illustrates the exemplary
functional blocks of one implementation of character reconstruction
in accordance with system and methodologies herein.
[0137] With reference to FIG. 4, character elements are identified
in a first step 160. To this end, the decoder uses the first few
elements of a label, or historical information, to determine the
character width for a new character. The character width is used to
identify the element edge of the new character that is closest to
the element width. If the character width of the new character is
different from the original estimate by more than a specified
amount, the data of the new character is adjusted at the character
boundary to correct the error. By way of example, the characters of
the UPC symbology are comprised of a fixed number of modules with
each module width being a known specified fraction of the character
width. When decoding such symbology in accordance with the approach
herein, if a decoded character is found to vary in width from the
previous character by more than 1 module width, the character
boundary may be adjusted by the appropriate amount to restore the
overall character width to the correct number of modules.
[0138] In a second step 165, once the character elements are
identified, the system attempts to find matches between element
edges and character templates. For this purpose as well, the
decoder uses the first few elements of a label, or historical
information, to determine the expected element widths for all
possible element widths of the current character. The expected
element widths are used to expand the normalized templates for all
characters of the symbology. A comparison is made between each
character of the symbology and the current character. The distance
between the element edges of the current character and the expanded
templates are used to determine which symbology characters are the
closest match to the current character.
[0139] In a third step 170, the system determines whether or not
there is only one acceptable match between element edges and
character templates. If so, there is only one symbology character
that is within a satisfactory amount of difference from the current
character. Thus, that match is accepted and the corresponding
character identifier is loaded into the label buffer (as provided
in step nine 175 below). Character reconstruction is then complete
and the system exits the routine at the exit step 205. If there was
not only one acceptable match between element edges and character
templates, then there may be multiple symbology characters that
match the current character and the system proceeds to step four
180.
[0140] In the fourth step 180, the system attempts to fill
appropriate elements. For example, if there are more element edges
than are required by this character, the system determines which
element to change from a bar to a space or a space to a bar. When
one element is switched, two element edges are removed. To this
end, several rules may be utilized to guide the decision about
which element to switch. For example, a first rule may be that the
decoder should give a higher priority to changing a narrow space to
a bar than changing a narrow bar to a space. As well, a second rule
may be that the decoder should give a higher priority to changing
very narrow elements compared to changing wider elements. It is
envisioned that other rules may be readily devised and employed
with a mind toward specific symbologies to be decoded. Once changes
are determined and completed, the system then proceeds to step five
185.
[0141] In the fifth step 185, the system determines whether or not
the character resulting from the fill operation changes made in
step four 180 is acceptable. To this end, the decoder checks for a
match with symbology characters. If the character with filled
elements matches a symbology character, then that match is accepted
and the corresponding character identifier is loaded into the label
buffer (as provided in step nine 175 below). Character
reconstruction is then complete and the system exits the routine at
the exit step 205. If the character with filled elements does not
match a symbology character, the system proceeds to step six
190.
[0142] In the sixth step 190, the system attempts to split
appropriate elements. For example, if there are not enough elements
for this character, one or more of the elements must be split.
Various information and rules may be utilized to guide the decision
about which element(s) to split, including: the type of elements of
a character in the current symbology; the type of elements of the
current character; and/or the elements that are not within a
certain range of a valid element widths. It is envisioned that
other criteria may be readily devised and employed with a mind
toward specific symbologies to be decoded. Once changes are
determined and completed, the system then proceeds to step seven
195.
[0143] In the seventh step 195, the system determines whether or
not the character resulting from the split operation changes made
in step six 190 is acceptable. To this end, the decoder checks for
a match with symbology characters. If the character with split
elements matches a symbology character, then that match is accepted
and the corresponding character identifier is loaded into the label
buffer (as provided in step nine 175 below). Character
reconstruction is then complete and the system exits the routine at
the exit step 205. If the character with split elements does not
match a symbology character, the system proceeds to step eight
200.
[0144] In the eighth step 200, the system has determined that an
acceptable character could not be reconstructed. Accordingly, the
Undecodable Character Identifier is loaded into the label buffer.
Character reconstruction is then complete and the system exits at
exit step 205.
[0145] In the ninth step 175, the instant system has determined,
from either step three 170, step five 185 or step seven 195, that
an acceptable character could be reconstructed. Accordingly, the
appropriate identifier for that character is loaded into the label
buffer. Character reconstruction is then complete and the system
exits at exit step 205.
[0146] Character Correlation and Stitching
[0147] In accordance with a still further aspect of the system and
methodologies herein, character correlation across several scans is
provided. Utilizing such techniques, character information from
multiple scans are merged without requiring overlap as in past
practices. As in the case of reconstructing single scan lines
above, where multiple scan lines are merged using the character
correlation techniques herein, the scanner decodes all of the
characters in the label that are of good quality, while poor
quality characters are skipped to be reconstructed after merger
rather than thrown out. Thus enabling decoding of poorly printed
labels.
[0148] As indicated previously, poorly printed labels may have
spots and voids. It may also be difficult to capture the entire
label in one scan line. Using the character correlation techniques
herein, multiple scans may be used to assemble all characters of a
label with no overlap of label information required and even when
no single scan has enough information to decode all characters of
the label. To this end, the position of the character in the label
may be used to correctly assemble the characters, and repetitive
scans of character information may be used to validate the label.
As above, undecodable characters are skipped over with decoding of
further label data continuing.
[0149] Decoded Characters and their position may be stored in a
correlation store. Further, an Undecoded Character Identifier may
be used for characters that cannot be decoded. Additional scan
lines are decoded in the same way. Decoded characters from the
additional scans may be merged with the data in the correlation
store in accordance with techniques herein. When each character of
the label is seen in the same location a specified number of times,
e.g., at least two (2) times, the complete label is made available
for final verification. Such merging of character data from
multiple scans of a label is referred to herein as character
correlation.
[0150] Character correlation is utilized when a complete label may
otherwise be decoded except that it is missing one or more
characters. In situations where repeated scans of the same label
result in different characters being missed, the characters decoded
may be correlated across multiple scans with some degree of
repetition in the same location to create a complete label. This
could also be thought of as stitching on a single character basis
with no overlap required. Utilizing character equality boundaries
of bars and spaces, the elements of undecodable characters could be
skipped. The correlation is implemented by keeping track of the
number of times a character has been seen. If a different character
begins to be decoded, the number of reads is decremented until it
reaches zero. Then the new character takes over the position.
[0151] If a certain number of characters are different from one
scan to the next, the first scan may be thrown out and that next
scan saved for further processing. Alternatively, both scans may be
saved with that next scan being saved in a separate data store than
the first. It is also envisioned that read requirements may be
adjusted to account for situations involving high risk
reconstruction.
[0152] A decoder may decode both Full Length Labels and Fragments.
In another aspect of the system and methodologies herein, the
combination of character correlation and stitching is implemented.
A left fragment correlation store and a right fragment correlation
store may be established as to each symbology, as appropriate, to
store the characters of the fragments and the number of scans that
each character has been seen. Full Length Labels may be stored in
the left fragment correlation store under such scheme.
[0153] After the first label is stored in the correlation store,
new labels may be merged with the stored label, i.e., Decoded
Characters may be merged into the Correlation Store. To this end,
the number of scans are stored for each character and each
character of the new label is compared to a character of the stored
label in the corresponding location. The following logic is used
after comparing a character of the new label (new character) with a
character from the stored label (stored character):
[0154] IF new character is not an Undecoded Character
Identifier
[0155] IF new character is equivalent to the stored character
[0156] Increment number of scans for the stored character
1 ELSE new character is different than the stored character .sup.
IF number scans for stored character is greater or equal to 1 .sup.
Decrement number of scans for this character by 1 .sup. `ENDIF
.sup. IF number of scans for this character is 0 .sup. Replace the
stored character with the new character .sup. Set number of scans
for this character to 1 .sup. ENDIF ENDIF ENDIF
[0157] A stored label may be replaced with a new label if the new
label is a complete scan and the length of the new label is
different from the stored label. Alternatively, or additionally, a
stored label may be replaced with a new label if the number of
Decoded Characters in the new label that are different than the
Decoded Characters of the stored label represent more than 50% of
the label length. Still further alternatively, a first stored label
need not be discarded and replaced with a new label under the above
circumstances; rather, the new label may be saved in a separate
data store and both the first stored label and the new label may be
utilized in further processing.
[0158] FIG. 5 provides pictorial representations of exemplary sets
of scan lines 210 and 215 that may be processed using correlation
and stitching techniques in accordance with the system and
methodologies herein. As may be seen in the first scan lines 210 of
FIG. 5, the four label scans comprise two left fragments 220 and
two right fragments 225 are identified and the character values and
positions in each are correlated (i.e., "lined up"). With respect
to the first scan lines 210, it may be seen that no Undecodable
Characters are identified. Accordingly, based upon the correlation,
the label scans are stitched and a first resulting label 230 is
decoded. It is noted that the correlation process includes
maintaining correlation scan count information 235 for each scan
line (as well as in relation to a resulting label) which indicates
the number of times a particular character has been identified in a
specific position.
[0159] Similarly, with respect to the second scan lines 215 of FIG.
5, the five scan lines comprising three left fragments 240 and two
right fragments 245 are identified and the character values and
positions in each are correlated (i.e., "lined up"). It may be seen
that one undecodable character 250 is associated with one of the
second scan lines 215. Despite the missing character value
associated with undecodable character 250, the system and
methodologies are capable of correlating the characters and
stitching together a second resulting label 255 to be decoded. As
with the first scan lines 210, the correlation process includes
maintaining correlation scan count information 235 for each scan
line (as well as in relation to the second resulting label 255)
which indicates the number of times a particular character has been
identified in a specific position.
[0160] In further accordance with the system and methodologies
herein, improved stitching of label fragments from poor quality
labels is provided. For example, stitching of Fragments may proceed
even if some characters are not decodable. As well, symbologies
configured for variable length may be stitched. In one aspect, the
system may be set such that the order of arrival of Fragments may
be considered when stitching. In this latter regard, less stringent
stitching requirements may be allowed for Fragments that are
decoded from consecutive scans of a specific scan line pattern as
compared to Fragments decoded from non-consecutive scans.
[0161] The system and methodologies herein provide for scans of a
label to be decoded using correlation techniques as described
above. The decode of a scan may result in a decode of a Full Length
Label or only a Fragment. Where decoded Full Length Labels and
Fragments have characters that were successfully decoded and
characters that could not be decoded, i.e., Decoded Characters and
Undecodable Characters, specific rules, as further described by
example hereinbelow, may be utilized to merge such Full Length
Labels and/or Fragments together. In this regard, one set of rules
may be implemented to merge Full Length Labels and Fragments
together, while another set of rules is implemented to stitch just
Fragments together. Further, specific rules, as provided herein,
are used on the final stitched label before the label is accepted.
The flow chart of FIG. 6 illustrates the functional blocks of
exemplary merge and stitching aspects of the systems and
methodologies herein.
[0162] With reference to FIG. 6, in a first step 260, the system
decodes scans of a label, e.g., a new label. The decode of a scan
may result in a Full Length Label or Fragment. Characters of the
Full Length Label or Fragment may be Decoded Characters or
Undecodable Characters. If the label is a Fragment, it is
identified as a left or right fragment of the label.
[0163] In a second step 265, the system next attempts to merge a
new label with a currently stored label if present. To this end, it
may be determined if the two labels are to be merged in accordance
with specific rules and logic (e.g., as provided herein). When a
merge is acceptable, characters of the labels are merged using the
previously detailed merge logic. Before an actual merge occurs, a
merge check may be done (e.g., also in accordance with the rules
set forth herein) to determine if a certain percentage (e.g., 75%
in a preferred embodiment) of the Decoded Characters in the two
labels match in value and position. If the percent matching
criteria is not met, the merge check fails and the merge does not
progress. Otherwise, the merge check passes and merge proceeds.
[0164] In a third step 270, the system determines whether the merge
changed the stored data. If not, further merge/stitching processing
is not required. If any of the merge actions resulted in a change
to the stored data, the system continues with step four 275. If
not, the routine proceeds to the exit step 280 and completes this
processing.
[0165] In the fourth step 275, the system determines whether or not
there is a new or modified Full Length Label. If so, further
processing to determine if the new or modified Full Length Label
meets requirements is performed (as will be further detailed
hereinbelow in relation to step eight 285). If not, i.e., if it is
Fragments that were modified, the system continues with step five
290.
[0166] In the fifth step 290, the system determines whether both
left and right fragments are present. If not, further
merge/stitching processing is not required as to the present labels
and, thus, the routine proceeds to the exit step 280 and completes
this processing. However, if both left and right fragments are
present, the system then continues with step six 295.
[0167] In the sixth step 295, the system attempts to stitch the
right and left fragments of the correlation store. Attempts to
stitch both fixed length symbologies or variable length symbologies
may be made.
[0168] In the seventh step, the system determines whether the
stitch was successful. If stitching was not successful, then
further merge/stitching processing is not required as to the
present labels and, thus, the routine proceeds to the exit step 280
and completes this processing. If stitching was successfully
performed, the system continues with step eight 285.
[0169] In the eighth step 285, the system checks whether or not the
Full Length Label meets the system correlation requirements that
have been established, e.g., whether each character of the label
has been seen the specified number of times (e.g., as detailed in
the rules set forth herein).
[0170] In the ninth step 305, the system stores the label for
further correlation if it does not meet requirements. The routine
then proceeds to the exit step 280 and completes this processing.
If, however, the requirements are met, the system proceeds with
step ten 310.
[0171] In the tenth step 310, the system does a final format and
verification of the label. Final formatting of the label may
include adding or removing characters in further stages of
decoding. Verification of the label may include verifying a check
digit or other configurable attributes of the label. Upon
completion of this step, the routine then proceeds to the exit step
280 and completes this processing.
[0172] With respect to merging, the following rules are exemplary
of those that may be utilized to merge labels in accordance with
the system and methodologies herein.
[0173] When Full Length Labels are merged with other Full Length
Labels, they must be the same length or the merge is not
accepted.
[0174] Fragments can be merged with Fragments of different lengths
or with a Full Length Label. The Merging Length is the length of
the smallest Fragment.
[0175] If the length of a Fragment is greater than a Full Length
Label, the two shall not be merged.
[0176] If the new label is a Full Length Label and Fragments are
currently in the Correlation Store, an attempt to merge the
Fragments with the Full Length Label is made before storing the
result.
[0177] If the new label is a Fragment and a Full Length Label is
currently stored, an attempt to merge the Fragment with the Full
Length Label is made before storing the Fragment.
[0178] With respect to stitching, the following rules are exemplary
of those that may be utilized when performing character correlation
and stitching in a preferred embodiment:
[0179] When Fragments or Full Length Labels are merged together, at
least 50% of the Decoded Characters must match or the oldest is
discarded (alternatively, both old and new fragments may be
separately saved for further processing). The shortest Fragment may
be discarded in the case of merging two (2) Fragments together.
[0180] Full Length Labels have priority over Fragments.
[0181] Long Fragments have priority over short Fragments.
[0182] Fragments can be merged with a Full Length Label or other
Fragments using character correlation.
[0183] Stitching of label Fragments in a symbology that is Variable
Length shall require more Matching Decoded Characters in the
Overlapping Region than a symbology that is Fixed Length.
[0184] Stitching of Fragments in a symbology that is Fixed Length
or configured for Fixed Length shall require at least two (2)
Matching Decoded Characters in the Overlapping Region.
[0185] Stitching of Fragments in a symbology that is configured for
Variable Length shall require at least four (4) Matching Decoded
Characters in the Overlapping Region.
[0186] A certain percentage of the Decoded Characters in the
Overlapping Region shall be Matching Decoded Characters or the
stitch is not accepted.
[0187] At least 80% of the Decoded Characters in the Overlapping
Region of a stitched label shall match in character value and
position.
[0188] For each Matching Decoded Character in the Overlapping
Region, the sum of the scans from the right fragment and left
fragment must meet a specified minimum value or the stitch is not
accepted.
[0189] For each Matching Decoded Character in the Overlapping
Region, the sum of the scans from the right fragment and left
fragment must be at least four (4).
[0190] In symbologies with more than one, e.g., two (2), Fixed
Lengths or Variable Length, the stitch of two Fragments will not be
allowed if all of the Matching Decoded Characters in the
Overlapping Region are the same character, i.e., have the same
character value. Alternatively, the stitch of two fragments may not
be allowed unless at least a specific number of different character
values, e.g., three (3) are identified in the Overlapping
Region.
[0191] When stitching Fragments of a variable length symbology, the
overlapping length with the greatest number of Matching Decoded
Characters in the Overlapping Region will be accepted.
[0192] Each character of a label has to be seen at least two (2)
times before the label will be made available for final
verification. This applies to all labels, stitched or not.
[0193] The stitching of label Fragments that are decoded in
consecutive scans require fewer Matching Decoded Characters and
fewer scans of the Matching Decoded Characters than the stitching
of Fragments that are not decoded from consecutive scans. For
example, a preferred embodiment requires no further scans when a
left and right fragment are scanned consecutively and merged
successfully; however, if left and right fragments are scanned
non-consecutively, two scans would be required for each character
in the left fragment and two scans would be required for each
character in the right fragment.
[0194] When stitching Fragments, the positions with Non-Matching
Decoded Characters will be merged by storing the character of the
two Fragments with the most scans. If the number of scans are
equivalent, the merge of the characters will result in storing an
Undecodable Character Identifier in that position. The number of
scans for the merged character will be the difference in the number
of scans of the Non-Matching Decoded Characters of the two
Fragments.
[0195] Element Reconstruction, Correlation and Stitching
[0196] Similarly to methodologies implemented with respect to
character level processing, as detailed above, element level
processing may further be utilized in accordance with the system
and methodologies herein.
[0197] In one aspect, element correlation may be utilized when a
complete label may otherwise be decoded except that it is missing
one or more characters. If repeated scans of the same label cause
the same characters to be missed, elements in the same area in the
raw label data could be correlated across multiple scans (e.g.,
with some degree of repetition as in character correlation) in an
attempt to create a decodable character. This could also be thought
of as stitching on a single element basis with no overlap required.
Alternatively, stitching may be implemented on an element level
with pieces of a label being stitched together on an element basis
with a certain amount of overlap being required before pieces are
stitched together.
[0198] In another aspect of element correlation, elements across
several scans may be correlated by correlating the entire scan at
once. To line up two scans with each other, a set of random time
values within the scan may be compared. The offset providing the
best comparison result may then be utilized to correlate the two
scans. To correlate the scans, the elements are normalized. With
respect to binary symbologies, a preferred embodiment normalizes
the scans into about 6 widths, e.g., too narrow, narrow, not narrow
enough, not wide enough, wide, too wide. Similarly, with respect to
multi-width symbologies the scans are normalized into about 24
widths. As with character correlation, specific rules may be
devised and implemented for choosing which elements are correct
between two scans.
[0199] Element correlation will merge normalized element width
information from several scan lines to build a complete scan of the
label. The element widths identified from the histogram will be
used to normalize the element width data. Should element
correlation fail to yield a decodable character, element
reconstruction may be utilized. This latter technique makes use of
multiple scans of data and a knowledge of the character set being
decoded in an attempt to reconstruct the most likely character that
is encoded in the undecodable data. Using the Element Width
Histogram data to assess element equality, voids present in the
middle of a bar and spots present in the middle of a space may be
corrected. To this end, the average width of each width for the
spaces and bars is determined using the histogram data. If a
particular element in the label does not fit an average size, the
system and methodologies herein provide for an attempt to combine
that element with either the previous two elements or with the
following two elements in a systematic manner. If either of the
resulting combinations is an average size, the combination is saved
as the correct element.
[0200] Quality Measure Techniques
[0201] Element Level Quality Measure Techniques
[0202] Typical standard algorithms for decoding bar codes rely on
the elements as they are captured to be of relatively accurate
width and position. Depending upon the symbology being decoded, the
correct number of detected elements to make up a character are
first normalized, and then the resulting pattern is compared to a
table of valid characters to determine the value of this encoded
character. However, if the elements are distorted such that they
are no longer detectable, or such that the element widths and
positions as detected are not accurate, the typical standard
decoding algorithm may no longer be capable of decoding the
character or may decode it incorrectly.
[0203] In accordance with the preferred system and methods herein,
measures of quality may be calculated and used in order to validate
each detected element edge and to guide in the decoding of bar code
characters. In cases where the elements have been distorted,
disfigured or obliterated, and so might not be decodable by
standard algorithms, such operation may be utilized to enable the
elements to be reconstructed back to their intended widths and
positions such that they could be correctly decoded. By using
measures of the validity of the detected element edges, it may be
possible to judge the validity of decoded characters, and to
reconstruct distorted elements to their originally intended widths
and positions, so that the character may be correctly decoded. In
this manner, the ability of the bar code scanner to decode label
data that may not be decodable using standard decoding algorithms
may be improved.
[0204] One method of determining the quality of elements that may
be implemented is to compare the elements as detected with target
element widths that have been calculated as being appropriate for
this particular label if it were of a particular enabled symbology.
In this regard, it is envisioned that the target widths used for
comparison may be generated by the histogram. Optionally, the
decoder could generate these values by examining a number of
elements in the data that is being decoded. In either case, the
number of target widths would be equivalent to the number of valid
element widths in the symbology being attempted. By way of example,
with respect to a Code 39 symbology that has two valid widths,
there would be two target widths. Similarly, since a typical UPC
symbology has four valid element widths, there would be four target
widths used for comparison.
[0205] A variety of possible means may be envisioned by one skilled
in the art for determining allowable deviation of element widths
for purposes of the above comparison. One possible means in
accordance with a preferred embodiment herein is to calculate a
tolerance value from the target widths. By way of example in
relation to a Code 39 symbology, one half of the difference between
the wide target width and the narrow target width could be utilized
as a valid threshold to determine acceptable deviation.
[0206] Another method of determining element quality that may be
implemented is to use a confidence rating for the edges of the
elements and to compare this value with some calculation of such
value for the rest of the character or label being decoded. In this
latter regard, a value indicating the strength of the edges as
previously described may, for example, be utilized. As above, it is
envisioned that the target edge strength that is used for such
comparison may be generated by the histogram. Again, optionally,
the decoder could generate this value by examining the edge
strength of a number of elements in the data that is being decoded.
As with the element width comparison above, a variety of possible
means may be envisioned by one skilled in the art for determining
allowable deviation of element edge strengths for purposes of the
above comparison.
[0207] In cases where single elements have been split into multiple
components through the inclusion of spots, voids or other defects,
a combination of the above two methods may be envisioned for use in
determining the correct bounds of the element, allowing the invalid
detected elements to be ignored. In cases where elements have been
rendered undetectable through obliteration by spots, voids or other
defects, a combination of these methods might be used to insert an
element of the desired width at the appropriate location into a
character, based upon the locations and calculated validity of the
other, detected elements.
[0208] To further assist in the above process, and/or as a check,
resulting patterns may be compared with a table of possible valid
characters as element widths are being reconstructed. This would
provide an additional validation that the elements were being
reconstructed back into their most likely original form. As well,
such comparison may be utilized to identify characters that are, in
fact, not decodable earlier in the process so that no further
effort would be spent attempting to decode such character.
[0209] It is noted that some instances of this reconstruction
process may result in two or more possible interpretations of the
same element set, creating an ambiguous decode. In such cases, a
preferred embodiment may resolve such ambiguity through a
comparison of the sums of the quality measures of the elements as
they have been defined to compose the different potential
characters. In this regard, the character having the highest
determined quality by a pre-established margin may, for example, be
selected as the correctly decoded character.
[0210] In accordance with a preferred embodiment, one possible
means of generating a measure of quality of an individual element
is to calculate the product of the deviation of the element width
from target and the deviation of the element edge strength from
target. The sum of these products for all of the elements in a
character would generate a measure of quality for the character. It
is noted, however, that other means of generating a measure of
quality of individual elements based upon the above comparisons may
be devised and implemented by one skilled in the art without
departing from the spirit and scope of the inventive concepts set
forth herein and in the appended claims.
[0211] With reference to FIG. 7, element level processing with
quality measure calculation begins with a leading edge of a
character in the first step 315. In a second step 320 it is assumed
that the current edge and the next edge in the element edge buffers
define an element. In a third step 325, the element width defined
by the assumed current edge and next edge in the element edge
buffers is compared with a first target width. In a fourth step
330, a determination is made regarding whether the deviation in the
compared values from the third step 325 is within the
pre-established tolerance. If so, processing continues with the
eleventh step 335 (as further detailed below).
[0212] If a determination is made in the fourth step 330 that the
deviation is not within tolerance, a further determination is made
in the fifth step 340 regarding whether such element width is
greater than the target element width. If not, processing proceeds
with the sixth step 345 wherein a new element width is calculated
by adding the appropriate value associated with the next two edges
in the element edge buffers to the old element width. Processing
then continues from the third step 325, as previously detailed,
with the new element width value. If it is determined in the fifth
step 340 that the element width is greater than the target width,
processing continues with the seventh step 350 wherein the element
width is compared with a second target width. In the eighth step
355, a determination is made regarding whether the deviation in the
compared values from the seventh step 350 is within the
pre-established tolerance. If so, processing continues with the
eleventh step 335 (as further detailed below).
[0213] If a determination is made in the eighth step 355 that the
deviation is not within the tolerance, a further determination is
made in the ninth step 360 regarding whether such element width is
greater than the target element width. If not, processing proceeds
with the sixth step 345 wherein a new element width is calculated
by adding the appropriate value associated with the next two edges
in the element edge buffers to the old element width. Processing
then continues from the third step 325, as previously detailed,
with the new element width value. If it is determined in the ninth
step 360 that the element width is greater than the target width an
error is recorded in the tenth step 365 and processing ends.
[0214] If, as a result of the fourth step 330 or the eighth step
355, it is determined that the corresponding deviation is within
the corresponding pre-established tolerance, processing proceeds
with the eleventh step 335 wherein the corresponding edge strength
value is compared with the target edge strength. Processing then
continues with the twelfth step 370 wherein the element width
deviation and the edge strength deviation values are multiplied to
generate a quality measure for this element. Further processing
continues as detailed below in conjunction with FIG. 8.
[0215] With reference to FIG. 8, a determination is made in a first
step 375 regarding whether or not the quality measure generated (in
the twelfth step 370 with reference to FIG. 7) is acceptable. If
not, an error is recorded in a second step 380 and processing ends.
If the quality measure is determined to be acceptable in the first
step 375, the quality measure for the current element is added to
the quality sum for the current character in the third step 385.
Processing then continues in the fourth step 390 wherein a
determination is made regarding whether or not the quality sum
resulting from the third step 385 is acceptable. If not, an error
is recorded in a fifth step 395 and processing ends.
[0216] If the quality sum is determined to be acceptable in the
fourth step 390, processing continues in the sixth step 400 wherein
the element pattern assembled to that point is compared with a
table of valid patterns. In the seventh step 405, a determination
is made regarding whether or not the currently assembled element
pattern is a valid pattern. If not, an error is recorded in the
eighth step 410 and processing ends.
[0217] If the currently assembled element pattern is determined to
be a valid pattern in the seventh step 405, a further determination
is made in the ninth step 415 regarding whether or not the
currently assembled element pattern comprises a complete character.
If not, the trailing edge value of the current element becomes the
current edge value in the tenth step 420 for further processing
from the second step 320 of FIG. 7.
[0218] If it is determined in the ninth step 415 that the currently
assembled element pattern comprises a complete character,
processing continues with the eleventh step 425 wherein the decoded
character is stored and the quality sum is saved for possible use
in correlation and stitching routines. Processing is then completed
in the twelfth step 430.
[0219] Character Level Quality Measure Techniques
[0220] As indicated previously, when attempting to decode poor
quality bar code labels, character correlation and stitching
algorithms may be used in an effort to assemble a complete label
from individual characters decoded over multiple scans. In one
manner of implementation, as detailed above, character correlation
and stitching algorithms may operate by requiring that any given
character in a label be decoded as the same character a preset
number of times before being accepted as a valid character for that
position. Because of the nature of poor quality labels, however,
all of the individual characters may still not be correctly
decoded. Such remaining invalid characters can potentially corrupt
the accumulated data such that the correct label is never
completely assembled.
[0221] In accordance with a preferred embodiment herein, a
confidence measure for each decoded character may further be used
to assist in correlation and stitching. The measure of confidence
of each character as it is decoded may be used to determine the
number of times that a particular character must be decoded before
being accepted. In a preferred implementation, a decoded character
that is determined to be of poor quality may be required to be
decoded as that same character a greater number of times than if it
were of good quality.
[0222] In a preferred approach, an inverse relationship between the
quality of a character and the number of times that it would have
to be decoded before being accepted may be established and
utilized. The following example illustrates a manner in which this
approach may be implemented. Assuming a first scan of a label
yields a character decoded as a first value in a particular
position and with a quality rating of 100. On a second scan of the
same label, the character in the same position is decoded as a
second value with a quality rating of 300. In accordance with this
example, lower quality rating numbers indicate higher confidence.
Thus, the quality rating of 300 represents only one-third the
confidence of character decoded with a quality rating of 100. In
such instance, the character having the quality rating of 300 may,
for example, be required to be decoded three consecutive times
before it would be allowed to replace the character having a
quality rating of 100 that was decoded once in the correlation
function.
[0223] By using a measure of the quality of each decoded character,
the correlation and stitching algorithms may be able to prevent the
invalid characters from being accepted as valid, and therefore
enable the correct label to eventually be completely assembled. In
this manner, the effectiveness of character correlation and
stitching algorithms may be improved. Such algorithms may then be
used in a bar code scanner to decode label data not decodable using
standard algorithms.
[0224] Threshold Adjusting Techniques
[0225] In another aspect of the system and methodologies herein, a
limitation on acceptable element widths may be implemented when
using character correlation to scan poor quality labels. As
indicated previously, thresholds are used to determine which
normalized element width represents the actual element width when
normalizing the elements of a label. The thresholds allow a range
of element widths to be accepted for each normalized width. When
poor quality labels are scanned and require the use of character
correlation and stitching, however, the risk of incorrect decoding
is increased. To offset this increased risk, the system and
methodologies herein provide for the threshold ranges to be changed
when character correlation and stitching are used. That is, when
the scanner starts using character correlation and stitching, the
acceptable range of element widths for each normalized element may
be reduced from the initial range. By reducing the acceptable range
of element widths, fewer characters may be decoded incorrectly;
thus, giving decoded data that is more accurate and consistent.
With more accurate decoded data, character correlation and
stitching converges on the correct label data more quickly. In this
manner, the performance of character correlation and stitching when
poor quality labels are scanned may be improved.
[0226] One method that may be envisioned to adjust the threshold
values in relation to character correlation and stitching would be
to maintain a record, for each symbology decoded, of the degree of
congruence of elements in labels that did not require correlation
or stitching. Such record would then provide example values in
relation to good quality labels. When correlation or stitching was
subsequently required in relation to further labels, the threshold
levels could be adjusted such that only elements with equivalent or
better degrees of congruence to those in the good quality examples
would be accepted.
[0227] In another aspect, variable thresholding may be implemented.
This technique would mainly apply to binary codes and would be used
to allow the wide to narrow ratio to be adjusted to be more or less
stringent vs. aggressive. This technique may advantageously further
result in an increase of the depth of field in which binary codes
may be read.
[0228] Further, the instant system and methodologies provide for
staged decoding through levels of decoding intelligence. In this
regard, the scanner may be programmed such that its level of
decoding intelligence is increased as it reads more scans. As the
scanner goes to more intelligent decoding modes, it may use a more
complicated decoding threshold scheme. For example, the system may
start with a simple scheme (to decode good quality labels that are
susceptible to normal decoding fast) and then advance to a more
complicated threshold scheme for aggressive decoding to reduce
misreads and allow for better definition of the problems in the
label.
[0229] In a scanner that has programmable thresholds for decoding,
setting the thresholds at the most stringent levels will generally
result in the fewest misreads. However, this may prevent reading of
labels of poorer quality. As a result, the user may try to program
the scanner with inappropriate threshold levels in an effort to
scan all of their labels. In a still further aspect, the system and
methodologies herein provide for automatic programming of decoding
thresholds to enable the user to easily adjust decoding
aggressiveness to match label quality. This technique allows the
user to set thresholds by scanning labels of typical quality. For
example, when the scanner has been placed into a special
programming mode, the user may then scan labels that exhibit
characteristics typical of the labels that they will be scanning.
Decoding routines could then be adjusted to utilize the appropriate
thresholds to allow the labels to be decoded. Thus, thresholds
could be adjusted to the optimum levels for decoding the user's
labels. These thresholds would be saved and used for all future
decoding of labels of this same symbology until further programming
is performed.
[0230] Signal Processing Modification Based on Decoder Feedback
[0231] When scanning label data, the accuracy of the bar/space
edges detected and passed on to the decoding software is dependent
upon a number of factors. Among the factors are parameters in the
signal processing system such as gain and threshold. Typically, the
signal processing system in a bar code scanner is designed around
parameters that are fixed or, if variable, may be modified based
upon feedback within the signal processing system itself. Thus, for
example, gain and threshold parameters, if not fixed, may be
adaptively adjusted based upon feedback from prior processing of
the input signal by the signal processing system. It has not
heretofore been devised to incorporate feedback from outside of the
signal processing system in order to adaptively adjust
signal-processing parameters for further processing.
[0232] In a further aspect of the preferred system and methods
herein, aspects of the signal processing system may further be
enabled to be modified based upon feedback from the decoding
software. Signal processing parameters such as gain and threshold
may be adjusted based upon information obtained in the process of
decoding label information. Should decoding of information from the
signal processor (for example, utilizing further techniques
identified herein) indicate that an adjustment to the gain,
threshold, or other parameters in the signal processing system
could provide for more efficient decoding of subsequent label
information, then appropriate adjustment to such parameters may be
made accordingly. By allowing parameters to vary based upon
feedback from the decoders, it may be possible to more accurately
tune the signal processing system to match the specific
circumstances of the label being scanned, thus leading to more
accurate data being collected, and to the generation of a more
accurate representation of the label data being scanned. In turn,
the probability of correctly decoding the label in a short time is
increased.
[0233] Scan Line/Mechanism Compensation
[0234] When capturing bar code data using a dithering scan
mechanism, the bar/space element times will increase at the ends of
the scan line because the scan mechanism must slow down to reverse
direction. As the dithering mechanism slows down to reverse
direction, the corresponding distortion of the collected scan data
can cause it to be unusable for decoding. This effectively shortens
the usable scan line. Current practices either discard the data
from the ends of the scan line as being too distorted, or attempt
to correct it on a character by character basis as it is decoded.
However, the distortion of the data at the ends of the scan line
can potentially be more severe than can typically be corrected on a
character by character basis.
[0235] To counter the effects of the scan mechanism operation at
the end of scan lines, and to further ensure that accurate
information is presented for decoding, the system and methodologies
herein provide for the adjustment of certain collected scan data by
a predefined offset to compensate for known variations in the scan
mechanism speed. Because the physical properties of the scanning
mechanism are well understood by those skilled in the art, the
variations in speed which it will exhibit over the course of the
mechanism's scanning arc can be accurately predicted. Accordingly,
a table of compensation values can be generated that can be applied
to the collected data. Because the location in the scanning arc
where each data value was collected is known, the appropriate value
from the compensation table can be applied to each item of
data.
[0236] For example, the speed of the scanning spot can be
characterized over the course of the scan line. With knowledge of
the rate of change of the scan mechanism speed at the ends of the
scan line, and position information in relation to such change in
speed over the scan line, a measure of the associated time
distortion with respect to elements encoded in the scan line
information may be established. In turn, the compensation curve may
be determined to identify the offset that may be applied to the
collected data to adjust it for the variation in speed. By
compensating for such distortion, the entire scan line of data may
be used; thus more efficiently obtaining complete character
information that might otherwise have required additional
scans--and time--to obtain and decode. In this manner, the effect
that the variations in scanning speed may have had upon the value
of the data may be effectively nullified.
[0237] Rounded Surface Interpolation. When scanning a label
attached to a rounded surface (e.g., on a can or bottle), a certain
amount of distortion is encountered due to the varying distances of
the scan line to the label as it moves across the label. In this
aspect, the system and methodologies herein provide interpolation
techniques that may be implemented as a means of compensation for
the distortion of elements. Similarly to scan line compensation
techniques discussed above, potential offset amounts could be
determined and implemented to adjust for character/element width
distortion. It may be envisioned that such offsets could be used
either directly on identified character/element widths, or they may
be implemented as part of a secondary, more aggressive technique to
fit elements/characters into a known pattern during
reconstruction.
[0238] Additional Decoding Techniques
[0239] To further ensure that scan information is properly decoded,
a scanner in accordance with the system and methodologies herein
may employ one or more of the following techniques.
[0240] Decode Initiation. In this aspect, the scanner would keep
track of the number of elements in potential labels and the total
time (i.e., label element total count) associated with potential
labels. In this regard, the first stage of the
decoding/reconstruction sequence would not be initiated until the
number of elements and the time count stabilized.
[0241] Margins. Existing scanners typically require that some
amount of margin space be detected in conjunction with a label
scan. In accordance with this aspect of the system and
methodologies herein, margin checking requirements could be
modified as the decoding intelligence level changes. For example,
if the histogram shows a label with well defined element widths, a
margin requirement may be skipped with respect to that label. This
feature could further be implemented in conjunction with the
aggressiveness level changes, as further detailed hereinbelow, to
change the margin requirements automatically as different levels of
decoding are implemented.
[0242] Quiet Zones. As above, existing scanners will typically find
leading quiet zones during data capture. In this aspect of the
system and methodologies, the scanner would also find possible
trailing quiet zones in order to aid in a determination of where
potential label data exists in the capture buffer.
[0243] Typically, quiet zones are defined as being an element which
is some integer multiple, commonly six to ten, times the width of a
narrow element in the label. These quiet zones are expected to be
found on either end of the label and serve to delineate the label
from the label's surroundings. However in some cases, particularly
when the label has been printed on a textured surface, spurious
transitions may occur at the ends of the label in the area of the
quiet zones. Such spurious transitions may appear as elements to
the scanner where, in fact, there are none. Normally, the presence
of elements in what should be the quiet zone would invalidate that
area as a quiet zone. If a detection of a quiet zone were required
for decoding a particular symbology, or by a particular decoding
algorithm, the erroneous invalidation of the quiet zone could
prevent the successful completion of the decode.
[0244] In accordance with a further aspect of the preferred systems
and methods herein, edge strength information may be used to detect
the existence of a valid quiet zone even though it may appear that
it contains elements. In this regard, if a quiet zone is being
tested for, and it appears to contain elements, the edge strength
of those elements could be compared with the average edge strength
of the elements in the label. If the edge strength, i.e. confidence
level, of the elements in the potential quiet zone were below some
threshold (which may, for example, be 25 percent less than the
confidence level of the elements in the label), then other factors,
such as the presence of an adjacent STOP or START pattern, could be
considered to determine if this was a valid quiet zone. This could
allow the successful completion of a decode even though phantom
elements may appear in the data in the location of the quiet
zone.
[0245] Bi-directional Decoding. Existing scanners typically decode
in only one direction. Thus, when scanning a poorly printed label,
the scanner is only able to "look at" the label from one side on
each scan. Further, when scanning a label fragment, the scanner is
only be able to decode the fragment every other scan line. In this
aspect of the system and methodologies herein, decoders and margin
searching features are enhanced so that the decoders can decode the
scan line in both directions. In this manner, additional scan
information may be decoded, e.g., through reconstruction techniques
that might otherwise have been lost as a result of the inopportune
location of label defects.
[0246] Decoding Credits. In this aspect of the system and
methodologies herein, it is envisioned that each decoding session
of a label would be allowed a certain number of decoding credits.
Such decoding credits would be assignable to the various decoding
techniques that may be implemented in the established configuration
for a particular scanner. Decoding methods of high risk would use
more credits than methods of low risk. Since the use of more
aggressive, i.e., higher risk, decoding techniques may result in an
increase of potential misreads, use of a decoding credit scheme
could serve as a check on decoding security.
[0247] By way of example, a decoding session could start out with
each symbology having a budget of 100 credits. A particular number
of credits would be associated with each of the variety of decoding
function/technique available for implementation, respectively. For
example, ten (10) credits may be associated with reconstruction of
a character, twenty (20) credits with the lack of a trailing quiet
zone, five (5) credits per character may be associated with
correlation, and so on. As each decoding function is invoked, the
appropriate number of credits associated with that function is
subtracted from the total available. If the total drops to zero or
below as a result of such subtraction, decoding for that symbology
is stopped.
[0248] This scheme would allow the decoder to attempt a certain
number of high risk decoding techniques while maintaining a desired
overall security level. Thus, by way of one example, even where a
high level of decoding security is desired, decoding credits could
be implemented such that where all of the data characters of a
label decode easily, the scanner could allow the guard patterns to
be of lower quality requiring more aggressive decoding
techniques.
[0249] Use Of Analog Information. The systems and methodologies in
accordance with the preferred embodiment herein may further make
use of analog data, such as the amplitude of RTV/STV signals from
the scan head. Such amplitude information may be stored as the bar
and space data is stored. This amplitude information would then
give the decoders information about the strength of space-to-bar
and bar-to-space transitions that may be used to distinguish
phantom transitions from real transitions. In addition, the
strength of the signal could be used as an aid in a determination
of how to adjust for inter-symbol-interference when the bar and
spaces are very narrow or the label is at a far distance. Further
aspects of how the system and methodologies herein may
advantageously utilize analog information are detailed immediately
hereinbelow.
[0250] Decoding Aggressiveness Configurations Staged Decoding
[0251] In accordance with the system and methodologies herein, two
stage use of analog and digital label data (i.e., a
digital-to-analog switch) may further be implemented as a means of
systematically varying the aggressiveness of decoding.
[0252] Existing systems have typically approached the decoding of
labels in one of two ways:
[0253] One approach has been to process only the digital label
information so that good quality labels were decoded quickly. With
respect to digital decoding, the hardware of a laser based scanner
may be constructed to generate one or more digital signals from the
reflected laser signal. One possible implementation of a digital
signal indicates a bar of the label by maintaining a specified
voltage level for the time that the laser is positioned on the bar
and it indicates a space of the label by maintaining a different
specified voltage level for the time that the laser is positioned
on the space. Another possible implementation of the digital signal
indicates a space-to-bar transition of the label by generating a
digital pulse when the laser moves from a space to a bar. In this
second implementation, a second digital signal indicates a
bar-to-space transition of the label by generating a different
digital pulse when the laser moves from a bar to a space. In both
types of implementations, the digital signal(s) are used to
determine the width of bars and spaces using time measurements. The
time measurements of bars and spaces are then used to decode the
bar code. The digital signal provides a simplified version of the
reflected laser signal. The simplified signal is quick to store and
quick to decode by the scanner's microprocessor. Since the signal
is quickly processed, the decoding is very fast. However, if the
label is of poor quality, the digital signal alone may be
insufficient to allow the label to be decoded.
[0254] Another approach has been to spend the processing time to
record and process both analog and digital label information so
that labels of all levels of quality could be decoded. With respect
to analog decoding, the hardware of a laser based scanner may also
be constructed to generate one or more analog signals from the
reflected laser signal. One possible implementation of an analog
signal produces the signal strength of the reflected laser signal.
This signal can be digitally sampled and used by the microprocessor
based decoder. A second possible implementation of an analog signal
produces the first derivative of the signal strength of the
reflected laser signal. This signal can be digitally sampled and
used by the microprocessor based decoder. Analog signals from the
reflected laser signal provide more information than a digital
signal. In addition to the information that a digital signal can
provide, the analog signal can indicate the amount of contrast
between the bars and spaces and the sharpness of the edge between
bars and spaces.
[0255] The digital only approach limits the scanner in its ability
to read poor quality labels. The additional information provided by
analog decoding may be used to help read high density labels, to
correct for problems due to low contrast, or to correct for
problems due to spots and voids. However, while analog information
may be useful when trying to read low quality labels, sampling,
storing, and processing the analog information is time consuming;
thus, decoding labels with exclusive use of analog information can
lead to long decoding times for labels even if they are good
quality. Thus, the analog and digital approach results in the
decoding time for good quality bar codes to be long.
[0256] The instant system and methodologies improve on these
limitations so that good quality labels are decoded quickly while
poor quality labels may still be decoded. In the preferred
embodiment, the system first attempts, e.g., with respect to a
first set of scan lines, to store and use only digital label
information. If a valid label has not been found during this first
set of scan lines, the system then starts storing and processing
analog information to help find the label in the scan line data.
Thus, the preferred embodiment is capable of using both the analog
and digital representation of the bars and spaces of a label that
may be produced by the electronics of the scanner, but does so in a
systematic, staged manner so as to improve decoding time. In the
first stage of decoding, the decoder will use the digital
information to attempt the decoding of a label. In the second stage
of decoding, only if necessary, the decoder will use the digital
and analog information to attempt the decoding of a bar code.
[0257] Levels of Reconstructive Logic Decoding
[0258] In addition to the staged digital/analog decoding as
detailed above, the instant system and methodologies provide
further techniques for systematically adjusting the aggressiveness
of decoding. There are many techniques to aggressively decode
poorly printed labels. Each technique has a certain amount of
misread risk. In general, the techniques that allow the scanner to
read more poorly printed labels have a higher risk of misread. The
levels of aggressiveness could be established so that the
techniques that allow the most poorly printed labels to be read
have the highest aggressiveness level. Some possible techniques
that could be assigned aggressiveness levels are:
[0259] Character based stitching--Combining several pieces of a
label to make a resulting complete label. The pieces can be
combined when a certain number of characters are common between the
pieces.
[0260] Element based stitching--Combining several pieces of a label
to make a resulting complete label. The pieces can be combined when
a certain number of bars and spaces are common between the
pieces.
[0261] Element addition--Bars and spaces that are much smaller than
most bars and spaces of the label can be combined with other bars
and spaces.
[0262] Character correlation--Using multiple full scans of a label
to find all characters of a label. Some characters may not be
decoded in one scan while other characters may not be decoded in a
second scan.
[0263] Accordingly, the reconstruction techniques set forth herein,
while more aggressively attempting to decode label information, may
also increase the element of risk for misreads. In a preferred
embodiment herein various levels of decoding may be accommodated
and systematically implemented as further detailed hereinbelow.
Each increased level of decoding generally corresponds to an
increased level of aggressiveness and decreased level of
security.
[0264] Exemplary of the levels of logic decoding that may be
accommodated in accordance with the system and methodologies herein
are:
[0265] Level 1: This level results in the quickest and most secure
decoding on good quality data. In this level, a full scan of the
label is required and all of the characters must be decodable by
standard decoding techniques, i.e., no correlation, stitching or
reconstruction is performed.
[0266] Level 2: This level may be utilized when different scans of
the label yield different characters as being decodable, but no
single scan yields all of the characters. Security is still good as
each character must be seen multiple times in the same location to
be accepted. Unless otherwise guarded against (such as through
limitations on attempt time allowed), one downside of the stitching
techniques that may be implemented at this level is that the
decoder may spend extra time working on the wrong symbology.
Traditional methods of stitching may be implemented at this level
for use, e.g., with respect to situations where scanning is done
from a distance wherein it is more difficult to line up the scan
line with the label. Accordingly, multiple pieces of labels are
assembled together with overlapping of characters. Thus, where a
user merely swept the scan line through the label instead of lining
the scan line across the entire label, complete label information
may nonetheless be reconstructed. Fixed Length Label stitching may
be utilized, i.e., partial scans which begin or end with a START or
STOP pattern may be accepted and are assembled into a complete
label. In such manner, label pieces from multiple scans of poorly
printed labels may also be used to compensate for voids in the
label data. Character correlation may also be utilized, i.e., full
scans of data which are missing characters may be accepted and are
correlated across multiple scans to produce a complete label.
[0267] Level 3: This level may be utilized when Undecodable
Characters are identified in one or more scans of a label.
Character reconstruction is enabled at this level, as well as
Variable Length stitching. While more aggressive, this level is
also less secure because the reconstruction is done by passing the
corrupted data through a set of rules to determine the correct
character; thus, there is always the chance that the decoder will
make the wrong decision. Stitching of Variable Length labels can
also lead to misreads when there are large repeating patterns
within the label. Enabling this level also consumes more time,
which could delay the correct decoder for this symbology from being
invoked. Character reconstruction may be utilized in this level,
i.e., when a character is distorted such that no scan yields a
decodable set of elements for that character. This can occur when
an element has been corrupted over the entire height of the label.
This function will attempt to reconstruct the character from the
corrupted elements using knowledge of the character set for the
symbology. Variable Length label stitching may also be utilized at
this level, i.e., partial scans of a Variable Length symbology
which begin or end with a START or STOP pattern may be accepted and
are assembled into a complete label.
[0268] Level 4: This level may also be utilized when one or more
characters cannot be decoded due to the corruption of elements.
There is a greater potential for misreads using the techniques at
this level because of the insecurity of the initial data. Element
correlation may be utilized at this level, i.e., when the label is
so poorly printed that large numbers of the elements are missing on
any given scan. This function will attempt to correlate the
elements from several scans together to create one scan that can
then be decoded.
[0269] The instant system and methodologies envision that the
levels of reconstruction aggressiveness may be implemented such
that the user could configure the degree of aggressiveness desired.
For example, the user could configure the minimum and maximum
aggressiveness on a per symbology basis. Allowing the minimum
aggressiveness to start at a higher level (i.e., higher than level
1) could give the scanner a head start on aggressive scanning when
the quality of the labels to be scanned is known to be poor.
Allowing the maximum aggressiveness level to be set allows the user
to limit the risk of misreads. It is further envisioned that a
variety of techniques may be utilized to provide for variable
aggressiveness configuration. For example, separate configurable
decoding intelligence levels could be implemented at the label
level and the character level. A further option would be to provide
a bitmap of reconstruction options that could then be investigated
and appropriately set for each level utilizing pre-established
criteria. Still further, a specific set of reconstruction options
could be developed to address specific problems (e.g., problems
that have previously been encountered with respect to a particular
symbology, or problems that are known to be likely to occur).
[0270] In another aspect of the system and methodologies herein, a
technique of advancing decoding aggressiveness through time may be
utilized. In a manner similar to that discussed above with respect
to staged digital/analog decoding, the instant system and
methodologies may use a multi-level approach for decoding
aggressiveness that advances through the levels as the scanner
processes scan lines. Existing scanners typically use only one
level of decoding aggressiveness during the entire time that a
label is decoded. The advantage of the instant system and
methodologies is that well printed labels may be decoded quickly,
and with low risk, while poorly printed labels may still be decoded
as well. This allows for fast decoding times for good quality
labels with decoding times increasing as the quality of the label
decreases. This is important for scanners that cannot keep up with
the label data input when using the most aggressive decoding
techniques. It also allows the scanner to use the decoding
techniques with lower risk of misread first and use the higher risk
techniques only when necessary.
[0271] In accordance with the instant system and methodologies, the
scanner is set up to have several levels of decoding
aggressiveness, such as have been previously detailed hereinabove.
The scanner starts with the initial level and advances through each
level at certain time increments. In one envisioned application,
the time could be measured by counting the number of scans of data
collected. For example, after six scans of data have been collected
without a successful decode, the level of aggressiveness could be
incremented. Each level of decoding allows the scanner to decode
labels of lower quality.
[0272] The above represents one possible implementation of
aggressiveness level configuration. However, it is envisioned that
progression through levels and decoding techniques at each level
could be implemented differently.
[0273] In another aspect of a preferred embodiment, each symbology
may have a level of aggressiveness option which can be set by the
user to dictate how hard the scanner should try to make a label of
that symbology out of any data that is scanned. As each level is
enabled, the lower numbered levels may also be enabled, i.e.
enabling Level 3 implies that Level 2 will also be enabled. In one
implementation, the scanner would always start each scanning
session decoding at level 1 and then would increase the level, as
allowed, as each level of decoding fails to successfully decode the
data. Such structure is intended to allow for fast decode times on
good data, with decode times increasing as the quality of the data
decreases. In effect, if the scanner is enabled to do so, as the
quality of the data deteriorates, the scanner will work harder to
decode it. FIGS. 7 through 10 combine to illustrate the functional
blocks of an exemplary increased aggressiveness level decoding
through time process which may be implemented in accordance with
the system and methodologies herein.
[0274] With reference first to FIG. 9, scanning begins at a first
step 435 whereupon decoding logic is initialized to level 1 at a
second step 440. Element times are captured in a third step 445,
delta time values are calculated in a fourth step 450, a quiet zone
search is performed in a fifth step 455 and symbology
identification is attempted, as further described herein, in a
sixth step 460. In a seventh step 465, the system then determines
whether the decoding logic level is greater than 1. If not, then
the system proceeds to the twelfth step 470 as further detailed
hereinbelow. If the decoding logic level is determined to be
greater than 1, the system proceeds to the eighth step 475 to
determine whether or not there is a leading quiet zone that has
been identified. If not, the system proceeds to the twelfth step
470 as further detailed hereinbelow. If a leading quiet zone has
been identified in the eighth step 475, the system proceeds to the
ninth step 480 to determine whether or not there is a trailing
quiet zone that has been identified. If not, the system proceeds to
the tenth step 485 and adds the identified element times to the
histogram information and proceeds to the twelfth step 470 as
further detailed hereinbelow. If a trailing quiet zone has been
identified in the ninth step 480, the system proceeds to the
eleventh step 490 to calculates the histogram information prior to
proceeding to the twelfth step 470. In the twelfth step 470, the
system determines whether the end of the scan line has been
reached. If not, the system returns to the third step 445 for
further capturing of elements and subsequent processing as set
forth above. Upon determining that the end of the scan line has
been reached in the twelfth step 470, the system then proceeds with
decoding as further detailed and illustrated with reference to FIG.
10 below.
[0275] In a first step 495 as seen in FIG. 10, decoding is invoked.
In a second step 500, the system determines whether a character may
be decoded. If not, the system proceeds to the third step 505 to
determine whether or not the decoding logic level is greater than
1. If not, the system then proceeds to the eleventh step 510
wherein decoding is exited. If the decoding logic level is
determined to be greater than 1 in the third step 505, then the
system proceeds to the fourth step to determine whether or not the
decoding logic level is greater than 2. If the decoding logic level
is not determined to be greater than 2 in the fourth step 515, then
the system proceeds to the ninth step 520 as further detailed
hereinbelow. If the decoding logic level is determined to be
greater than 2 in the fourth step 515, then the system proceeds to
determine whether or not the character may be reconstructed in the
fifth step 525. If not, then the system proceeds to the ninth step
520 as further detailed hereinbelow. If the character is
reconstructed in the fifth step 525, the system then proceeds to
the sixth step 530 to determine whether or not the character may be
decoded. If not, the system then proceeds to the ninth step 520 as
further detailed hereinbelow. If, as a result of the second step
500 or the sixth step 530, it is determined that a character may be
decoded, the system then proceeds to the seventh step 535 to store
the decoded character in a decoded character buffer. The system
then proceeds to the eighth step 540 to determine whether or not a
stop character has been found. If so, the system then proceeds with
further processing in accordance with the routine detailed in
conjunction with FIG. 11 below. If it is determined that a stop
character is not found in the eighth step 540, the system then
proceeds with the tenth step as further detailed hereinbelow. If,
as a result of the fourth step 515, the fifth step 525, or the
sixth step 530, the system determines that a character may not be
properly decoded, an undecoded character identifier (i.e., marker)
is stored in an appropriate buffer and the system proceeds to the
tenth step 545. If an undecoded character identifier is stored in
the ninth step 520, or a stop character is not found in the eighth
step 540, the system proceeds to the tenth step 545 to determine
whether the end of raw data has been reached. If not, the system
returns to the second step 500 to determine whether or not
additional characters may be decoded and proceeds again through the
above steps accordingly. If it is determined that the end of raw
data has been reached in the tenth step 545, then the system
proceeds with further processing in accordance with the routine
detailed in conjunction with FIG. 11 below.
[0276] With reference to FIG. 11, the system first determines
whether or not a complete label has been decoded in a first step
550. If so, the scanning is done and the system proceeds to the
eleventh step 555. If it is determined that a complete label has
not been decoded, then the system proceeds to the second step 560
to determine whether or not the decoding logic level is greater
than 1. If yes, the system then proceeds to the eighth step 565 as
further detailed hereinbelow. If the decoding logic level is not
greater than 1, the system proceeds to the third step 570 to
determine whether the current scan is the fourth scan of the data.
If not, the system proceeds to the seventh step 575 to continue
scanning and processing as previously detailed. If it is determined
that the current scan is the fourth scan of the data, the system
then proceeds to the fourth step 580 to determine whether or not
level 2 logic has been allowed. If not, the system proceeds to the
sixth step 585 and marks the scan buffers as used prior to
advancing to the seventh step 575 to continue scanning. If it is
determined that level 2 logic has been allowed in the fourth step
580, the system then proceeds to the fifth step 590 wherein the
decoding logic level is set to logic level 2 prior to advancing to
the sixth step 585 to mark the scan buffers as used and then to the
seventh step 575 to continue scanning. In the fifth step 565,
character correlation and stitching are invoked based upon the
determination in the second step 560 that the decoding logic level
was greater than 1. The system then proceeds to the ninth step 595
to determine whether or not a complete label has been assembled. If
so, scanning is done and the system proceeds to the eleventh step
555 to complete this processing. If it is determined that a
complete label has not been assembled in the ninth step 595, the
system then proceeds to the tenth step 600 to determine whether the
correlated element buffer may be decoded. If so, the system
proceeds to the sixth step 585 to mark the scan buffers as used
prior to advancing to the seventh step 575 to continue scanning. If
it is determined that the correlated element buffer may not be
decoded in the tenth step 600, the system proceeds with further
processing in accordance with the routine detailed in conjunction
with FIG. 12 below.
[0277] With reference to FIG. 12, the system first determines
whether or not the current scan is the eighth scan of data in the
first step 605. If so, the system then proceeds to the second step
610 to determine whether or not level 3 logic is allowed. If the
current scan is determined not to be the eighth scan of data in the
first step 605, the system then proceeds to the fourth step 615 as
further detailed hereinbelow. If it is determined that level 3
logic is not allowed in the second step 610, the system advances to
the ninth step 620 as further detailed hereinbelow. If it is
determined that level 3 logic is allowed in the second step 610,
then the system proceeds to the third step 625 to set the decoding
logic level to logic level 3 prior to advancing to the ninth step
620 as further detailed hereinbelow. If it is determined in the
fourth step 615 that the current scan is the twelfth scan of data,
the system then proceeds to the fifth step 630 to determine whether
or not level 4 logic is allowed. If not, the system then proceeds
to the ninth step 620 as further detailed hereinbelow. If the
current scan is not determined to be the twelfth scan of data in
the fourth step 615, the system then proceeds to the seventh step
635 to determine whether the current scan number is a multiple of
four. If not, the system proceeds to the tenth step 640 to continue
scanning. If it is determined that the current scan number is a
multiple of four in the seventh step 635, the system then proceeds
to the eighth step 645 as further detailed hereinbelow.
[0278] If it is determined that level 4 logic is allowed in the
fifth step 630, the system then proceeds to the sixth step 650 to
set the decoding logic level to logic level 4 prior to advancing to
the eighth step 645. In the eighth step 645, element level
correlation is performed and the system is returned to the routine
detailed in conjunction with FIG. 10 for further processing. In the
ninth step 620, scan buffers are marked as used prior to the system
advancing to the tenth step 640 to continue scanning.
[0279] Because security may decrease as aggressiveness levels
increase (i.e., the more aggressive the technique, the more likely
that decoding errors may arise in general), it is further
envisioned in another aspect of the instant system and
methodologies, that one or more of the more aggressive techniques
may optionally be established for use only with respect to
symbologies incorporating check digit capabilities, and with
respect to which such check calculation is enabled--thus, allowing
the check character calculation to give additional security to the
decoding process under those circumstances.
[0280] Symbology Based Aggressiveness
[0281] Some existing scanners allow a user to set an overall
decoding aggressiveness level; however, once set, this level is
utilized with respect to all scans by the scanner. With respect to
users, e.g., in industrial areas, who often need to decode several
different symbology types, the overall setting for aggressiveness
may pose an unwanted risk of misreads for some symbologies. In a
further aspect of the system and methodologies herein, a desired
decoding aggressiveness level may be set based on symbology type,
for each symbology type to be scanned by a user. In this regard,
the level of aggressiveness for a particular symbology may be
established through user configuration or it may be determined by
programming within the scanner itself (utilizing further techniques
provided herein). In either event, the scanner could be made to
maintain a decoding aggressiveness level for each bar code
symbology. In this manner, a user could maintain the lowest risk of
decode aggressiveness overall and still read labels in symbologies
with poorly printed labels.
[0282] Learning Mode
[0283] The configuration of decoding for scanners can be very
complex due to the many types of symbologies that may be
encountered in different environments, as well as the many decoding
techniques and attributes thereof that are common in scanners. In
the past, a user (or scanner expert) would have to know about the
configurable attributes of the scanner, as well as the user's
environment, in order to configure the scanner appropriately. In
yet a further aspect, the instant systems and methodologies provide
for the determination of a decoding configuration through a
learning mode. To this end, scanning data from labels in the user's
environment may be used to set decoder configuration attributes.
For example, in learning mode, the scanner may use all possible
decoding techniques to determine the least aggressive technique
required to decode the particular label scanned for learning. When
learning mode is complete, the scanner would then use the learned
aggressiveness to decode future labels. Accordingly, less
intervention from a scanner expert is required. As well, the
configuration of decoding attributes may easily be customized to
the user's environment.
[0284] In conjunction with this technique, it is envisioned that
the configuration of scanner attributes could be determined by
putting the scanner into a learning mode. To this end, various
techniques may be implemented either alternatively or in
combination as a means of entering the learning mode. For example,
the learning mode could be initiated and/or terminated through the
use of special bar code labels which, when read, would result in
entry of the learning mode. Further, a hardware button or switch
may be utilized on the scanner body, or elsewhere, to provide
access to the learning mode. Still further, a command from an
external device which may be received through a defined interface
may be utilized. Alternatively, the learning mode could be "on" all
the time such that the scanner continues to learn and adjust to the
scanning environment as it is performing actual scans.
[0285] Where the learning mode is separately activated (as opposed
to continuously operating in the background at all times), the
scanner would be freed to perform decodes upon exiting the learning
mode. Based upon the configuration attributes established in the
learning mode, the scanner would then focus only on the decoding
techniques required for the labels of that particular environment;
thus, resulting in more efficient decoding since otherwise
non-productive decoding techniques may be skipped.
[0286] While in learning mode, the scanner would save configurable
attributes that allow it to read labels that are presented. After
saving the data, and exiting learning mode if necessary, the
scanner would then continue to use the saved configuration to read
future labels (until learning mode programming is received). The
system and methodologies herein further envision that all of the
attributes configured in a learning mode session with respect to a
scanner could subsequently be downloaded from that scanner and
uploaded to other scanners in the same environment.
[0287] In accordance with the system and methodologies herein,
there are many attributes that could be learned. Exemplary of
possible attributes that may, alone or in combination, be subject
to configuration through a learning mode are:
[0288] Symbology types to be operated upon in a particular
environment.
[0289] Threshold ranges, e.g., as previously discussed in relation
to automatic programming of decoding thresholds to enable a user to
easily adjust decoding aggressiveness to match label quality.
[0290] Maximum decoding aggressiveness level, e.g., as previously
discussed in relation to the advancing of decoding aggressiveness
through time.
[0291] Character correlation attributes, e.g., correlation across
several scans as previously discussed.
[0292] Stitching attributes, e.g., stitching bar code fragments
from poor quality labels as previously discussed.
[0293] Character reconstruction attributes for use in conjunction
with decoding poor quality labels through reconstruction of
normally undecodable characters as previously discussed.
[0294] Element correlation attributes as previously discussed.
[0295] Number of repetitive reads of a label required for
successful decoding.
[0296] It is further envisioned that some or all of the attributes
could be learned on a symbology basis as previously discussed
herein with respect to decoding aggressiveness levels based on
symbology types. For example, on a symbology basis, the scanner
could keep track of the number of scan lines that it takes to
reconstruct labels. It could also keep track of the level of
reconstruction that was needed to reconstruct the labels of a
symbology. Such information would then be used to help the scanner
determine what kind of reconstruction/decoding to first attempt in
future labels. It would also help the scanner determine how much
data should be analyzed before moving to the next level of
reconstruction.
[0297] Label Quality Reporting
[0298] Typically, bar code verifiers are used to acquire
information about the quality of bar code labels. This process,
however, requires additional work on the part of the user, i.e.,
that of scanning the bar code labels with the verifier. In a
further aspect of the preferred system and methods herein, label
quality feedback information is provided to the user about label
quality based upon the techniques used to decode the labels. The
algorithms currently employed for decoding poor quality labels each
typically compensate for a particular type of label defect. For
example, labels containing such defects as: invalid wide to narrow
ratio, invalid element proportions, spots, voids, tears and
disfigures can be reconstructed and decoded through the use of
different algorithms. Therefore, by knowing which algorithms were
used to decode a particular label, assumptions can be made about
the types of defects that may have been included in that label.
This label defect information, along with the decoded label data
itself, could be made available to the user, allowing them to
monitor the quality of the labels used in their system. By
providing label quality feedback directly from the bar code scanner
normally used in the process, the added expense and time of using
the verifier could be greatly reduced.
[0299] The appendix attached hereto provides exemplary software
code portions for implementing routines in relation to correlation
and stitching, element histograms and edge strength techniques and
element width and quality measure techniques detailed herein in
accordance with a preferred embodiment herein.
[0300] While the above-identified techniques are described in
conjunction with one another for use in a scanner system, it is
noted that the various aspects of the present system and
methodologies may advantageously be selectively employed alone or
in conjunction with one or more aspects in a particular system.
Moreover, the various rules and methodologies set forth herein are
not inclusive of all rules and methodologies that may readily be
employed by one skilled in the art with respect to particular
symbologies and/or user environments, nor are must all of the rules
and methodologies detailed herein be employed with respect to a
particular system. It will be apparent to those skilled in the art
that certain rules may be obviated and other rules added as a
result of system configuration requirements, symbology variations,
user needs and specifications, environmental considerations, and
the like. As well, while various aspects of the system and
methodologies herein have been set forth by way of certain
examples, many other variations and examples are possible and are
intended to be within the scope and spirit of this disclosure and
any claims made hereto. Furthermore, it is intended that
modifications to the disclosed system and methodologies may be made
without departing from the scope and spirit of the inventive
concepts set forth herein and in the appended claims.
2 This code is an implementation of the algorithims for correlation
and stitching of labels from incomplete label fragments generated
by the decoders.
/************************************************************************-
**** * FUNCTION: InitCharCorrelation AUTHOR: Jon Brandt, 7/10/98
REFERENCE: Product SDD DESCRIPTION: This function initializes the
correlation buffer for the current symbology. The label length is
set to 0 so that any new label will cause the buffers for
characters and scans to be rest. INPUTS:
currents_symbology_object_ptr - global store that keeps a pointer
to the current object. OUTPUTS: SYMB_RECONSTRUCT_INFO_TYPE
structure for the current symbology: left_frag.length - Length of
left reconstruction label is set to 0. right_frag.length - Length
of right reconstruction label is set to 0. full_length_label - set
to FALSE.
*************************************************************************-
**** / void InitCharCorrelation( void ) { /* Set the length to 0 to
force new labels to fill buffer. */
current_symbology_object_ptr->reconstr_info->left_frag.l-
ength = 0; current_symbology_object_ptr->reconstr_info->r-
ight_frag.length = 0; current_symbology_object_ptr->reconstr-
_info->full_length_label = FALSE; }
/************************************************************************-
**** * FUNCTION: CorrelateCharacters AUTHOR: John Brandt, 8/22/98
REFERENCE: Product SDD DESCRIPTION: This function decides on the
stitching and character correlation approach for the new fragment
in the current symbology. the function has to consider what label
information is currently stored for this symbology. It also has to
consider the type of fragment that is ready for correlation. Please
note that when complete label is read or stitched, FULL_Label is
set and the label will be stored in the area designated for the
left fragment. INPUTS: .sup. FORMAL .sup. unsigned char
fragment_type - type of label fragment. COMPLETE_LABEL_FRAGMENT -
entire label is ready for merge. LEFT_SIDE_FRAGMENT - Only part of
the left side of label is ready. RIGHT_SIDE_FRAGMENT - Only part of
the right side of label is ready. .sup. INFORMAL: .sup.
current_symbology_object_ptr - global store that keeps a pointer
.sup. to the current object. .sup. IntermediateLabelBuffer - global
variable pointing to the start location of the buffer that has the
new fragment. .sup. IntermediateLength - global variable of the
length of the new fragment. .sup. SYMB_RECONSTRUCT_INFO_TYPE
structure for the current symbology: .sup. unsigned char
*left_frag.char - Pointer to the characters of the left fragment.
.sup. unsigned char *left_frag.char_scans - Pointer to the storage
.sup. area for the number of scans for the left fragment. unsigned
char left_frag.length - length of the left fragment. .sup. unsigned
char *right_frag.chars - Pointer to the characters of the .sup.
right fragment. .sup. unsigned char *rightfrag.char_scans - Pointer
to the storage area .sup. for the number of scans for the right
fragment. unsigned char right_frag.length - length of the right
fragment. unsigned char full_length_label - indicates if a full
label has been seen. .sup. character_correlation_min_read - Minimum
number of times each character has to be seen in the same position
before the correlated label is accepted. OUTPUTS: .sup. FORMAL
.sup. BOOLEAN LabelComplete - The returned parameter indicates the
.sup. success of character correlation: .sup. TRUE - The label has
been completed. .sup. FALSE - The label is not complete. .sup.
INFORMAL .sup. IntermediateLabelBuffer - global variable pointing
to the start .sup. location of the buffer that may be filled with a
label .sup. completed with character correlation. .sup.
IntermediateLength - length of the label may be updated if the
.sup. correlation completed a label. .sup.
SYMB_RECONSTRUCT_INFO_TYPE structure for the current symbology
which .sup. may be updated with new label information. .sup.
unsigned char *left_frag.chars - Pointer to the characters .sup. of
the left fragment. .sup. unsigned char *left_frag.char_scans -
pointer to the storage area for the number of scans for the left
fragment. .sup. unsigned char left_frag.length - length of the left
fragment. .sup. unsigned char *right_frag.chars - Pointer to the
characters of the right fragment. .sup. unsigned char
*rightfrag.char_scans - Pointer to the storage area for the number
of scans for the right fragment. .sup. unsigned char
right_frag.length - length of the right fragment. .sup. unsigned
char full_length_label - indicates if a full label .sup. has been
seen. ***************************************-
************************************** / .sup. BOOLEAN
CorrelateCharacters( unsigned char fragment_tpye ) { .sup.
SYMB_RECONSTRUCT_INFO_TYPE *corr_info; .sup. unsigned char
*new_lbl; .sup. unsigned char *corr_lbl; .sup. unsigned char
*corr_scans; .sup. unsigned char char_num; .sup. unsigned char
start_pos_1; .sup. unsigned char start_pos_2; .sup. unsigned char
compare_length; .sup. unsigned char num_merge_chars; .sup. /* Get
pointer to character correlation information for this .sup. **
symbology. .sup. */ .sup. corr_info = current_symbology_object_p-
tr->reconstr_info; .sup. /* If this is a left side fragment,
attempt to stitch it. */ .sup. /* Check to see if stitching is
currently enabled */ .sup. if ( (fragment_type &
LEFT_SIDE_FRAGMENT) != 0) .sup. { .sup. StripUndecodableEndChars(
fragment_type ) ; /* Set long fragment flag if this is a long
fragment */ if ( NEW_FRAG_LEN >= MIN_CHARS_IN_LONG_FRAGMENT ) {
DM_Vars.label_or_long_frag- ment_decoded = TRUE; } if (
(ActiveDecodingAlgs & (DM_FIXED_LENGTH_STITCHING_MASK
.vertline.DM_VARIABLE_LENGTH_STIT- CHING_MASK) ) != 0) { /* Check
to see if we have a full length label stored */ if
(corr_info->full_length_label == TRUE) { /* See if the new
fragment and the full length label ** are similar enough to merge.
The new fragment ** length must be <= stored label length. */ if
( (corr_info->left_frag.length >= NEW_FRAG_LEN) && (
(num_merge_chars = CompareLeftFragToLabel ( NEW_FRAG_CHARS,
corr_info->left_frag.chars, NEW_FRAG_LEN ) ) > 0) ) { /* They
are similar so merge them */ MergeLeftFragments (
&(corr_info->left_frag) , NEW_FRAG_CHARS, num_merge_chars )
; } else { /* They are not similar so do not use the new fragment
** and return a FALSE. */ return FALSE; } } else /* The correlation
store only has fragments */ { /* See if new left fragment and left
stored fragment ** are similar enough to merge. The stored fragment
** length must not be 0. ** First, figure out which fragment is
smallest for the comparison. */ if ( NEW_FRAG_LEN >
corr_info->left_frag.length ) { compare_length = NEW_FRAG_LEN; }
else { compare_length = corr_info->left_frag.length; } if (
(corr_info->left_frag.length != 0) && (TRUE
==CompareWithFragmentCriteria( NEW_FRAG_CHARS,
corr_info->left_frag.chars, compare_length )) ) { /* They are
similar so merge the new fragment ** into the stored fragment. */
MergeLeftFragments( &(corr_info->left_fra- g),
NEW_FRAG_CHARS, NEW_FRAG_LEN ); } else /* The new fragment is not
similar to stored fragment */ { /* Store new fragment if it is
longer than 3/4 ** of the stored fragment. if ( (unsigned
short)NEW_FRAG_LEN > ((unsigned short)
(corr_info->left_frag.length) * 3 / 4) ) { StoreLeftFragment(
&(corr_info->left_frag), NEW_FRAG_CHARS, NEW_FRAG_LEN ); } }
} } else { /* stitching is not enabled so discard this fragment */
/* Nothing has changed so return a FALSE. */ return FALSE; } }/*
End of processing for left side fragment */ /* If this is a right
side fragment, attempt to stitch it. */ /* Check to see if
stitching is currently enabled */ else if ((fragment_type &
RIGHT_SIDE_FRAGMENT) != 0) { StripUndecodableEndChars (
fragment_type ); /* Set long fragment flag if this is a long
fragment */ if ( NEW_FRAG_LEN >= MIN_CHARS_IN_LONG_FRAGMENT {
DM_Vars.label_or_long_fragment_decoded = TRUE; } if
((ActiveDecodingAlgs & (DM_FIXED_LENGTH_STITCHING_MASK
.vertline. DM_VARIABLE_LENGTH_STITCHING_MASK)) != 0) { /* Check to
see if we have a full length label stored */ if
(corr_info->full_length_label == TRUE) { /* See if the new
fragment and the full length label ** are similar enough to merge.
The new fragment ** length must be <= stored label length. */ if
( (corr_info->left_frag.length >= NEW_FRAG_LEN) &&
((num_merge_chars = CompareRightFragToLabel ( NEW_FRAG_CHARS,
corr_info- >left_frag. chars, NEW_FRAG_LEN, corr_info-
>left_frag.length )) > 0) ) { /* They are similar so merge
them. */ start_pos_1 = (unsigned char)
(corr_info->left_frag.length - num_merge_chars);
MergeCharsFromNewFrag(
&(corr_info->left_frag.chars(start_pos_1[),
&(corr_info->left_frag.char_scans [start_pos_l])
NEW_FRAG_CHARS, num_merge_chars ); } else { /* They are not similar
so do not use the new fragement ** and return a FALSE. */ return
FALSE; } } else /* The correlation store only has fragments */ { /*
See if new right fragment and right stored fragment ** are similar
enough to merge. The stored fragment ** length must not be 0. **
First, figure out which fragment is smallest for the comparison. */
if ( NEW_FRAG_LEN < corr_info->right_frag.length ) { compare
length = NEW_FRAG_LEN; } else compare_length =
corr_info->right_frag.length; } /* Now set up for the
comparison. */ start_pos_1 = (unsigned char) (NEW_FRAG_LEN -
compare_length); start_pos_2 = (unsigned char) (FRAG_BUFFER_SIZE -
compare_length); if ( (corr_info->right_frag.length != 0)
&& (TRUE == CompareWithFragmentCriteria (
&(NEW_FRAG_CHARS [start_pos_2]),
&(corr_info->right_frag.chars- [start_po_2]), compare_length
)) ) { /* They are similar so merge the new fragment ** into the
stored fragment. */ MergeRightFragments (
&(corr_info->right_frag), NEW_FRAG_CHARS, NEW_FRAG_LEN ); }
else /* The new fragment is not similar to stored fragment */ { /*
Store new fragment if it is longer than 3/4 ** of the stored
fragment. */ if ( (unsigned short)NEW_FRAG_LEN > ((unsigned
short) (corr_info->right_frag.length) * 3 / 4) ) {
StoreRightFragment( &(corr_info->right_frag) ,
NEW_FRAG_CHARS, NEW_FRAG_LEN ) ; } else { /* Nothing has changed so
return a FALSE. */ return FALSE; } } } } else { /* stitching is not
enabled so discard this fragment. */ /* Nothing has changed so
return a FALSE. */ return FALSE; } } /* End of processing for right
side fragment */ /* Check to see if the label has undecodable
characters or ** is a poor quality label. In both cases attempt to
merge ** the label with previous scans. */ else if ( (
((ActiveDecodingAlgs & DM_CHARACTER_CORRELATION_MASK) != 0)
&& ((fragment_type & UNDECODED_CHARACTERS) != 0) )
.vertline. .vertline. ((fragment_type & POOR_QUALITY_LABEL) !=
0) ) { /* Set full label flag if this is a long fragment */
DM_Vars.label_or_long_fragment_decoded = TRUE; /* Check to see if
we already have a full length label */ if (corr_info->full_len-
gth_label == TRUE) { /* If we already have a full length label and
their ** lengths match, try to merge them together. */ if (
NEW_FRAG_LEN == corr_info->left_frag.length ) { /* See if labels
are similar enough to merge */ if ( TRUE ==
CompareWithFullLabelCriteria ( NEW_FRAG_CHARS,
corr_info->left_frag.chars, NEW_FRAG_LEN ) ) { /* They are
similar so merge them */ MergeLeftFragments(
&(corr_info->left_frag) , NEW_FRAG_CHARS, NEW_FRAG_LEN ); }
else { /* They are not similar so store new full length label */
StoreLeftFragment( &(corr_info->left_frag- ) ,
NEW_FRAG_CHARS, NEW_FRAG_LEN ) ; } } else /* the lengths do not
match */ { /* Store new full length label. */ StoreLeftFragment(
&(corr_info->left_frag), NEW_FRAG_CHARS, NEW_FRAG_LEN ); } }
else /* The correlation store only has fragments */ { /* See if new
full length label and left stored fragment ** are similar enough to
merge. The stored fragment ** length must be <= new label length
and not 0. */ if ( (corr_info->left_frag.- length != 0)
&& (corr_info->left_frag.length <= NEW_FRAG_LEN)
&& ((num_merge_chars = CompareLeftFragToLabel(
corr_info->left_frag.chars, NEW_FRAG_CHARS,
corr_info->left_frag.length )) > 0) ) { /* Adjust left
fragment length for merge */ corr_info->left_frag.length =
num_merge_chars; /* Merge the new label into the fragment. */
MergeLeftFragments( &(corr_info->left_frag) ,
NEW_FRAG_CHARS, NEW_FRAG_LEN ); } else { /* They are not similar so
store new full length label */ StoreLeftFragment(
&(corr_info->left_frag- ), NEW_FRAG_CHARS, NEW_FRAG_LEN ); }
/* We now have a full length label so update the flag */
corr_info->full_length_label = TRUE; /* See if new full length
label in the left store and right ** stored fragment are similar
enough to merge. The stored ** fragment length must be <= new
label length and not 0. */ start_pos_1 = (unsigned char)
(FRAG_BUFFER_SIZE - corr_info- >right_frag.length) ; if (
(corr_info->right_frag.length != 0) &&
(corr_info->right_frag.length <= NEW_FRAG_LEN) &&
(num_merge_chars = CompareRightFragToLabel (
&(corr_info->right_frag.chars[start_pos_1]),
corr_info->left_frag.chars, corr_info->right_frag.length,
NEW_FRAG_LEN )) > 0) ) { /* Merge the right fragment into the
full length label ** in the left store. */
corr_info->right_frag.length = num_merge_chars;
MergeOverlapOfStoreFrags( num_merge_chars ); } else { /* They are
not similar. */ } /* The right fragment needs to be discarded so **
set length to 0. */ corr_info->right_frag.length = 0; } } /* End
of processing for undecoded characters or poor quality label */ /*
If we don't have a full length label but we do ** have fragments,
attempt to stitch the fragments. */ if (
(corr_info->full_length_label == FALSE) && (
corr_info->left_frag.length > 0 ) && (
corr_info->right_frag.length > 0 ) ) { corr_info->stitch
() ; } /* If we have a full length label, check for enough scans **
for each character. */ corr_scans =
corr_info->left_frag.char_scans; if
(corr_info->full_length_label == TRUE) { /* Check the number of
scans for each character. */ for ( char_num = 0; char_num <
corr_info->left_frag.length; char_num++ ) { if ( *corr_scans
< DM_Config.character_correlation_min_read ) { /* If we don't
have enough scans, get out now */ return FALSE; } corr_scans++; }
/* Since all characters meet requirement, load correlated ** label
into intermediate label. ** Set new length. */ NEW_FRAG_LEN =
corr_info->left_frag.length; new_lbl = NEW_FRAG_CHARS; corr_lbl
= corr_info->left_frag.chars; for ( char_num = 0; char_num <
NEW_FRAG_LEN; char_num++ ) { *new_lbl = *corr_lbl; new_lbl++;
corr_lbl++; } return TRUE; } /* end of check for full label with
enough scans */ return FALSE; }
/************************************************************************-
** * FUNCTION: CompareWithFullLabelCriteria AUTHOR: Jon Brandt,
11/24/98 REFERENCE: Product SDD DESCRIPTION: This fuction compares
two full length labels to determine if they are similar. If the
number of decoded characters that are different is more than 1/4 of
the label length of the decoded characters, a FALSE is returned.
Otherwise, a TRUE is returned. Both labels must be the same length.
INPUTS: FORMAL unsigned char *Lbl1 - Pointer to the label
characters from the first label. unsigned char *Lbl2 - Pointer to
the label characters from the second label. unsigned char num_chars
- Number of characters in label. INFORMAL None OUTPUTS: FORMAL TRUE
- The comparison found a matching set of labels. FALSE - The
comparison found a non-matching set of labels. INFORMAL None
****************************-
************************************************* / BOOLEAN
CompareWithFullLabelCriteria( register unsigned char *lbl1,
register unsigned char lbl2, unsigned char num_chars ) { unsigned
char char_num; unsigned char num_diff_chars; unsigned char
num_decoded_chars; num_diff_chars = 0; num_decoded_chars = 0; /*
Step through the contents of each buffer */ for ( char_num = 0;
char_num < num_chars; char_num++ ) { /* Only count characters if
both of them are decoded. */ if ( ( *lbl1 != UNDECODABLE_CHAR )
&& ( *lbl2 != UNDECODABLE_CHAR ) ) { /* If the characters
don't match, increment counter. */ if ( *lbl1 != *lbl2 ) {
num_diff_chars++; } /* Increment number of decode characters */
num_decoded_chars++; } /* Increment to next buffer locations */
lbl1++; lbl2++; } /* Determine if labels are similar. ** Devide
num_decoded_chars by 4 to determine if the number of ** different
characters is greater than 1/4 of the decoded chars. */ if (
num_diff_chars > (num_decoded_chars / 4) ) { /* More than 1/4 of
the characters are different so return a false */ return FALSE; }
else { /* The labels are similar so return a true */ return TRUE; }
}
/***********************************************************************-
***** * FUNCTION: CompareLeftFragToLabel AUTHOR: Jon Brandt,
11/24/98 REFERENCE: Product SDD DESCRIPTION: This function compares
a left fragment to a porion of a full length label to determine if
they are similar. If the number of decoded characters that are
different is more than 1/4 of the merge length, a 0 is returned.
This function also determines the number of characters that can be
merged. The number of merge characters is returned when the
comparison determined a match. INPUTS: FORMAL unsigned char
*left_frag - Pointer to the characters of the left fragment.
unsigned char *full_label - Pointer to the characters of the full
length label. unsigned char num_chars - Number of characters to
compare. INFORMAL None OUTPUTS: FORMAL merge_chars - The number of
characters to merge. 0 - The comparison did not find a match
between the fragment and label. INFORMAL None
**********************************************************-
******************* / unsigned char CompareLeftFragToLabel (
register unsigned char *left_frag, register unsigned char
*full_label, unsigned char merge_chars ) { /* Determine merge
length giving priority to the characters ** close to the start/stop
character. Only allow 1/2 of the ** fragment to be discarded. */
merge_chars = DetermineLeftFragMergeLen( left_frag, full_label,
merge_chars, merge_chars/2 ); if ( ( merge_chars >=
MIN_MERGE_LEN ) && ( TRUE == CompareWithFullLabelCriteria(
left_frag, full_label, merge_chars ) ) ) { return merge_chars; }
else { return 0; } }
/********************************************************-
******************** * FUNCTION: CompareRightFragToLabel AUTHOR:
Jon Brandt, 11/24/98 REFERENCE: Product SDD DESCRIPTION: This
function compares a right fragment to a portion of a full length
label to determine if they are similar. If the number of decoded
characters that are different is more than 1/4 of the merge length,
a 0 is returned. This function also determines tha number of
characters that can be merged. The number of merge characters is
returned when the comparison determined a match. INPUTS: FORMAL
unsigned char *right_frag - Pointer to the leftmost character of
the right fragment. unsigned char *full_label - Pointer to the
leftmost character of the full length label. unsigned char
num_right_chars - Number of right fragment chars. unsigned char
num_label_chars - Number of label chars. INFORMAL None OUTPUTS:
FORMAL merge_chars - The number of characters to merge. 0 - The
comparison did not find a match between the fragment and label.
INFORMAL None ***************************************-
************************************** / unsigned char
CompareRightFragToLabel( register unsigned char *right_frag,
register unsigned char *full_label, unsigned char num_right_chars,
unsigned char num_label_chars ) { unsigned char merge_chars; /*
Determine merge length giving priority to the characters ** close
to the start/stop character. Only allow 1/2 of the ** fragment to
be discarded. */ merge_chars = DetermineRightFragMergeLen(
right_frag, full_label, num_right_chars, num_label_chars,
num_label_chars/2 ); right_frag += ( num_right_chars - merge_chars
); full_label += ( num_label_chars - merge_chars ); if ( (
merge_chars >= MIN_MERGE_LEN ) && ( TRUE
==CompareWithFullLabelCriteria( right_frag, full_label, merge_chars
) ) ) { return merge_chars; } else { return 0; } }
/********************************************************-
******************** * FUNCTION: CompareWithFragmentCriteria
AUTHOR: Jon Brandt, 8/22/98 REFERENCE: Product SDD DESCRIPTION:
This function compares two fragments to determine if they are
similar. If the number of decoded characters that are different is
more than 1/2 of the decoded chars, a FALSE is returned. Otherwise,
a TRUE is returned. INPUTS: FORMAL unsigned char *frag1 - Pointer
to the label characters from the first fragment. unsigned char
*frag2 - Pointer to the label characters from the second fragment.
unsigned char num_chars - Number of characters to compare. INFORMAL
None OUTPUTS: FORMAL TRUE - The label comparison found a matching
set of fragments. FALSE - The label comparison found a non-matching
set of fragments. INFORMAL None
***********************************************************************-
****** / BOOLEAN CompareWithFragmentCriteria( register unsigned
char *frag1, register unsigned char *frag2, unsigned char num_chars
) { unsigned char char_num; unsigned char num_diff_chars; unsigned
char num_decoded_chars; num_decoded_chars = 0; num_diff_chars = 0;
/* Step through the contents of each buffer */ for ( char_num = 0;
char_num < num_chars; char_num++ ) { /* Only count the
characters if both of them are decoded. */ if ( ( *frag1 !=
UNDECODABLE_CHAR ) && ( *frag2 != UNDECODABLE_CHAR ) ) { /*
If the characters don't match, increment counter. */ if ( *frag1 !=
*frag2 ) { num_diff_chars++; } num_decoded_chars++; } /* Increment
to next buffer locations */ frag1++; frag2++; } /* Determine if
fragments are similar. ** Devide number of decoded chars by 2
determine if the number of ** different characters is greater than
1/2 of the decoded chars. */ if ( num_diff_chars >
(num_decoded_chars / 2) ) { /* More than 1/2 of the characters are
different so return a false */ return FALSE; } else { /* The
fragments are similar so return a true */ return TRUE; } }
/*******************************************************************-
********* * FUNCTION: DetermineLeftFragMergeLen AUTHOR: Jon Brandt,
11/24/98 REFERENCE: Product SDD DESCRIPTION: This function discards
left fragment and characters that do not match the full length
label. This is done to give the characters of the full length a
higher priority than the fragment end characters. The new length of
the fragment is returned. INPUTS: FORMAL unsigned char
*Left_Frag_Chars - Pointer to the label characters of the left
fragment. unsigned char *Full_Label_Chars - Pointer to the label
characters of the full length label. unsigned char num_chars -
Number of characters in the left fragment. unsigned char
max_discard_chars - maximum number of characters that can be
discarded. INFORMAL None OUTPUTS: FORMAL unsigned char num_chars -
Number of characters remaining in fragment. INFORMAL None
********************************************-
********************************* / unsigned char
DetermineLeftFragMergeLen( register unsigned char *left_frag_chars,
register unsigned char *full_label_chars, unsigned char num_chars,
unsigned char max_discard_chars ) { /* Increment pointers to the
end of the fragment. */ left_frag_chars += (num_chars - 1);
full_label_chars += (num_chars - 1); /* Step through the characters
starting at the end of the fragment */ while ( (num_chars > 0)
&& (max_discard_chars > 0) ) { /* if the characters
don't match or if one of them ** is undecodable go to the previous
character of ** the fragment. */ if ( ( *left_frag_chars !=
*full_label_chars ) .vertline. .vertline. ( *left_frag_chars ==
UNDECODABLE_CHAR ) .vertline. .vertline. ( *full_label_chars ==
UNDECODABLE_CHAR ) ) { /* The characters are different so decrease
the number. */ num_chars--; max_discard_chars--; left_frag_chars--;
full_label_chars--; } else /* The characters match */ { /* Stop
searching for matching chars */ break; } } return num_chars; }
/************************************************************************-
**** * FUNCTION: DetermineRightFragMergeLen AUTHOR: Jon Brandt,
11/24/98 REFERENCE: Product SDD DESCRIPTION: This function discards
all of the right fragment end characters that do not match the full
length label. This is done to give the characters of the full
length a higher priority than the fragment end characters. The new
length of the fragment is returned. INPUTS: FORMAL unsigned char
*Right_Frag_Chars - Pointer to the leftmost character of the right
fragment. unsigned char *Full_Label_Chars - Pointer to the leftmost
character of the full length label. unsigned char num_frag_chars -
Number of characters in the right fragment. unsigned char
num_full_label_chars - Number of characters in the full label.
unsigned char max_discard_chars - maximum number of characters that
can be discarded. INFORMAL None OUTPUTS: FORMAL unsigned char
num_chars - Number of characters remaining in fragment. INFORMAL
None
*************************************************************************-
**** / unsigned char DetermineRightFragMergeLen( register unsigned
char *right frag_chars, register unsigned char *full_label_chars,
unsigned char num_frag_chars, unsigned char num_full_label_chars,
unsigned char max_discard_chars ) { /* Increment pointers to the
end of the fragment. ** The right fragment is positioned at the
right end of the buffer. */ full_label_chars +=
(num_full_label_chars - num_frag_chars); /* Step through the
characters starting at the end of the fragment */ while (
(num_frag_chars > 0) && (max_discard_chars > 0) ) {
/* if the characters don't match or if one of them ** is
undecodable go to the next character of ** the fragment. */ if ( (
*right_frag_chars != *full_label_chars ) .vertline. .vertline. (
*right_frag_chars == UNDECODABLE_CHAR ) .vertline. .vertline. (
*full_label_chars == UNDECODABLE_CHAR ) ) { /* The characters are
different so decrease the number of ** characters. */
num_frag_chars--; max_discard_chars--; right_frag_chars++;
full_label_chars++; } else /* The characters match */ { /* Stop
searching for matching chars */ break; } } return num_frag_chars; }
/****************************************-
************************************ * FUNCTION: MergeLeftFragments
AUTHOR: Jon Brandt, 8/23/98 REFERENCE: Product SDD DESCRIPTION:
This function performs the merge of two label fragments and aligns
the left side of each fragment. It uses the label characters and
the number of scans for each character to perform the merge. This
function handles the merge of label fragments that are not the same
size. INPUTS: FORMAL LABEL_FRAGMENT_TYPE *stored_fragment - pointer
to store of a fragment. This store includes the characters, scans,
and length of the fragment. unsigned char *new_frag_chars - Pointer
to the characters of the new fragment. unsigned char
new_frag_length - length of the new fragment. INFORMAL none.
OUTPUTS: FORMAL LABEL_FRAGMENT_TYPE *stored_fragment - The fragment
data will change with merge. INFORMAL none
*****************************************-
************************************ / void MergeLeftFragments(
LABEL_FRAGMENT_TYPE *stored_fragment, unsigned char
*new_frag_chars, unsigned char new_frag_length ) { unsigned char
merge_length; unsigned char copy_start_pos; unsigned char
copy_frag_length; /* Check to see if new fragment is bigger than
stored fragment. */ if ( stored_fragment->length <
new_frag_length ) { /* New fragment is bigger than stored fragment
so start by ** determining how much to merge. The actual merge will
** happen below. */ merge_length = stored_fragment->length; /*
Now determine how many characters need to be copied from ** new to
stored and then store tehm. */ copy_start_pos =
stored_fragment->length; copy_length = (unsigned char)
(new_frag_length - stored_fragment- >length);
StoreCharsFromNewFrag(
&(stored_fragment->chars[copy_start_pos]),
&(stored_fragment->char_scans[copy_start_pos]),
&(new_frag_chars[copy_start_pos]), copy_length ); /* Now update
the stored fragment with the new length */
stored_fragment->length = new_frag_length; } else /* The stored
fragment is at least as long as the new fragment */ { /* For this
case we only need to merge the overlapping section */ merge_length
= new_frag_length; } /* Merge the common sections of the 2
fragments */ MergeCharsFromNewFrag( stored_fragment->chars,
stored_fragment->char_scans, new_frag_chars, merge_length ); }
/***********************-
***************************************************** * FUNCTION:
MergeRightFragments AUTHOR: Jon Brandt, 8/23/98 REFERENCE: Product
SDD DESCRIPTION: This function performs the merge of two label
fragments and aligns the right side of each fragment. It uses the
label characters and the number of scans for each character to
perform the merge. This function handles the merge of right
fragments that are not the same size. Please note that the right
fragment is stored at the end of the fragment buffer. The new
fragment is stored at the beginning of its buffer. INPUTS: FORMAL
LABEL_FRAGMENT_TYPE *stored_fragment - pointer to store of a
fragment. This store includes the characters, scans, and length of
the fragment. unsigned char *new_frag_chars - Pointer to the
characters of the new fragment. unsigned char new_frag_length -
length of the new fragment. INFORMAL none. OUTPUTS: FORMAL
LABEL_FRAGMENT_TYPE *stored fragment - The fragment data will
change with the merge. INFORMAL none
*************************************************************************-
**** / void MergeRightFragments( LABEL_FRAGMENT_TYPE *stored
fragment, unsigned char *new_frag_chars, unsigned char
new_frag_length ) { unsigned char merge_length; unsigned char
merge_stored_start_pos; unsigned char merge_new_start_pos; unsigned
char copy_stored_start_pos; unsigned char copy_length; /* Check to
see if new fragment is bigger than stored fragment. */ if (
stored_fragment->length < new_frag_length ) { /* New fragment
is bigger than stored fragment so start by ** determining how much
to merge. The actual merge will ** happen below. */ merge_length =
stored_fragment->length; /* Now determine how many characters
need to be copied from ** new to stored and then store them. The
stored right ** fragment is at the end of the buffer. The new
fragment ** is at the beginning of its buffer. */
copy_stored_start_pos = (unsigned char) (FRAG_BUFFER_SIZE -
new_frag_length); copy_length = (unsigned char)(new_frag_length -
stored_fragment- >length); StoreCharsFromNewFrag( &
(stored_fragment- >chars[copy_stored_s- tart_pos]), &
(stored_fragment- >char_scans[copy_stored_- start_pos]),
new_frag_chars, copy_length ); /* Now update the stored fragment
with the new length */ stored_fragment->length =
new_frag_length; } else /* The stored fragment is at least as long
as the new fragment */ { /* For this case we only need to merge the
overlapping section */ merge_length = new_frag_length; } /* Merge
the common sections of the 2 fragments. The stored right **
fragment is at the end of the buffer. The new fragment ** is at the
beginning of its buffer. */ merge_stored_start_pos = (unsigned
char) (FRAG_BUFFER_SIZE - merge_length); merge_new_start_pos =
(unsigned char) (new_frag_length - merge_length);
MergeCharsFromNewFrag (
&(stored_fragment->chars[merge_stored_st- art_pos]), &
(stored_fragment->char_scans[merge_stored_start_po- s]), &
(new_frag_chars[merge_new_start_pos]), merge_length ); }
/*****************************************************-
********************** * FUNCTION: MergeCharsFromNewFrag AUTHOR:
Jon Brandt, 8/23/98 REFERENCE: Product SDD DESCRIPTION: This
function performs the merge of two fragments. left side of each
fragment. It uses the label characters and the number of scans for
each character to perform the merge. INPUTS: FORMAL unsigned char
*stored_frag_chars - pointer to the characters of the stored
fragment. unsigned char *stored_frag_scans - pointer to the scans
of the stored fragment. unsigned char *new_frag_chars - Pointer to
the characters of the new fragment. unsigned char new_frag_length -
length to merge. INFORMAL none. OUTPUTS: FORMAL unsigned char
*stored_frag_chars - may be updated with new or changed charcters.
unsigned char *stored_frag_scans - may be updated with additional
scan information. INFORMAL none
************************************************************-
**************** / void MergeCharsFromNewFrag( register unsigned
char *stored_frag_chars, register unsigned char *stored_frag_scans,
register unsigned char *new_frag_chars, unsigned char merge_length
) { unsigned char char_num; /* Step through the contents of each
buffer */ for ( char_num = 0; char_num < merge_length;
char_num++ ) { /* Only update the stored character if the ** new
character is decoded. */ if ( *new_frag_chars != UNDECODABLE_CHAR )
{ /* Check to see if the characters match. */ if (
*stored_frag_chars == *new_frag_chars ) { /* The characters match.
Update ** scans unless it's bigger than O.times.7F to ** prevent an
overrun. */ if ( *stored_frag_scans <
DM_Config.character_correlation_max_scans ) { (*stored_frag_scans)
++; } } else /* The new character is different */ { /* Decrement
scans if there are any scans */ if ( *stored_frag_scans > 0 ) {
(*stored_frag_scans) --; } /* If there are no scans, replace the **
stored character and update scans. */ if ( *stored_frag_scans == 0
) { *stored_frag_chars = *new_frag_chars; *stored_frag_scans = 1 }
} } /* Increment to next buffer locations */ stored_frag_chars++;
stored_frag_scans++; new_frag_chars++; } }
/****************************-
************************************************ * FUNCTION:
StoreCharsFromNewFrag AUTHOR: Jon Brandt, 8/23/98 REFERENCE:
Product SDD DESCRIPTION: This function copies the characters into
the store and initializes the scans to the proper value for the
character data. INPUTS: FORMAL unsigned char *target_store_chars -
pointer to the storage area for the characters. unsigned char
*target_store_char_scans - pointer to the storage area for the
character scans. unsigned char *new_chars - Pointer to the new
characters. unsigned char store_length - length to store. INFORMAL
none. OUTPUTS: FORMAL unsigned char *target_store_chars - will be
updated with new characters. unsigned char *target_store_char_scans
- will be updated with new scan values. INFORMAL none
*************************************************************************-
**** / void StoreCharsFromNewFrag( register unsigned char
*target_store_chars, register unsigned char
*target_store_char_scans, register unsigned char *new_chars,
unsigned char store_length ) { unsigned char char_num; /* Step
through the contents of each buffer */ for ( char_num = 0; char_num
< store_length; char_num++ ) { /* Store the character. */
*target_store_chars = *new_chars; /* Update the number of scans for
this character. */ if ( *new_chars == UNDECODABLE_CHAR ) {
*target_store_char_scans = 0; } else { *target_store_char_scans =
1; } /* Increment to next buffer locations */ new_chars++;
target_store_chars++; target_store_char_scans++; } }
/************************************************************************-
**** * FUNCTION: MergeOverlapOfStoredFrags AUTHOR: Jon Brandt,
8/24/98 REFERENCE: Product SDD DESCRIPTION: This function takes the
information from both stored fragments and merges the specified
amount of overlap. The result is stored in the left fragment store.
The characters and the character scans are updated. The overlap
region of the left fragment is on the right side of the fragment.
The overlap region of the right fragment is on the left side of the
fragment. INPUTS: FORMAL unsigned char overlap_length - length of
the overlap region. INFORMAL current_symbology_object_ptr - global
store that keeps a pointer to the current object.
SYMB_RECONSTRUCT_INFO_TYPE structure for the current symbology:
unsigned char *left_frag.chars - Pointer to the characters of the
left fragment. unsigned char *left_frag.char_scans - Pointer to the
storage area for the number of scans for the left fragment.
unsigned char left_frag.length - length of the left fragment.
unsigned char *right_frag.chars - Pointer to the characters of the
right fragment. unsigned char *rightfrag.char_scans - Pointer to
the storage area for the number of scans for the right fragment.
unsigned char right_frag.length - length of the right fragment.
character_correlation_min_read - Minimum number of times each
character has to be seen in the same position before the correlated
label is accepted. OUTPUTS: FORMAL none INFORMAL
SYMB_RECONSTRUCT_INFO_TYPE structure for the current symbology.
This information will be updated with the merge. unsigned char
*left_frag.chars - Pointer to the characters of the left fragment.
unsigned char *left_frag.char scans - Pointer to the storage area
for the number of scans for the left fragment.
***********************************************-
****************************** / void MergeOverlapOfStoredFrags(
unsigned char overlap_length ) { SYMB_RECONSTRUCT_INFO_TYPE
*corr_info; unsigned char *left_frag_chars; unsigned char
*left_frag_char_scans; unsigned char *right_frag_chars; unsigned
char *right_frag_char_scans; unsigned char char_num; /* Get pointer
to character correlation information for this ** symbology.
corr_info = current_symbology_object_ptr->reconstr_- info; /*
Set up pointers to character and scan buffers. ** The left buffer
needs to start overlap length from the ** right end of the
fragment. The right buffer needs to ** start at the left end of the
fragment considering that ** the right fragment is stored at the
high end of the buffer. */ left_frag_chars =
&(corr_info->left_frag.chars [corr_info->left_frag.length
- overlap length]); left_frag_char_scans
=&(corr_info->left_frag.char_scans
[corr_info->left_frag.length - overlap_length]);
right_frag_chars =&(corr_info->right_frag.chars
[FRAG_BUFFER_SIZE - corr_info->right_frag.length]);
right_frag_char_scans =&(corr_info->right frag.char_scans
[FRAG_BUFFER_SIZE - corr_info->right_frag.length]); /* Step
through the contents of each buffer */ for ( char_num = 0; char_num
< overlap_length; char_num++ ) { /* The confidence level of the
characters in the overlapping ** region is not high since they are
near the end of the ** fragment. Before each character position is
merged, give the ** character from each fragment a maximum scans of
** character_correlation_mi- n_read. This will keep a misdecoded **
character from overriding a correctly decoded character that ** may
have only a few scans. */ if ( *right_frag_char_scans >
DM_Config.character_correlation_min_read ) { *right_frag_char_scans
= DM_Config.character_correlation_min_read; } if (
*left_frag_char_scans > DM_Config.character_cor-
relation_min_read ) { *left_frag_char_scans =
DM_Config.character_correlation_min_read; } /* If the left fragment
character is undecoded, get character ** from right fragment. if
(*left_frag_chars == UNDECODABLE_CHAR) { *left_frag_chars =
*right_frag_chars; *left_frag_char_scans = *right_frag_char_scans;
} /* if left frag char is decoded and right frag char is decoded */
else /* left f rag char is decoded */ if (*right_frag_chars !=
UNDECODABLE_CHAR) { /* If both chars are the same combine the
number of scans. */ if ( *left_frag_chars == *right_frag_chars ) {
*left_frag_char_scans += *right_frag_char_scans; if (
*left_frag_char_scans > DM_Config.character_correlation_max_sca-
ns ) { *left_frag_char_scans =
DM_Config.character_correlation_max_scans; } } else /* Both
characters are not the same. */ { /* Store the character with the
most scans and ** combine the scans by taking the difference of **
the two fragments. if ( *left_frag_char_scans >
*right_frag_char_scans ) { *left_frag_char_scans -=
*right_frag_char_scans; } else if ( *left_frag_char_scans <
*right_frag_char_scans ) { *left_frag_chars = *right_frag_chars;
*left_frag_char_scans = (unsigned char) (*right_frag_char_scans -
*left_frag_char_scans); } else /* The scans are equal */ {
*left_frag_chars = UNDECODABLE_CHAR; *left_frag_char_scans = 0; } }
} /* Increment to next buffer locations */ left_frag_chars++;
left_frag_char_scans++; right_frag_chars++;
right_frag_char_scans++; } }
/************************************************************************-
**** * FUNCTION: StoreLeftFragment AUTHOR: Jon Brandt, 8/3/98
REFERENCE: Product SDD DESCRIPTION: This function stores a new left
fragment or label in the left correlation store and also
initializes the number of scans and length of the fragment. INPUTS:
FORMAL LABEL_FRAGMENT_TYPE *target_store - Pointer to store for
fragment including characters, scans, and length. unsigned char
*new_frag - Pointer to the characters of the new fragment. unsigned
char new_frag_length - length of the new fragment. INFORMAL none.
OUTPUTS: FORMAL LABEL_FRAGMENT_TYPE *target_store - The target
store will be updated with the new fragments. INFORMAL none
*************************-
**************************************************** / void
StoreLeftFragment( LABEL_FRAGMENT_TYPE *target_store, unsigned char
*new_frag, unsigned char new_frag_len ) { StoreCharsFromNewFrag(
target_store->chars, target_store->char_scan- s, new_frag,
new_frag_len ); target_store->length = new_frag_len; }
/******************************************-
********************************** * FUNCTION: StoreRightFragment
AUTHOR: Jon Brandt, 8/3/98 REFERENCE: Product SDD DESCRIPTION: This
function stores a new right fragment or label in the right
correlation store and also initializes the number of scans and
length of the fragment. INPUTS: FORMAL LABEL_FRAGMENT_TYPE
*target_store - Pointer to store for fragment including characters,
scans, and length. unsigned char *new_frag - Pointer to the
characters of the new fragment. unsigned char new_frag_length -
length of the new fragment. INFORMAL none. OUTPUTS: FORMAL
LABEL_FRAGMENT_TYPE *target_store - The target store will be
updated with the new fragments. INFORMAL none
*************************************************************-
**************** / void StoreRightFragment( LABEL_FRAGMENT_TYPE
*target_store, unsigned char *new_frag,
unsigned char new_frag_len ) { StoreCharsFromNewFrag(
&(target_store->chars[FRAG_BUFFER_SIZE - new_frag_len]),
&(target_store->char_scans[FRAG_BUFFER_SIZE -
new_frag_len]), new_frag, new_frag_len ); target_store->length =
new_frag_len; }
/********************************************************-
******************** * FUNCTION: StripUndecodableEndChars AUTHOR:
Jon Brandt, 8/24/98 REFERENCE: Product SDD DESCRIPTION: This
function strips the undecodable characters from the end of the new
fragment. If the fragment is a left fragment, the function looks on
the right side of the fragment. If the fragment is a right
fragment, the function looks on the left side of the fragment.
INPUTS: FORMAL unsigned char fragment_type - type of label
fragment. LEFT_SIDE_FRAGMENT - Only part of the left side of label
is ready. RIGHT_SIDE_FRAGMENT - Only part of the right side of
label is ready. INFORMAL NEW_FRAG_CHARS - IntermediateLabelBuffer -
global variable pointing to the start location of the buffer that
has the new fragment. NEW_FRAG_LEN - IntermediateLength - global
variable of the length of the new fragment. OUTPUTS: FORMAL none
INFORMAL NEW_FRAG_CHARS - IntermediateLabelBuffer - characters may
be modified when the undecodable characters are stripped.
NEW_FRAG_LEN - IntermediateLength - length may be modified when the
undecodable characters are stripped.
*************************************************************************-
**** / void StripUndecodableEndChars( unsigned char fragment_type )
{ signed short char_num; unsigned char num_undec_chars;
num_undec_chars = 0; if ((fragment_type & LEFT_SIDE_FRAGMENT)
!= 0) { for ( char_num = NEW_FRAG_LEN - 1; char_num >= 0;
char_num-- ) { if ( NEW_FRAG_CHARS[char_num] == UNDECODABLE_CHAR )
{ num_undec_chars++; } else { break; } } NEW_FRAG_LEN -=
num_undec_chars; } else if ((fragment_type &
RIGHT_SIDE_FRAGMENT) != 0) { for ( char_num = 0; char_num <
NEW_FRAG_LEN; char_num++ ) { if ( NEW_FRAG_CHARS[char_num] ==
UNDECODABLE_CHAR ) { num_undec_chars++; } else { break; } } if (
num_undec_chars > 0 ) { NEW_FRAG_LEN -= num_undec_chars;
memmove( NEW_FRAG_CHARS, &(NEW_FRAG_CHARS[num_undec_chars]),
NEW_FRAG_LEN ); } } }
/**********************************************************-
****************** * FUNCTION: StitchLabelFragmentsOneFixedL- ength
AUTHOR: Jon Brandt, 8/25/98 REFERENCE: Product SDD DESCRIPTION:
This function attempts to stitch the left and right fragments for a
symbology with one fixed length. If it is successful, a TRUE is
returned and the complete label is stored in the left fragment
storage area. The scans for the new label is a combination of both
fragments. If the stitch fails, a FALSE is returned. The following
rules are used for fixed length stitching with one length: 1) When
the left and right fragments are stitched, at least 2 characters
have to match and overlap. 2) Overlapping characters can be the
same character. INPUTS: FORMAL none INFORMAL
current_symbology_object_ptr - global store that keeps a pointer to
the current object. SYMB_RECONSTRUCT_INFO_TYPE reconstr_info;
stitch_len1 - This label length will be used to attempt a stitch of
the fragments. OUTPUTS: FORMAL BOOLEAN success - TRUE is stitching
worked. FALSE otherwise. INFORMAL RECONSTRUCT_INFO_TYPE
*reconstr_info; Some of the reconstruction information for this
symbology may be modified if stitching is a success.
******************************************-
*********************************** / BOOLEAN
StitchLabelFragmentsOneFixedLength ( void ) { unsigned char
stitch_len; /* Check to see if stitching is currently enabled */ if
( (ActiveDecodingAlgs & DM_FIXED_LENGTH_STITCHING_M- ASK) != 0
) { /* Get the fixed length */ stitch_len =
current_symbology_object_ptr->reconstr_info- >stitch_len1; /*
Evaluate if the stitch meets requirements. */ if (
EvaluateStitchingMatchAllowDupChars( stitch_len ) >=
FIXED_LENGTH_STITCHING_OVERLAP ) { /* It meets requirements so
stitch the fragments. */ StitchFragmentsAtLength( stitch_len );
return TRUE; } } /* Requirements for stitching are not met so
return FALSE. */ return FALSE; }
/*************************************************-
*************************** * FUNCTION:
StitchLabelFragmentsTwoFixedLengths AUTHOR: Jon Brandt, 8/25/98
REFERENCE: Product SDD DESCRIPTION: This function attempts to
stitch the left and right fragments at 2 lengths of a fixed length
symbology. If it is successful, a TRUE is returned and the complete
label is stored in the left fragment storage area. The scans for
the new label is a combination of both fragments. If the stitch
fails, a FALSE is returned. The following rules are used for a two
fixed length stitching: 1) When the left and right fragments are
stitched, at least 2 characters have to match and overlap. 2)
Overlapping characters cannot all be the same character. INPUTS:
FORMAL none INFORMAL current_symbology_object_ptr - global store
that keeps a pointer to the current object.
SYMB_RECONSTRUCT_INFO_TYPE *reconstr_info; stitch_len1 - This label
length will be used to attempt a stitch of the fragments. stitch
len2 - This label length will be used to attempt a stitch of the
fragments. OUTPUTS: FORMAL BOOLEAN success - TRUE is stitching
worked. FALSE otherwise. INFORMAL SYMB_RECONSTRUCT_INFO_T- YPE
*reconstr_info; Some of the reconstruction information for this
symbology may be modified if stitching is a success.
*************************************************************************-
**** / BOOLEAN StitchLabelFragmentsTwoFixedLengths ( void ) {
unsigned char max_num_matching_chars; unsigned char success_len;
unsigned char matching_chars; unsigned char stitch_len; /* Check to
see if stitching is currently enabled */ if ( (ActiveDecodingAlgs
& DM_FIXED_LENGTH_STITCHING_MASK) != 0 ) {
max_num_matching_chars = 0; success_len = 0; /* It's a good idea to
first attempt a stitch for length #1 because ** it is the longer
length of the two lengths and it will have ** priority over the
shorter length if there are the same number ** of matching
characters. */ /* Get fixed length 1 */ stitch_len =
current_symbology_object_ptr->reconstr_info- >stitch_len1; /*
Evaluate if the stitch for length1 meets requirements. */
matching_chars = EvaluateStitchingMatchRejectDup- Chars( stitch_len
); if ( matching_chars > 0 ) { max_num_matching_chars =
matching_chars; success_len = stitch_len; } /* Get fixed length 2
*/ stitch_len = current_symbology_object_ptr->reconstr_info-
>stitch_len2; /* Evaluate if the stitch for length2 meets
requirements. */ matching_chars =
EvaluateStitchingMatchRejectDupChars( stitch_len ); if (
matching_chars > max_num_matching_chars ) {
max_num_matching_chars = matching_chars; success_len = stitch_len;
} /* If the number of matching characters meet requirements **
stitch the two fragments. */ if ( max_num_matching_chars >=
FIXED_LENGTH_STITCHING_OVERLAP ) { /* It meets requirements so
stitch the fragments. */ StitchFragmentsAtLength( success_len );
return TRUE; } } /* Requirements for stitching are not met so
return FALSE. */ return FALSE; } /*******************************-
********************************************* * FUNCTION:
StitchLabelFragmentsVariableLength AUTHOR: Jon Brandt, 8/10/98
REFERENCE: Product SDD DESCRIPTION: This function attempts to
stitch the left and right fragments at all lengths of the
configured range for this symbology. If it is successful, a TRUE is
returned and the complete label is stored in the left fragment
storage area. The scans for the new label is a combination of both
fragments. If the stitch fails, a FALSE is returned. The following
rules are used for variable length stitching: 1) When the left and
right fragments are stitched, at least 4 characters have to match
and overlap. 2) Overlapping characters cannot all be the same
character. INPUTS: FORMAL none INFORMAL
current_symbology_object_ptr - global store that keeps a pointer to
the current object. SYMB_RECONSTRUCT_INFO_TYPE *reconstr_info;
stitch_len1 - This is the minimum label length of the acceptable
range for this symbology. stitch_len2 - This is the maximum label
length of the acceptable range for this symbology. OUTPUTS: FORMAL
BOOLEAN success - TRUE is stitching worked. FALSE otherwise.
INFORMAL RECONSTRUCT_INFO_TYPE *reconstr_info; Some of the
reconstruction information for this symbology may be modified if
stitching is a success.
*********************************************************-
******************** / BOOLEAN StitchLabelFragmentsVariableLength(
void ) { SYMB_RECONSTRUCT_INFO_TYPE *corr_info; unsigned char
max_num_matching_chars; unsigned char success_len; unsigned char
matching_chars; signed char stitch_len; signed char min_stitch_len;
signed char frag_stitch_extreems; /* Check to see if stitching is
currently enabled */ if ( (ActiveDecodingAigs &
DM_VARIABLE_LENGTH_STITCHING_MASK) != 0 ) { max_num_matching_chars
= 0; success_len = 0; /* Get pointer to character correlation
information for this ** symbology. */ corr_info =
current_symbology_object_ptr-&g- t;reconstr_info; /* It's a
good idea to first attempt a stitch of the longer lengths **
because they will have priority over the shorter length if there **
are the same number of matching characters. */ /* Get configured
maximum length for the starting length. */ stitch_len =
current_symbology_object_ptr->- ;reconstr_info-
>stitch_len2; /* Determine the fragment maximum stitching length
using the available ** fragments. The fragment maximum stitching
length is the length ** with the minimum overlap. */
frag_stitch_extreems = (signed char) ((signed char) corr_info-
>left_frag.length + (signed char)corr_info->right_frag.length
- (signed char) VARIABLE_LENGTH_STITCHING_OVERLAP); /* Now
determine which maximum stitching length to use. Use the ** minimum
of the configured and fragment maximum stitching lengths. */ if (
frag_stitch_extreems < stitch_len ) { stitch_len =
frag_stitch_extreems; } /* Get configured minimum stitching length.
*/ min_stitch_len = current_symbology_object_pt-
r->reconstr_info- >stitch_len1; /* Determine the fragment
minimum stitching length using the available ** fragments. The
fragment minimum stitching length is the size of the ** biggest
fragment. */ if ( corr_info->left_frag.length >
corr_info->right_frag.length ) { frag_stitch_extreems =
corr_info->left_frag.length; } else { frag_stitch_extreems =
corr_info->right_frag.length; } /* Now determine which minimum
stitching length to use. Use the ** maximum of the configured and
fragment minimum stitching lengths. */ if ( frag_stitch_extreems
> min_stitch_len ) { min_stitch_len = frag_stitch_extreems; } /*
Evaluate if the stitch for each length to see if it meets
requirements. */ for ( ;stitch_len >= min_stitch_len;
stitch_len-- ) { matching_chars =
EvaluateStitchingMatchRejectDupChars( (unsigned char) stitch_len );
/* If we have a better match, store the length */ if (
matching_chars > max_num_matching_chars ) {
max_num_matching_chars = matching_chars; success_len = stitch_len;
} } /* If the number of matching characters meet requirements **
stitch the two fragments. */ if ( max_num_matching_chars >=
VARIABLE_LENGTH_STITCHING_OVERLAP ) { /* It meets requirements so
stitch the fragments. */ StitchFragmentsAtLength( success_len );
return TRUE; } } /* Requirements for stitching are not met so
return FALSE. */ return FALSE; }
/*************************************************-
*************************** * FUNCTION: StitchLabelFragmentsEAN13
AUTHOR: Jon Brandt, 8/25/98 REFERENCE: Product SDD DESCRIPTION:
This function attempts to stitch the left and right fragments for
EAN13. It also verifies that the guards are in the correct position
to make sure the correct pieces were used to make this label. If it
is successful, a TRUE is returned and the complete label is stored
in the left fragment storage area. The scans for the new label is a
combination of both fragments. If the stitch fails, a FALSE is
returned. The following rules are used for EAN13. 1) When the left
and right fragments are stitched, at least 2 characters have to
match and overlap. 2) Overlapping characters can be the same
character. 3) There has to be left, middle, and right guard present
in the result. INPUTS: FORMAL none INFORMAL
current_symbology_object_ptr - global store that keeps a pointer to
the current object. SYMB_RECONSTRUCT_INFO_TYPE structure for the
current symbology: unsigned char *left_frag.chars - Pointer to the
characters of the left fragment. OUTPUTS: FORMAL BOOLEAN success -
TRUE is stitching worked. FALSE otherwise. INFORMAL
SYMB_RECONSTRUCT_INFO_TYPE *reconstr_info; Some of the
reconstruction information for this symbology may be modified if
stitching is a success. ******************************************-
*********************************** / /* Set up defines for
locations of guards */ #define EAN13_LEFT_GUARD_POSITION (0)
#define EAN13_CENTER_GUARD_POSITION (7) #define
EAN13_RIGHT_GUARD_POSITION (14) BOOLEAN StitchLabelFragmentsEAN13(
void ) { unsigned char *label_chars; SYMB_RECONSTRUCT_INFO_TYPE
*corr_info; /* Check to see if stitching is currently enabled */ if
( (ActiveDecodingAlgs & DM_FIXED_LENGTH_STITCHING_MASK) != 0 )
{ /* Evaluate if the stitch meets requirements. */ if (
EvaluateStitchingMatchAllowDupChars( EAN13_STITCHING_LEN ) >=
FIXED_LENGTH_STITCHING_OVERLAP ) { /* It meets requirements so
stitch the fragments. */ StitchFragmentsAtLength(
EAN13_STITCHING_LEN ); /* Get pointer to characters in left
fragment buffer. */ corr_info = current_symbology_object_ptr->-
reconstr_info; label_chars = corr_info->left_frag.chars; /* Now
check to make sure the correct guards are ** in the correct places.
*/ if ( (label_chars[EAN13_LEFT_GUARD_POS- ITION] ==
UPC_RIGHT_LEFT_GUARD) && (label_chars[EAN13_CENTE-
R_GUARD_POSITION] == UPC_CENTER_GUARD) &&
(label_chars[EAN13_RIGHT_GUARD_POSITION] == UPC_RIGHT_LEFT_GUARD) {
/* Everything looks good so return a TRUE. */ return TRUE; } else {
/* Label was stitched with bad data. Throw out the data. */
corr_info->left_frag.length = 0; corr_info->right_frag.leng-
th = 0; } } } /* Requirements for stitching are not met so return
FALSE. */ return FALSE; }
/*****************************************************************-
*********** * FUNCTION: StitchLabelFragmentsEAN8 AUTHOR: Jon
Brandt, 8/25/98 REFERENCE: Product SDD DESCRIPTION: This function
attempts to stitch the left and right fragments for EAN8. It also
verifies that the guards are in the correct position to make sure
the correct pieces were used to make this label. If it is
successful, a TRUE is returned and the complete label is stored in
the left fragment storage area. The scans for the new label is a
combination of both fragments. If the stitch fails, a FALSE is
returned. The following rules are used for EAN8. 1) When the left
and right fragments are stitched, at least 2 characters have to
match and overlap. 2) Overlapping characters can be the same
character. 3) There has to be left, middle, and right guard present
in the result. INPUTS: FORMAL none INFORMAL
current_symbology_object_ptr - global store that keeps a pointer to
the current object. SYMB_RECONSTRUCT_INFO_TYPE structure for the
current symbology: unsigned char *left_frag.chars - Pointer to the
characters of the left fragment. OUTPUTS: FORMAL BOOLEAN success -
TRUE is stitching worked. FALSE otherwise. INFORMAL
SYMB_RECONSTRUCT_INFO_TYPE *reconstr_info; Some of the
reconstruction information for this symbology may be modified if
stitching is a success.
*************************************************************************-
**** / /* Set up defines for locations of guards */ #define
EAN8_LEFT_GUARD_POSITION (0) #define EAN8_CENTER_GUARD_POSITION (5)
#define EAN8_RIGHT_GUARD_POSITION (10) BOOLEAN
StitchLabelFragmentsEAN8( void ) { unsigned char *label_chars;
SYMB_RECONSTRUCT_INFO_TYPE *corr_info; /* Check to see if stitching
is currently enabled */ if ( (ActiveDecodingAigs &
DM_FIXED_LENGTH_STITCHING_MASK) != 0 ) { /* Evaluate if the stitch
meets requirements. */ if ( EvaluateStitchingMatchAllowDupChars(
EAN8_STITCHING_LEN ) >= FIXED_LENGTH_STITCHING_OVERLAP ) { /* It
meets requirements so stitch the fragments. */
StitchFragmentsAtLength( EAN8_STITCHING_LEN ); /* Get pointer to
characters in left fragment buffer. */ corr_info =
current_symbology_object_ptr->- reconstr_info; label_chars =
corr_info->left_frag.chars; /* Now check to make sure the
correct guards are ** in the correct places. if (
(label_chars[EAN8_LEFT_GUARD_POSITION] == UPC_RIGHT_LEFT_GUARD)
&& (label_chars[EAN8_CENTER_GUARD_POSIT- ION] ==
UPC_CENTER_GUARD) && (label_chars[EAN8_RIGHT_GUARD_-
POSITION] == UPC_RIGHT_LEFT_GUARD) ) { /* Everything looks good so
return a TRUE. */ return TRUE; } else { /* Label was stitched with
bad data. Throw out the data. */ corr_info->left_frag.length =
0; corr_info->right_frag.length = 0; } } } /* Requirements for
stitching are not met so return FALSE. */ return FALSE; }
/******************************************-
********************************** * FUNCTION:
StitchLabelFragmentsUPCE AUTHOR: Jon Brandt, 8/25/98 REFERENCE:
Product SDD DESCRIPTION: This function attempts to stitch the left
and right fragments for UPCE. It also verifies that the guards are
in the correct position to make sure the correct pieces were used
to make this label. If it is successful, a TRUE is returned and the
complete label is stored in the left fragment storage area. The
scans for the new label is a combination of both fragments. If the
stitch fails, a FALSE is returned. The following rules are used for
UPCE. 1) When the left and right fragments are stitched, at least 2
characters have to match and overlap. 2) Overlapping characters can
be the same character. 3) There has to be left and right upce guard
present in the result. INPUTS: FORMAL none INFORMAL
current_symbology_object_ptr - global store that keeps a pointer to
the current oblect. SYMB_RECONSTRUCT_INFO_TYPE structure for the
current symbology: unsigned char *left_frag.chars - Pointer to the
characters of the left fragment. OUTPUTS: FORMAL BOOLEAN success -
TRUE is stitching worked. FALSE otherwise. INFORMAL
SYMB_RECONSTRUCT_INFO_TYPE *reconstr_info; Some of the
reconstruction information for this symbology may be modified if
stitching is a success. ******************************************-
*********************************** / /* Set up defines for
locations of guards */ #define UPCE_LEFT_GUARD_POSITION (0) #define
UPCE_RIGHT_GUARD_POSITION (7) BOOLEAN StitchLabelFragmentsUPCE(
void ) { unsigned char *label_chars; SYMB_RECONSTRUCT_INFO_TYPE
*corr_info; /* Check to see if stitching is currently enabled */ if
( (ActiveDecodingAigs & DM_FIXED_LENGTH_STITCHING_MASK) != 0 )
{ /* Evaluate if the stitch meets requirements. */ if (
EvaluateStitchingMatchAllowDupChars( UPCE_STITCHING_LEN ) >=
FIXED_LENGTH_STITCHING_OVERLAP ) { /* It meets requirements so
stitch the fragments. */ StitchFragmentsAtLength(
UPCE_STITCHING_LEN ); /* Get pointer to characters in left fragment
buffer. */ corr_info = current_symbology_object_ptr->-
reconstr_info; label_chars = corr_info->left_frag.chars; /* Now
check to make sure the correct guards are ** in the correct places.
*/ if ( (label_chars[UPCE_LEFT_GUARD_POSI- TION] ==
UPC_RIGHT_LEFT_GUARD) && (label_chars[UPCE_RIGHT_G-
UARD_POSITION] == UPCE_RIGHT_GUARD) ) { /* Everything looks good so
return a TRUE. */ return TRUE; } else { /* Label was stitched with
bad data. Throw out the data. */ corr_info->left_frag.length =
0; corr_info->right_frag.length = 0; } } } /* Requirements for
stitching are not met so return FALSE. */ return FALSE; }
/******************************************-
********************************** * FUNCTION:
EvaluateStitchingMatchAllowDupChars AUTHOR: Jon Brandt, 8/7/98
REFERENCE: Product SDD DESCRIPTION: This function evaluates the
stitch of the left and right fragments at the specified length.
This function allows all the matching characters in the overlap
region to have the same value. It returns the number of matched
characters if the stitch meets the following criteria: 1. Either
fragment cannot be greater than the stitching length. 2. At least
3/4 of the characters in the overlap region, that have decoded
characters, are identical in both fragments. 3. Each character that
is identical in the overlap region must also have
Min_Char_Corr_Scans scans. If the criteria is not met, a 0 is
returned to indicate a stitching failure. INPUTS: FORMAL unsigned
char stitch_len - the stitching length to evaluate. INFORMAL
current_symbology_object_ptr - global store that keeps a pointer to
the current object. SYMB_RECONSTRUCT_INFO_TY- PE structure for the
current symbology: unsigned char *left_frag.chars - Pointer to the
characters of the left fragment. unsigned char
*left_frag.char_scans - Pointer to the storage area for the number
of scans for the left fragment. unsigned char left_frag.length -
length of the left fragment. unsigned char *right_frag.chars -
Pointer to the characters of the right fragment. unsigned char
*rightfrag.char_scans - Pointer to the storage area for the number
of scans for the right fragment. unsigned char right_frag.length -
length of the right fragment. character_correlation_min_read -
Minimum number of times each character has to be seen in the same
position before the correlated label is accepted. OUTPUTS: FORMAL
unsigned char matching_chars - number of characters that match in
the overlapping region. A 0 indicates one of the stitching
requirements were not met. INFORMAL none
*****************************************************-
************************ / unsigned char
EvaluateStitchingMatchAllowDupChars( unsigned char stitch_len {
SYMB_RECONSTRUCT_INFO_TYPE *corr_info; unsigned char
*left_frag_chars; unsigned char *left_frag_char_scans; unsigned
char *right_frag_chars; unsigned char *right_frag_char_scans;
unsigned char char_num; signed char overlap_length; unsigned char
adjusted_overlap_len; unsigned char delta_overlap_length; unsigned
char num_matching_chars; unsigned char num_decoded_chars; /*
Initialize to no matching or decoded characters */
num_matching_chars = 0; num_decoded_chars = 0; /* Get pointer to
character correlation information for this ** symbology. */
corr_info = current_symbology_object_ptr-&g- t;reconstr_info;
/* Determine amount of overlap for the current fragments. */
overlap_length = (signed char) ((signed
char)corr_info->left_frag.length + (signed
char)corr_info->right_frag.length - (signed char)stitch_len); /*
Make sure there is overlap. Also verify that neither of the **
fragments are longer than the stitching length. */ if (
(overlap_length > 0) && ! (
corr_info->left_frag.leng- th > stitch_len ) && ! (
corr_info->right_frag.length > stitch_len ) ) { /* Set up
pointers to character and scan buffers. ** The left buffer needs to
start overlap length from the ** right end of the fragment. The
right buffer needs to ** start at the left end of the fragment
considering that ** the right fragment is stored at the high end of
the buffer. */ left_frag_chars =
&(corr_info->left_frag.chars [corr_info->left_frag.length
- (unsigned char)overlap_length]); left_frag_char_scans =
&(corr_info->left frag.char_scans
[corr_info->left_frag.length - (unsigned char)overlap_length]);
right_frag_chars = &(corr_info->right_frag.chars
[FRAG_BUFFER_SIZE - corr_info->right_frag.length]);
right_frag_char_scans = &(corr_info->right_frag.char_scans
[FRAG_BUFFER_SIZE - corr_info->right_frag.length]); /* Strip end
characters from left fragment if they don't match ** right
fragment. Then adjust overlap length. Only allow 1/2 of ** the
fragment to be stripped. */ overlap_length = (signed
char)DetermineLeftFragMergeLen left_frag_chars, right_frag_chars,
(unsigned char)overlap_length, (unsigned char) (overlap_length/2)
); /* Strip end characters from right fragment if they don't match
** left fragment. Then adjust fragment pointers. Only allow 1/2 **
of the fragment to be stripped. */ adjusted_overlap_len =
DetermineRightFragMergeLen( right_frag_chars, left_frag_chars,
(unsigned char) overlap_length, (unsigned char) overlap_length,
(unsigned char) (overlap_length/2) ); delta_overlap_length =
(unsigned char) ((unsigned char)overlap_length -
adjusted_overlap_len); left_frag_chars += delta_overlap_length;
left_frag_char_scans += delta_overlap_length; right_frag_chars +=
delta_overlap_length; right_frag_char_scans +=
delta_overlap_length; overlap_length = (signed
char)adjusted_overlap_len; /* Go through the overlap region and
determine how many ** characters match and have enough combined
scans. */ for (char_num = 0; char_num < (unsigned char)
overlap_length; char_num++) { /* Find overlap position where both
characters are decoded. */ if ( ( *left_frag_chars !=
UNTDECODABLE_CHAR ) && ( *right_frag_chars !=
UNDECODABLE_CHAR ) ) { /* Find characters that match and have
enough combined ** scans. Check that the sum of scans >=
min_scans * 2 */ if ( (*left_frag_chars == *right_frag_chars)
&& (*left_frag_char_scans >=
DM_Config.character_correlation_min_read) &&
(*right_frag_char_scans >= DM_Config.character_correlation_min_-
read) ) { num_matching_chars++; } /* Count number of decoded
character pairs. */ num_decoded_chars++; } left_frag_chars++;
left_frag_char_scans++; right_frag_chars++;
right_frag_char_scans++; } /* Make sure that 75% (3/4) of decoded
characters match */ num_decoded_chars -= (num_decoded_chars/4); if
( num_matching_chars < num_decoded_chars ) { num_matching_chars
= 0; } } return num_matching_chars; }
/************************************-
**************************************** * FUNCTION:
EvaluateStitchingMatchRejectDupChars AUTHOR: Jon Brandt, 8/7/98
REFERENCE: Product SDD DESCRIPTION: This function evaluates the
stitch of the left and right fragments at the specified length.
This function requires that there be at least three different
characters of the matching characters in the overlapping region. It
returns the number of matched characters if the stitch meets the
following criteria: 1. Either fragment cannot be greater than the
stitching length. 2. At least 3/4 of the characters in the overlap
region, that have decoded characters, are identical in both
fragments. 3. Each character that is identical in the overlap
region must also have Min_Char_Corr_Scans scans in each fragment.
4. There must be at least 3 different matching characters in the
overlapping region or the stitch is rejected. If the criteria is
not met, a 0 is returned to indicate a stitching failure. INPUTS:
FORMAL unsigned char stitch_len - the stitching length to evaluate.
INFORMAL current_symbology_object_ptr - global store that keeps a
pointer to the current object. SYMB_RECONSTRUCT_INFO_TY- PE
structure for the current symbology: unsigned char *left_frag.chars
- Pointer to the characters of the left fragment. unsigned char
*left_frag.char_scans - Pointer to the storage area for the number
of scans for the left fragment. unsigned char left_frag.length -
length of the left fragment. unsigned char *right_frag.chars -
Pointer to the characters of the right fragment. unsigned char
*rightfrag.char_scans - Pointer to the storage area for the number
of scans for the right fragment. unsigned char right_frag.length -
length of the right fragment. character_correlation_min_read -
Minimum number of times each character has to be seen in the same
position before the correlated label is accepted. OUTPUTS: FORMAL
unsigned char matching_chars - number of characters that match in
the overlapping region. A 0 indicates one of the stitching
requirements were not met. INFORMAL none
*****************************************************-
************************ / unsigned char
EvaluateStitchingMatchRejectDupChars( unsigned char stitch_len {
SYMB_RECONSTRUCT_INFO_TYPE *corr_info; unsigned char
*left_frag_chars; unsigned char *left_frag_char_scans; unsigned
char *right_frag_chars; unsigned char *right_frag_char_scans;
unsigned char char_num; signed char overlap_length; unsigned char
adjusted_overlap_len; unsigned char delta_overlap_length; unsigned
char num_matching_chars; unsigned char num_decoded_chars; unsigned
char dup_char1; unsigned char dup_char2; unsigned char
num_different_chars; /* Initialize to no matching or decoded
characters */ num_matching_chars = 0; num_decoded_chars = 0;
num_different_chars = 0; /* Get pointer to character correlation
information for this ** symbology. */ corr_info =
current_symbology_object_ptr-&g- t;reconstr_info; /* Determine
amount of overlap for the current fragments. */ overlap_length =
(signed char) ((signed char)
corr_info->left_frag.length + (signed char)corr_info->right-
_frag.length - (signed char)stitch_len); /* Make sure there is
overlap. Also verify that neither of the ** fragments are longer
than the stitching length. */ if ( (overlap_length > 0)
&& ! ( corr_info->left_frag.length > stitch_len )
&& ! ( corr_info->right_frag.length > stitch_len ) )
{ /* Set up pointers to character and scan buffers. ** The left
buffer needs to start overlap_length from the ** right end of the
fragment. The right buffer needs to ** start at the left end of the
fragment considering that ** the right fragment is stored at the
high end of the buffer. */ left_frag_chars =
&(corr_info->left_frag.chars [corr_info->left_frag.length
- (unsigned char)overlap_length]); left_frag_char_scans =
&(corr_info->left_frag.char_scans
[corr_info->left_frag.length - (unsigned char)overlap_length]);
right_frag_chars = &(corr_info->right_frag.chars
[FRAG_BUFFER_SIZE - corr_info->right_frag.length]);
right_frag_char_scans = &(corr_info->right_frag.char_scans
[FRAG_BUFFER_SIZE - corr_info->right_frag.length]); /* Strip end
characters from left fragment if they don't match ** right
fragment. Then adjust overlap length. Since we are ** rejecting
duplicate characters, we will also restrict the ** number of
stripped characters to 1. */ overlap_length = (signed
char)DetermineLeftFragMergeLen( left_frag_chars, right_frag_chars,
(unsigned char)overlap_length, 1 ); /* Strip end characters from
right fragment if they don't match ** left fragment. Then adjust
fragment pointers. Since we are ** rejecting duplicate characters,
we will also restrict the ** number of stripped characters to 1. */
adjusted_overlap_len = DetermineRightFragMergeLen(
right_frag_chars, left_frag_chars, (unsigned char)overlap_length,
(unsigned char) overlap_length, 1 ); delta_overlap_length =
(unsigned char) ((unsigned char)overlap_length -
adjusted_overlap_len); left_frag_chars += delta_overlap_length;
left_frag_char_scans += delta_overlap_length; right_frag_chars +=
delta_overlap_length; right_frag_char_scans +=
delta_overlap_length; overlap_length = (signed char)
adjusted_overlap_len; /* Go through the overlap region and keep
track of the number ** of different characters, the number of
matching pairs, ** and the number of decoded pairs. */ for
(char_num = 0; char_num < (unsigned char)overlap_length;
char_num++) { /* Find overlap position where both characters are
decoded. */ if ( ( *left_frag_chars != UNDECODABLE_CHAR )
&& ( *right_frag_chars != UNDECODABLE_CHAR ) ) +TL,7{ /*
Find characters that match and have enough ** scans. Check that the
scans >= min_scans */ if ( (*left_frag_chars ==
*right_frag_chars) && (*left_frag_char_scans >=
DM_Config.character_correlation min_read) &&
(*right_frag_char_scans >= DM_Config.character_correlation_min_-
read) ) { /* Check if we still need to check for differing
characters. ** We only care if there is less than 3 different
characters. */ if ( num_different_chars < 3 ) { /* If we don't
have any different characters, save this one. */ if (
num_different_chars == 0 ) { num_different_chars = 1; dup_char1 =
*left_frag_chars; } /* If we've only seen one character value, **
check if the new character is different */ else if (
num_different_chars == 1 ) { if ( dup_char1 != *left_frag_chars ) {
/* The new character is different so save it */ num_different_chars
= 2; dup_char2 = *left_frag_chars; } } /* If we've only seen two
character values, ** check if the new character is different **
from the 2 stored ones. */ else if ( num_different_chars == 2 ) {
if ( (dup_char1 != *left_frag_chars) && (dup_char2 !=
*left_frag_chars) ) { /* The new character is different so
increment counter. */ num_different_chars = 3; } } }
num_matching_chars++; } /* Count number of decoded character pairs.
*/ num_decoded_chars++; } /* update pointers to next position */
left_frag_chars++; left_frag_char_scans++; right_frag_chars++;
right_frag_char_scans++; } /* Make sure that 75% (3/4) of decoded
characters match */ /* Subtract 1/4 of decoded characters for
comparison */ num_decoded_chars -= (num_decoded_chars/4); /* If
matching characters < 3/4 decoded characters ** the stitch is
not acceptable. ** If there are less than 3 different characters,
the stitch ** is not acceptable. */ if ( (num_matching_chars <
num_decoded_chars) .vertline. .vertline. (num_different_chars <
3) ) { num_matching_chars = 0; } } return num_matching_chars; }
/************************************-
**************************************** * FUNCTION:
StitchFragmentsAtLength AUTHOR: Jon Brandt, 8/7/98 REFERENCE:
Product SDD DESCRIPTION: This function stitches the two fragments
together at the length specified by the passed parameter. There are
three sections of the final label that need to be considered:
LEFT_NON_OVERLAPPING - The left characters of the label that are
only covered by the left fragment characters. OVERLAPPING - The
characters of the label that are covered by left and right fragment
characters. The end characters of each fragment will not be merged
if they differ from the other fragment. RIGHT_NON_OVERLAPPING - The
right characters of the label that are only covered by the right
fragment characters. INPUTS: FORMAL unsigned char stitch_len - the
stitching length to evaluate. INFORMAL current_symbology_object_ptr
- global store that keeps a pointer to the current object.
SYMB_RECONSTRUCT_INFO_TYPE structure for the current symbology:
unsigned char *left_frag.chars - Pointer to the characters of the
left fragment. unsigned char *left_frag.char_scans - Pointer to the
storage area for the number of scans for the left fragment.
unsigned char left_frag.length - length of the left fragment.
unsigned char *right_frag.chars - Pointer to the characters of the
right fragment. unsigned char *rightfrag.char_scans - Pointer to
the storage area for the number of scans for the right fragment.
unsigned char right_frag.length - length of the right fragment.
OUTPUTS: FORMAL SYMB_RECONSTRUCT_INFO_TYPE structure for the
current symbology: unsigned char *left_frag.chars - Pointer to the
characters of the left fragment. unsigned char *left_frag.char
scans - Pointer to the storage area for the number of scans for the
left fragment. unsigned char left_frag.length - length of the left
fragment. unsigned char *right_frag.chars - Pointer to the
characters of the right fragment. unsigned char
*rightfrag.char_scans - Pointer to the storage area for the number
of scans for the right fragment. unsigned char right_frag.length -
length of the right fragment. INFORMAL none
**************************-
*************************************************** / void
StitchFragmentsAtLength( unsigned char stitch_length ) {
SYMB_RECONSTRUCT_INFO_TYPE *corr_info; unsigned char
*left_frag_chars; unsigned char *left_frag_char_scans; unsigned
char *right_frag_chars; unsigned char *right_frag_char_scans;
unsigned char char_num; unsigned char overlap_length; unsigned char
adjusted_overlap_length; unsigned char copy_length; /* Get pointer
to character correlation information for this ** symbology. */
corr_info = current_symbology_object_ptr->reconstr_info; /*
Determine amount of overlap for the current fragments. */
overlap_length = (unsigned char) (corr_info->left_frag.length +
corr_info->right_frag.length - stitch_length); /* Set up
pointers to character. ** The left buffer needs to start
overlap_length from the ** right end of the fragment. The right
buffer needs to ** start at the left end of the fragment
considering that ** the right fragment is stored at the high end of
the buffer. */ left_frag_chars =
&(corr_info->left_frag.chars [corr_info->left_frag.length
- (unsigned char) overlap_length]); right_frag_chars =
&(corr_info->right_frag.chars [FRAG_BUFFER_SIZE -
corr_info->right_frag.length]); /* Strip end characters from
left fragment if they don't match ** right fragment. Then adjust
overlap length. Allow 1/2 of the ** overlap to be stripped.
adjusted_overlap_length = DetermineLeftFragMergeLen(
left_frag_chars, right_frag_chars, overlap_length, overlap_length/2
); corr_info->left_frag.length -= (overlap_length -
adjusted_overlap_length); overlap_length = adjusted_overlap_length;
/* Strip end characters from right fragment if they don't match **
left fragment. Then adjust fragment pointers. Allow 1/2 of the **
overlap to be stripped. */ adjusted_overlap_length =
DetermineRightFragMergeLen( right_frag_chars, left_frag_chars,
overlap_length, overlap_length, overlap_length/2 );
corr_info->right_frag.leng- th -= (overlap_length -
adjusted_overlap_length); overlap_length = adjusted_overlap_length;
/* Leave all non-overlapping characters on the left side of the **
left fragment alone. No processing necessary. */ /* Merge the
overlapping characters in the middle. */ MergeOverlapOfStoredFrag-
s ( overlap_length ); /* Process the non-overlapping characters
from the right side of the ** right fragment by copying them to the
end of the left fragment. ** This will complete the full length
label. */ left_frag_chars =
&(corr_info->left_frag.chars[corr_info-
>left_frag.length]); left_frag_char_scans =
&(corr_info->left_frag.char_scans[corr_- info-
>left_frag.length]); right_frag_chars =
&(corr_info->right_frag.chars[FRAG_BUFFER_SIZE -
corr_info->right_frag.length + overlap length]);
right_frag_char_scans = &(corr_info-
>right_frag.char_scans[FRA- G_BUFFER_SIZE -
corr_info->right_frag.length + overlap_length]); copy_length =
(unsigned char) (corr_info->right_frag.length - overlap_length);
for ( char_num = 0; char_num < copy_length; char_num++ ) {
*left_frag_chars = *right_frag_chars; *left_frag_char_scans =
*right_frag_char_scans; left_frag_chars++; left_frag char_scans++;
right_frag_chars++; right_frag_char_scans++- ; } /* Set new lengths
for the fragments */ corr_info->left_frag.length =
stitch_length; corr_info->right_frag.length = 0; /* Set flag
that indicates a full length label is stored. */
corr_info->full_length_label = TRUE; }
/**************************************************-
************************** * FUNCTION: ReVerifyCharCorrelation
AUTHOR: Jon Brandt, 7/10/98 REFERENCE: Product SDD DESCRIPTION:
This function sets all scans to 1 for the correlation buffer so
that the characters will have to be verified with more scans.
INPUTS: current_symbology_object_ptr - global store that keeps a
pointer to the current object. RECONSTRUCT_INFO_TYPE structure for
the current symbology: LabelLen--Length of reconstruction label
OUTPUTS: RECONSTRUCT_INFO_TYPE structure for the current symbology:
CharScans - Pointer to a buffer of the length of IntermediateLabel
TotalCharScans - Sum of all character scans
**********************************************************************-
******* / void ReVerifyCharCorrelation( void ) { unsigned char
*corr_scans; unsigned char char_num; unsigned char lbl_len;
corr_scans = current_symbology_object_- ptr->reconstr_info-
>left_frag.char_scans; lbl_len =
current_symbology_object_ptr->reconstr_info->left_frag.length;
for ( char_num = 0; char_num < lbl_len; char_num++ ) {
*corr_scans = 1; corr_scans++; } } This code is an implementation
of the algorithm to decode characters based upon calculated quality
of detected character elements. This quality measure is calculated
in part from comparison of element widths with target widths and
comparison of edge strength values with expected values.
;*****************************************-
******************************** BUILD_NEXT_CHARACTER: ; begin with
the first element in the character LDAA #0 STAA _ELEMENT_INDEX STX
_CHARACTER_LEADING_EDGE ; Code 39 characters always begin with a
bar, regardless of direction LDAA #80H STAA _BAR_BIT CLR
_EDGE_PAIR_TOTAL CLRW _ELEMENT_DEVIATION_TOTAL LDAA
#UNDECODED_CHARACTER_MARKER STAA _MATCHING_CHARACTER LDD
_NARROW_BAR_TARGET STD _NARROW_BAR_AVERAGE LDD _WIDE_BAR_TARGET STD
_WIDE_BAR_AVERAGE LDD _NARROW_SPACE_TARGET STD
_NARROW_SPACE_AVERAGE LDD _WIDE_SPACE_TARGET STD
_WIDE_SPACE_AVERAGE LDD _WIDE_BAR_TARGET ADDD _WIDE_SPACE_TARGET
ASLD STD _TOTAL_DEVIATION_UPPER_THRESH- OLD BUILD_NEXT_ELEMENT: ;
assume that this element is made of 1 pair of edges LDAA #1 STAA
_EDGE_PAIR_COUNT LDE 0,X AIX #2 SET_ELEMENT_TARGETS: ; load either
the bar or space targets, depending on what we are building LDA
_BAR_BIT BEQ BUILDING_SPACE BUILDING_BAR: LDD _NARROW_BAR_TARGET
STD _NARROW_ELEMENT_TARGET LDD _WIDE_BAR_TARGET STD
_WIDE_ELEMENT_TARGET BRA SET_DEVIATION_THRESHOLD BUILDING_SPACE:
LDD _NARROW_SPACE_TARGET STD _NARROW_ELEMENT_TARGET LDD
_WIDE_SPACE_TARGET STD _WIDE_ELEMENT_TARGET
SET_DEVIATION_THRESHOLD: ; set the deviation threshold for a single
element LDD _WIDE_ELEMENT_TARGET ASRD ASRD STD
_ELEMENT_DEVIATION_THRESHOLD DO_ELEMENT_COMPARISON: ; point to the
location in the edge strength buffer which corresponds ; to this
location in the raw data buffer TXY AIY #-2 LDD
_EDGE_STRENGTH_OFFSET ADY ; calculate the RTV or STV deviation,
depending on if we are ; building a bar or a space LDAA _BAR_BIT
BEQ CALCULATE_RTV_DEVIATION CALCULATE_STV_DEVIATION: LDD 0,Y SUBD
_StvAverageStrength BCC CALCULATE_STRENGTH_DEVIATION NEGD BRA
CALCULATE_STRENGTH_DEVIATION CALCULATE_RTV_DEVIATION: LDD 0,Y SUBD
_RtvAverageStrength BCC CALCULATE_STRENGTH_DEVIA- TION NEGD
CALCULATE_STRENGTH_DEVIATION: SUBD _EDGE_STRENGTH_THRESHOLD BCC
AMPLIFY_STRENGTH_DEVIATION CLRD BRA STORE_ABS_EDGE_STRENGTH
AMPLIFY_STRENGTH_DEVIATIO- N: ASLD ASLD STORE_ABS_EDGE_STRENGTH:
STD _STRENGTH_DEVIATION ; first, see if this is a narrow element
LDAA #NARROW_ELEMENT STAA _ELEMENT_TYPE ; compare the element width
with the narrow element target TED SUBD _NARROW_ELEMENT_TARGET BCC
CHECK_NARROW_POS_DEVIATION NEGD CHECK_NARROW_NEG_DEVIATION: ; the
element width is LESS than the target ; compare the deviation from
target with the allowable deviation CPD
_ELEMENT_DEVIATION_THRESHOLD BLS WITHIN_ELEMENT_TOLERANCE ; if the
deviation is too great, add another pair of edges BRA ADD_EDGES
CHECK_NARROW_POS_DEVIATION: ; the element width is GREATER than the
target ; compare the deviation from target with the allowable
deviation CPD _ELEMENT_DEVIATION_THRESHOLD BLS
WITHIN_ELEMENT_TOLERANCE ; if the deviation is too great, see if it
is a wide element LDAA #WIDE_ELEMENT STAA _ELEMENT_TYPE ; compare
the element width with the wide element target TED SUBD
_WIDE_ELEMENT_TARGET BCC CHECK_WIDE_POS_DEVIATION NEGD
CHECK_WIDE_NEG_DEVIATION: ; the element width is LESS than the
target ; compare the deviation from target with the allowable
deviation CPD _ELEMENT_DEVIATION_THRESHOLD BLS
WITHIN_ELEMENT_TOLERANCE ; if the deviation is too great, add
another pair of edges BRA ADD_EDGES CHECK_WIDE_POS_DEVIATION: ; the
element width is GREATER than the target ; compare the deviation
from target with the allowable deviation, ; if the deviation is too
great, it is an error CPD _ELEMENT_DEVIATION_THRESHOLD BHI
ELEMENT_ERROR WITHIN_ELEMENT_TOLERANCE: ; the deviation of the
element width from the target is within tolerance, ; now see if the
total deviation to this point is within tolerance ADDD
_STRENGTH_DEVIATION STD _ELEMENT_DEVIATION ADDD
_ELEMENT_DEVIATION_TOTAL CPD _TOTAL_DEVIATION_UPPER_THRESHOLD JBCC
ELEMENT_ERROR STD _ELEMENT_DEVIATION_TOTAL STE _ELEMENT_WIDTH STX
_ELEMENT_TRAILING_EDGE ; check if the element pattern being
generated matches a valid pattern JSR FIND_CHARACTER_MATCH JBCC
ELEMENT_VALID ; if the element pattern is not valid, subtract the
deviation back out ; of the total accumulated LDD
_ELEMENT_DEVIATION_TOTAL SUBD _ELEMENT_DEVIATION STD
_ELEMENT_DEVIATION_TOTAL ; if this is already a wide element don't
bother adding more edges, ; that will only make it wider and it
still won't be a valid pattern LDAA _ELEMENT_TYPE CMPA
#WIDE_ELEMENT BEQ ELEMENT_ERROR ADD_EDGES: ; increment the number
of edges in this element, ; if it is less than the maximum allowed,
add another pair of edges into ; the sum and threshold again LDAA
_EDGE_PAIR_COUNT INCA CMPA #EDGE_PAIR_COUNT_MAX BHI ELEMENT_ERROR
STAA _EDGE_PAIR_COUNT ADDE 0,X ADDE 2,X AIX #4 JBR
DO_ELEMENT_COMPARISON ELEMENT_ERROR: ; we got here because of an
error in the element width or pattern match ; if we have backed up
all the way to the first element in the character ; then we are
done LDAA _ELEMENT_INDEX JBEQ SEARCH_COMPLETE ; otherwise, back up
to the previous element in this character DECA STAA _ELEMENT_INDEX
TAB ; retrieve the number of edge pairs in the previous element LDY
#_ELEMENT_EDGE_COUNT_LIST ABY LDAA 0,Y ; if there were less than
the maximum allowable pairs of edges in the ; previous element,
increment the count and continue, otherwise error INCA CMPA
#EDGE_PAIR_COUNT_MAX BHI ELEMENT_ERROR STAA _EDGE_PAIR_COUNT ;
retrieve the element type for this element LDY #_ELEMENT_TYPE_LIST
ABY LDAA 0,Y ANDA #0F0H STAA _BAR_BIT ASLB ; retrieve the trailing
edge of the previous element in the raw data LDY
#_ELEMENT_TRAILING_EDGE_LIST ABY LDX 0,Y ; retrieve the deviation
of the previous element and subtract it from ; the deviation total
LDY #_ELEMENT_DEVIATION_LIST ABY LDE _ELEMENT_DEVIATION_TOTAL SUBE
0,Y STE _ELEMENT_DEVIATION_TOTAL ; retrieve the width of the
previous element, add another pair of edges ; into the sum and
threshold again LDY #_ELEMENT_WIDTH_LIST ABY LDE 0,Y ADDE 0,X ADDE
2,X AIX #4 JBR SET_ELEMENT_TARGETS ELEMENT_VALID: ; we got here
because the element width and pattern match were valid LDAB
_ELEMENT_INDEX ; store the number of edge pairs in this element LDY
#_ELEMENT_EDGE_COUNT_LIS- T ABY LDAA _EDGE_PAIR_COUNT STAA 0,Y ;
add the number of edge pairs in this element into the sum for this
; character ADDA _EDGE_PAIR_TOTAL STAA _EDGE_PAIR_TOTAL ; store the
element type for this element LDY #_ELEMENT_TYPE_LIST ABY LDAA
_ELEMENT_TYPE ORAA _BAR_BIT STAA 0,Y ASLB ; store the trailing edge
of this element in the raw data LDY #_ELEMENT_TRAILING_EDGE_LIST
ABY LDE _ELEMENT_TRAILING_EDGE STE 0,Y ; store the deviation from
target of this element LDY #_ELEMENT_DEVIATION_LIST ABY LDE
_ELEMENT_DEVIATION STE 0,Y ; store the width of this element LDY
#_ELEMENT_WIDTH_LIST ABY LDE _ELEMENT_WIDTH STE 0,Y ; did we just
build a bar or a space element LDAA _BAR_BIT BEQ BUILT_SPACE
BUILT_BAR: ; if we just built a bar, clear the flag so that we will
build ; a space next CLR _BAR_BIT ; save the width of the element
just built in the appropriate ; running average LDAA _ELEMENT_TYPE
CMPA #NARROW_ELEMENT BNE SAVE_WIDE_BAR SAVE_NARROW_BAR: ADDE
_NARROW_BAR_AVERAGE ASRE STE _NARROW_BAR_AVERAGE BRA
INCREMENT_INDEX SAVE_WIDE_BAR: ADDE _WIDE_BAR_AVERAGE ASRE STE
_WIDE_BAR_AVERAGE BRA INCREMENT_INDEX BUILT_SPACE: ; if we just
built a space, set the flag so that we will build ; a bar next LDAA
#80H STAA _BAR_BIT ; save the width of the element just built in
the appropriate ; running average LDAA _ELEMENT_TYPE CMPA
#NARROW_ELEMENT BNE SAVE_WIDE_SPACE SAVE_NARROW_SPACE: ADDE
_NARROW_SPACE_AVERAGE ASRE STE _NARROW_SPACE_AVERAGE BRA
INCREMENT_INDEX SAVE_WIDE_SPACE: ADDE _WIDE_SPACE_AVERAGE ASRE STE
_WIDE_SPACE_AVERAGE INCREMENT_INDEX: ; increment the index count,
if we have not yet built enough elements ; to make a character,
then continue LDAB _ELEMENT_INDEX INCB STAB _ELEMENT_INDEX CMPB
#ELEMENTS_PER_CHARACTER JBCS BUILD_NEXT_ELEMENT ; retrieve the
character from the table which corresponds to the pattern ; which
we have just built LDY #_CHARACTER_TABLE_BRANCH_LIST LDAB
_ELEMENT_INDEX DECB ASLB ABY LDZ 0,Y LDAA 0,Z ; if the number of
edge pairs in this character match the number for a valid ;
character then we are done LDAB _EDGE_PAIR_TOTAL CMPB
#ELEMENTS_PER_CHARACTER JBEQ NEXT_CHARACTER_VALID ; otherwise, we
have done some reconstruction so we have to check for ; ambiguous
character matches ; if this is the first matching character found
for this set of edges then ; just save the character match LDAB
_MATCHING_CHARACTER CMPB #UNDECODED_CHARACTER_MARKER BEQ
SAVE_CHARACTER_MATCH ; otherwise, compare the total deviation for
this match with the lower ; threshold set from a previous match, if
we are lower than the threshold ; then this is a valid character so
save it LDE _ELEMENT_DEVIATION_TOTAL CPE
_TOTAL_DEVIATION_LOWER_THRESHOLD BCS SAVE_CHARACTER_MATCH ;
otherwise, the deviation for this match is too close to the
deviation from ; a previous match so we have an ambiguous character
match ; don't save either character match, just mark it LDAA
#AMBIGUOUS_CHARACTER_MARKER STAA _MATCHING_CHARACTER ; now jump
back up and begin backing up through the tree, looking for ; other
possible character matches JBR ELEMENT_ERROR SAVE_CHARACTER_MATCH:
; we have a valid matching character so save it STAA
_MATCHING_CHARACTER ; save the trailing edge of the last element as
the trailing edge ; of this character LDD _ELEMENT_TRAILING_EDGE
STD _CHARACTER_TRAILING_EDGE ; use the total deviation for this
match to set upper and lower ; thresholds for deviation LDD
_ELEMENT_DEVIATION_TOTAL TDE ASRD ASRD ASRD SDE STE
_TOTAL_DEVIATION_LOWER_THRESHOLD ADE ADE STE
_TOTAL_DEVIATION_UPPER_THRESHOLD ; now jump back up and begin
backing up through the tree, looking for ; other possible character
matches JBR ELEMENT_ERROR SEARCH_COMPLETE: ; we have completed
searching the tree, if we have a matching character ; that is not
UNDECODED or AMBIGUOUS then we are successful LDAA
_MATCHING_CHARACTER CMPA #UNDECODED_CHARACTER_MARKER BEQ
NEXT_CHARACTER_INVALID CMPA #AMBIGUOUS_CHARACTER_MARKER BEQ
NEXT_CHARACTER_INVALID LDX _CHARACTER_LEADING_EDGE CLRE
CALCULATE_CHARACTER_WIDTH- : ADDE 0,X AIX #2 CPX
_CHARACTER_TRAILING_EDGE BCS CALCULATE_CHARACTER_WIDTH STE
_THIS_CHAR_WIDTH NEXT_CHARACTER_VALID: ; update the bar and space
targets with the widths from this character LDE _NARROW_BAR_AVERAGE
STE _NARROW_BAR_TARGET LDE _WIDE_BAR_AVERAGE STE _WIDE_BAR_TARGET
LDE _NARROW_SPACE_AVERAGE STE _NARROW_SPACE_TARGET LDE
_WIDE_SPACE_AVERAGE STE _WIDE_SPACE_TARGET ; clear the CARRY bit to
indicate a valid character match and return ANDP #0FEFFH RTS
NEXT_CHARACTER_INVALID: LDX _CHARACTER_LEADING_EDGE ; set the CARRY
bit to indicate an invalid character match and return ORP #100H RTS
;*******************************************-
************************ FIND_CHARACTER_MATCH: PSHM K,X LDAA
_START_CHARACTER BEQ NOT_LOOKING_FOR_START CLR _START_CHARACTER LDZ
#START_CHARACTER_TABLE BRA BEGIN_ELEMENT_MATCH
NOT_LOOKING_FOR_START: LDAB _ELEMENT_INDEX TBA BNE
LOAD_LAST_ADDRESS LDZ #FORWARD_CHARACTER_TABLE LDAB _FORWARD BEQ
BEGIN_ELEMENT_MATCH LDZ #REVERSE_CHARACTER_TABLE BRA
BEGIN_ELEMENT_MATCH LOAD_LAST_ADDRESS: DECB LDX
#_CHARACTER_TABLE_BRANCH_LIST ASLB ABX LDZ 0,X BEGIN_ELEMENT_MATCH:
TZY LDAB _ELEMENT_TYPE CMPB 0,Z BEQ ELEMENT_MATCH_FOUND BCS
ELEMENT_MATCH_NOT_FOUND ELEMENT_MATCH_LOOP: AIZ #10 CMPB 0,Z BCS
ELEMENT_MATCH_NOT_FOUND BNE ELEMENT_MATCH_LOOP CMPA #0 BEQ
ELEMENT_MATCH_FOUND STZ _TEMP_WORD BRANCH_VERIFY_LOOP: AIY #-1 AIZ
#-1 LDAB 0,Y CMPB 0,Z BNE ELEMENT_MATCH_NOT_FOUND DECA BNE
BRANCH_VERIFY_LOOP LDZ _TEMP_WORD ELEMENT_MATCH_FOUND: AIZ #1 LDX
#_CHARACTER_TABLE_BRANCH_LIST LDAB _ELEMENT_INDEX ASLB ABX STZ 0,X
PULM K,X ; clear the CARRY bit to indicate a match was found and
return ANDP #0FEFFH RTS ELEMENT_MATCH_NOT_FOUND: PULM K,X ; set the
CARRY bit to indicate no match was found and return ORP #100H RTS
;*******************************************************************-
* ; Code 39 bit patterns ; the first three bytes in each table
entry are the locations of the ; wide elements in the character,
the last byte is the check digit ; value of the character
FORWARD_CHARACTER_TABLE: .BYTE 1,1,1,1,1,1,2,2,2,26 .BYTE
1,1,1,1,1,2,2,1,2,16 .BYTE 1,1,1,1,2,1,1,2,2,23 .BYTE
1,1,1,1,2,1,2,2,1,29 .BYTE 1,1,1,1,2,2,1,1,2,13 .BYTE
1,1,1,1,2,2,2,1,1,19 .BYTE 1,1,1,2,1,1,2,1,2,7 .BYTE
1,1,1,2,2,1,1,1,2,4 .BYTE 1,1,1,2,1,2,1,2,1,42 .BYTE
1,1,1,2,2,1,2,1,1,0 .BYTE 1,1,2,1,1,1,1,2,2,21 .BYTE
1,1,2,1,1,1,2,2,1,28 .BYTE 1,1,2,1,1,2,1,1,2,11 .BYTE
1,1,2,1,1,2,2,1,1,18 .BYTE 1,1,2,1,2,1,1,2,1,25 .BYTE
1,1,2,1,2,2,1,1,1,15 .BYTE 1,1,2,2,1,1,1,1,2,2 .BYTE
1,1,2,2,1,1,2,1,1,9 .BYTE 1,1,2,2,2,1,1,1,1,6 .BYTE
1,2,1,1,1,1,2,1,2,36 .BYTE 1,2,1,1,1,2,1,2,1,41 .BYTE
1,2,1,1,2,1,1,1,2,33 .BYTE 1,2,1,1,2,1,2,1,1,0EEH .BYTE
1,2,1,2,1,1,1,2,1,40 .BYTE 1,2,1,2,1,2,1,1,1,39 .BYTE
1,2,2,1,1,1,1,1,2,31 .BYTE 1,2,2,1,1,1,2,1,1,38 .BYTE
1,2,2,1,2,1,1,1,1,35 .BYTE 2,1,1,1,1,1,1,2,2,20 .BYTE
2,1,1,1,1,1,2,2,1,27 .BYTE 2,1,1,1,1,2,1,1,2,10 .BYTE
2,1,1,1,1,2,2,1,1,17 .BYTE 2,1,1,1,2,1,1,2,1,24 .BYTE
2,1,1,1,2,2,1,1,1,14 .BYTE 2,1,1,2,1,1,1,1,2,1 .BYTE
2,1,1,2,1,1,2,1,1,8 .BYTE 2,1,1,2,2,1,1,1,1,5 .BYTE
2,1,2,1,1,1,1,2,1,22 .BYTE 2,1,2,1,1,2,1,1,1,12 .BYTE
2,1,2,2,1,1,1,1,1,3 .BYTE 2,2,1,1,1,1,1,1,2,30 .BYTE
2,2,1,1,1,1,2,1,1,37 .BYTE 2,2,1,1,2,1,1,1,1,34 .BYTE
2,2,2,1,1,1,1,1,1,32 REVERSE_CHARACTER_TABLE: .BYTE
1,1,1,1,1,1,2,2,2,32 .BYTE 1,1,1,1,1,2,2,1,2,3 .BYTE
1,1,1,1,2,1,1,2,2,34 .BYTE 1,1,1,1,2,1,2,2,1,35 .BYTE
1,1,1,1,2,2,1,1,2,5 .BYTE 1,1,1,1,2,2,2,1,1,6 .BYTE
1,1,1,2,1,1,2,1,2,12 .BYTE 1,1,1,2,1,2,1,2,1,39 .BYTE
1,1,1,2,2,1,1,1,2,14 .BYTE 1,1,1,2,2,1,2,1,1,15 .BYTE
1,1,2,1,1,1,1,2,2,37 .BYTE 1,1,2,1,1,1,2,2,1,38 .BYTE
1,1,2,1,1,2,1,1,2,8 .BYTE 1,1,2,1,1,2,2,1,1,9 .BYTE
1,1,2,1,2,1,1,2,1,0EEH .BYTE 1,1,2,1,2,2,1,1,1,0 .BYTE
1,1,2,2,1,1,1,1,2,17 .BYTE 1,1,2,2,1,1,2,1,1,18 .BYTE
1,1,2,2,2,1,1,1,1,19 .BYTE 1,2,1,1,1,1,2,1,2,22 .BYTE
1,2,1,1,1,2,1,2,1,40 .BYTE 1,2,1,1,2,1,1,1,2,24 .BYTE
1,2,1,1,2,1,2,1,1,25 .BYTE 1,2,1,2,1,1,1,2,1,41 .BYTE
1,2,1,2,1,2,1,1,1,42 .BYTE 1,2,2,1,1,1,1,1,2,27 .BYTE
1,2,2,1,1,1,2,1,1,28 .BYTE 1,2,2,1,2,1,1,1,1,29 .BYTE
2,1,1,1,1,1,1,2,2,30 .BYTE 2,1,1,1,1,1,2,2,1,31 .BYTE
2,1,1,1,1,2,1,1,2,1 .BYTE 2,1,1,1,1,2,2,1,1,2 .BYTE
2,1,1,1,2,1,1,2,1,33 .BYTE 2,1,1,1,2,2,1,1,1,4 .BYTE
2,1,1,2,1,1,1,1,2,10 .BYTE 2,1,1,2,1,1,2,1,1,11 .BYTE
2,1,1,2,2,1,1,1,1,13 .BYTE 2,1,2,1,1,1,1,2,1,36 .BYTE
2,1,2,1,1,2,1,1,1,7 .BYTE 2,1,2,2,1,1,1,1,1,16 .BYTE
2,2,1,1,1,1,1,1,2,20 .BYTE 2,2,1,1,1,1,2,1,1,21 .BYTE
2,2,1,1,2,1,1,1,1,23 .BYTE 2,2,2,1,1,1,1,1,1,26 This code is an
implementation of an algorithm to generate a histogram and use the
strength of the edges to filter the data included in the histogram.
/************************************************************************-
**** * FUNCTION: InitLabelElementHistogram AUTHOR: Jon Brandt,
12/13/98 DESCRIPTION: This zeros out all of the number of elements
and the element width sum for each bucket. It also sets the bucket
size to 0. INPUTS: hist_ptr is a pointer to a histogram data
structure. OUTPUTS: hist_ptr data is initialized.
*********************************************-
******************************** / void InitLabelElementHistogram(
LABEL_ELEMENT_HISTOGRAM_DATA_TYPE *hist_ptr ) {
hist_ptr->bucket_size = 0; memset (
&(hist_ptr->number_elements[0]), 0, (NUMBER_OF BUCKETS *
sizeof(hist_ptr->number_elements[0])) ); memset(
&(hist_ptr->width_sum[0]), 0, (NUMBER_OF_BUCKETS *
sizeof(hist_ptr->width_sum 0])) ); } #ifdef
HAS_CAPTURE_EDGE_STRENGTH /***************************************-
************************************* * FUNCTION:
RestartLabelElementHistogram AUTHOR: Jon Brandt, 12/13/98, modified
by R.Turkal DESCRIPTION: This function clears out the histograms
and determines the new bucket size. To find the new bucket size
divide the maximum element size by 8. The bucket size is stored in
each histogram data structure. INPUTS: info_ptr is a pointer to a
label element info data structure. biggest_element in_label -
Stores the biggest element that has been seen in the label.
OUTPUTS: info_ptr - the label histogram data is cleared an
initialized for the new label.
***********************************************************-
****************** / void RestartLabelElementHistogr- am(
LABEL_ELEMENTS_INFO_TYPE *info_ptr) { unsigned short min_value; /*
Initialize histogram for new data */ InitLabelElementHistogram(
&(info_ptr->bar_histogram) ); InitLabelElementHistogram(
&(info_ptr->space_histogram) ); /* To determine the new
bucket size, divide the ** biggest element
by 8. */ min_value = biggest_element_in_label / 8; /* store bucket
size in bar and space histogram. */
info_ptr->bar_histogram.bucket_size = min_value;
info_ptr->space_histogram.bucket_size = min_value; }
/************************************************************************-
**** * FUNCTION: UpdateLabelElementHistogram AUTHOR: Jon Brandt,
12/13/98, modified by R.Turkal DESCRIPTION: This function uses the
information in the label element info structure to add information
to the histogram and decode the histogram. First it adds the label
element information to the bar and space histograms. Then it finds
the peaks in the bar and space histogram and calculates the average
element width for each peak. Then the peaks are decoded to
determine what peaks are the correct ones for binary and
multi-width symbologies. A pointer to the 1st edge strength
measurement for each potential label is stored away for use by the
histogram updating function. A pointer to the edge strength that
corresponds to the 1st bar of a potential label is also stored in
the label information structure for later use by the low level
assembly language decoders. INPUTS: LABEL_ELEMENTS_INFO_TYPE
*info_ptr - pointer to element information for the current
potential label. OUTPUTS: info_ptr bar and space histograms are
updated. info_ptr binary_hist_confidence and
multiwidth_hist_confidence are determined. info_ptr
binary_bar_widths, binary_space_widths, multiwidth_bar_widths, and
multiwidth_space_widths are determined.
******************************************************-
*********************** / void UpdateLabelElementHistogram(
LABEL_ELEMENTS_INFO_TYPE *info_ptr) { unsigned short
new_label_num_elements; HistLblEndPtr = info_ptr->label_end; /*
Update the bar histogram with new elements. ** First set up global
variables for subroutine. */ HistLblStartPtr =
info_ptr->label_start; HistBucketSize =
info_ptr->bar_histogram.bucket_size; HistNumElementsPtr =
info_ptr->bar_histogram.number_elements; HistWidthSumPtr =
info_ptr->bar_histogram.width_sum; /* compute the index from the
top of the capture buffer to the leading_qz pointer */
new_label_num_elements = (short)((cur_capt_buf->StartPointer) -
HistLblStartPtr); now compute the edge strength value pointer by
using the just computed index */ StrengthPtr =
cur_capt_buf->EdgeStrengthBu- fferPointer -
new_label_num_elements; /* save a pointer to the first sty edge
strength for this label */ info_ptr->stv_strength data_start =
StrengthPtr; /* set edgeType = 1 to indicate we're working with stv
strengths (bar elements) */ edgeType = 1; /* init the average
strength pointer */ averageStrength =
&(info_ptr->stv_average_strengt- h);
UpdateaistogramCntsAndSum (); /* Determine the peaks and average
width for each peak ** of the bar histogram. */
HistPeakNumElementsPtr = HistBarPeakNumElements;
HistPeakAveWidthPtr = HistBarPeakAveWidth; FindHistogramPeaks ();
HistBarNumPeaks = HistNumPeaks; /* Update the space histogram with
new elements. ** First set up global variables for subroutine. */
HistLblStartPtr = info_ptr->label_start + 1; HistBucketSize =
info_ptr->space_histogram.bucket_size; HistNumElementsPtr =
info_ptr->space_histogram.number_elements; HistWidthSumPtr =
info_ptr->space_histogram.width_sum; /* compute the edge
strength value pointer */ StrengthPtr =
cur_capt_buf->EdgeStrengthBufferPointer - new_label_num_elements
+ 1; /* set edgeType = 0 to indicate we're working with rtv
strengths (space elements) */ edgeType = 0; /* init the average
strength pointer */ averagestrength =
&(info_ptr->rtv_average_strength); UpdateHistogramCntsAndSum
(); /* Determine the peaks and average width for each peak ** of
the space histogram. */ HistPeakNumElementsPtr =
HistSpacePeakNumElements; HistPeakAveWidthPtr =
HistSpacePeakAveWidth; FindHistogramPeaks (); HistSpaceNumPeaks =
HistNumPeaks; /* Decode the histogram peaks to determine the
probable element ** widths for multi-width and binary symbologies.
** Determine confidence level of widths for multi-width ** and
binary symbologies. */ DecodeHistogramPeaks ( infoptr ); }
/************************************************************************-
**** * FUNCTION: FindRistogramPeaks AUTHOR: Jon Brandt, 12/18/98,
modified by R.Turkal DESCRIPTION: This function searches the label
element histogram for peaks in the number of elements in a bucket.
A peak is defined as a bucket that has more elements than both of
it's neighbors. If there are more than 1 bucket in a row with the
same number of elements, the buckets are summed and then averaged
to produce a peak. When a peak is found, the average element width
is calculated and stored in an array. The number of elements for
the peak is also stored in an array. INPUTS: HistNumElementsPtr =
Histogram of the number of elements in a bucket. HistWidthSumPtr =
Histogram of the width total for all elements of the bucket.
OUTPUTS: HistNumPeaks - The number of peaks will be determined.
HistPeakNumElementsPtr - pointer to an array for the number of
elements in each peak. This will be filled in. HistPeakAveWidthPtr
- pointer to an array for the average width for the peaks. This
will be filled in.
**************************************************************-
*************** / void FindHistogramPeaks (void) { unsigned short
last_bkt_num_el; unsigned short bkt_num_el; unsigned long
bkt_width; unsigned char num_repeat_peaks; unsigned char
peak_index; unsigned char bucket_num; signed char i; BOOLEAN
ascending; last_bkt_num_el = 0; HistNumPeaks = 0; ascending = TRUE;
num_repeat_peaks = 0; /* Go through all the buckets of the
histogram. */ for (bucket_num = 0; bucket_num <
(NUMBER_OF_BUCKETS - 1); bucket_num++) { /* Calculate the 2 bucket
sum of the number of elements. */ bkt_num_el =
HistNumElementsPtr[bucket_num]; /* If the new two bucket sum is
greater than the previous ** we are ascending. */ if ( bkt_num_el
> last_bkt_num_el ) { ascending = TRUE; last_bkt_num el
=bkt_num_el; num_repeat_peaks = 0; } /* If this two bucket sum and
the previous are the same, ** we are on a plateau and need to
record the number of ** repeats. */ else if ( bkt_num_el ==
last_bkt_num_el ) { num_repeat_peaks++; } /* If the new two bucket
sum is less than the previous ** we are descending. */ else if (
bkt_num_el < last_bkt_num_el ) { last_bkt_num_el = bkt_num_el;
/* If we were previously ascending, store the ** peak we just
passed. */ if ( ascending == TRUE ) { /* Determine the middle of
the peak if it ** has a plateau. */ bkt_num_el = 0; bkt_width = 0;
i = num_repeat_peaks; while(i >= 0) { peak_index = (unsigned
char) (bucket_num - 1 - i); bkt_num_el +=
HistNumElementsPtr[peak_index]; bkt_width +=
HistWidthSumPtr[peak_index]; i--; } /* Determine the two bucket sum
of the number of elements ** from the middle of the peak. Then
store it in the ** peak store. */
HistpeakNumElementsPtr[HistNumPeaks] = bkt_num_el; /* Determine the
two bucket sum of the elements width ** sum from the middle of the
peak. Then store it ** in the peak store. */ bkt_width /=
bkt_num_el; HistpeakAveWidthPtr[HistNumPeaks] = (unsigned
short)bkt_width; HistNumPeaks++; } else { /* Already descending so
don't do anything. */ } ascending = FALSE; num_repeat_peaks = 0; }
/* If now descending */ } /* loop through buckets */ /* If the
histogram ending ascending, store the last ** two bucket sum as a
peak. */ if ( (ascending == TRUE) && (last_bkt_num_el >
0) ) { /* Determine the middle of the peak if it ** has a plateau.
*/ if(num_repeat_peaks > 0) { /* Determine the middle of the
peak if it ** has a plateau. */ bkt_num_el = 0; bkt_width = 0; i =
num_repeat_peaks; while(i >= 0) { peak_index = (unsigned
char)(bucket_num - 1 - i); bkt_num_el += HistNumElementsPtr[peak-
_index]; bkt_width += HistWidthSumPtr[peak_index]; i--; } } else {
bkt_num_el = HistNumElementsPtr[bucket_num - 1); bkt_width =
HistWidthSumPtr[bucket_num - 1]; } /* Determine the two bucket sum
of the number of elements ** from the middle of the peak. Then
store it in the ** peak store. */
HistpeakNumElementsPtr[HistNumPeaks] = bkt_num_el; /* Determine the
two bucket sum of the elements width ** sum from the middle of the
peak. Then store it ** in the peak store. */ bkt_width /=
bkt_num_el; HistPeakAveWidthPtr[HistNumPeaks] = (unsigned
short)bkt_width; HistNumPeaks++; } /* Check for last peak */ } /*
End of function */
/************************************************************************-
**** * FUNCTION: DetermineHistWidthsConfidence AUTHOR: R. Turkal
DESCRIPTION: This function determines the confidence level of the
binary and multiwidth average element widths. It just verifies that
no width is set to zero.
*************************************************************************-
**** / void DetermineHistWidthsConfidence( LABEL_ELEMENTS_INFO_TYPE
*info_ptr) { /* Check if element widths are loaded for multiwidth
and binary. */ if (HistBinaryBarWidthsLoaded == TRUE) { if (
info_ptr->binary_bar_widths[0] == 0 .vertline. .vertline.
info_ptr->binary_bar_widths[1] == 0 .vertline. .vertline.
info_ptr->binary_space_widths[0] == 0 .vertline. .vertline.
info_ptr->binary_space_widths[1] == 0 ) {
info_ptr->binary_hist_confidence =
HIST_CONFIDENCE_HIGH_NEGATIVE; } } if
(HistMultiwidthBarWidthsLoaded == TRUE) { if (
info_ptr->multiwidth_bar_widths[0] == 0 .vertline. .vertline.
info_ptr->multiwidth_bar_widths[1] == 0 .vertline. .vertline.
info_ptr->multiwidth_space_widths[0] == 0 .vertline. .vertline.
info_ptr->multiwidth_space_widths[1] == 0) {
info_ptr->multiwidth_hist_confidence =
HIST_CONFIDENCE_HIGH_NEGATIVE; } } }
/************************************************************************-
**** * FUNCTION: DecodeHistogramPeaks AUTHOR: Jon Brandt, 12/19/98,
modified by R. Turkal DESCRIPTION: This function finds multiwidth
and binary element widths using the peaks for this histogram. The
confidence level for the element widths are also determined.
**************************************-
*************************************** / void
DecodeHistogramPeaks( LABEL_ELEMENTS_INFO_TYPE *info_ptr ) { /*
Find binary element widths. */ HistBarElementwidthsPtr =
info_ptr->binary_bar_widths; HistSpaceElementWidthsPtr =
info_ptr->binary_space_widths; HistBinaryBarWidthsLoaded =
HistBinarySpaceWidthsLoaded = FindBinaryElementWidths (); /* Find
multi-width element widths. */ HistBarElementWidthsPtr =
info_ptr->multiwidth_bar_widths; HistSpaceElementWidthsPtr =
info_ptr->multiwidth_space_widths; HistMultiwidthBarWidthsLoaded
= HistMultiwidthSpaceWidthsLoaded = FindMultiWidthElementWidths ();
DetermineHistWidthsConfidence(inf- o_ptr); } #endif
/***********************************-
***************************************** * FUNCTION:
FindBinaryElementWidths AUTHOR: Jon Brandt, 12/19/98 DESCRIPTION:
This function goes through the list of peaks and determines which 2
peaks support the widths for a binary symbology. This function
allows a wide:narrow range from 1.5:1 to 5:1. The space peak with
the most elements will be tried as a narrow element first. Then a
wide space with the most elements will be found with a wide:narrow
range of 2:1 to 4:1. If that doesn't work, a range of 1.5:1 to 5:1
will be used. If not wide space is found, the element with the
second most elements will be tried as a narrow element and the
other checks are made. Once the spaces are identified, bars of
similar widths are searched for. All combinations of narrow:wide
are tried. If a combination has more elements than any previous
combinations, the new combination is tested for the valid
wide:narrow range. The combination that has valid wide:narrow ratio
and has the most elements is the winner of the search. PSEUDOCODE
INPUTS: HistPeakNumElementsPtr - Number of elements for histogram
peaks HistPeakAveWidthPtr - Average widths for histogram peaks
HistNumPeaks - Number of peaks OUTPUTS: HistElementWidthsptr -
Binary Element width array that will be filled in. BOOLEAN TRUE -
Binary element widths were found and loaded. BOOLEAN FALSE - Binary
element widths were not found.
*************************************************************************-
**** / BOOLEAN FindBinaryElementWidths( void ) { unsigned short
max_narrow_space_num_elements; unsigned char
max_narrow_space_peak_num; unsigned short max_narrow_space_width;
unsigned short max_wide_space_num_element- s; unsigned short
max_wide_space_width; unsigned short wide_space_width; unsigned
short space_wide_narrow_delta; unsigned short
max_narrow_bar_num_elements; unsigned char max_narrow_bar_peak_num;
unsigned short max_narrow_bar_width; unsigned short
narrow_bar_width; unsigned short max_wide_bar_num_elements;
unsigned short max_wide_bar_width; unsigned short wide_bar_width;
unsigned char narrow_peak_num; unsigned char wide_peak_num;
unsigned short min_width; unsigned short max_width; BOOLEAN
found_widths; max_narrow_space_num_elements = 0; found_widths =
FALSE; /* Find the peak with the most number of elements. This will
be the ** narrow width. */ for ( narrow_peak_num = 0;
narrow_peak_num < (HistSpaceNumPeaks - 1); narrow_peak_num++ ) {
if ( HistSpacePeakNumElements[narrow_peak_num] >
max_narrow_space_num_elements ) { max_narrow_space_num_el- ements =
HistSpacePeakNumElements[narrow_peak_num];
max_narrow_space_peak_num = narrow_peak_num; } }
max_narrow_space_width = HistSpacePeakAveWidth[max_narrow_space_pe-
ak_num]; /* Now try to find the biggest wide space with a
wide:narrow ratio in ** the range of 4:1 to 2:1. */ min_width =
max_narrow_space_width * 2; max_width = max_narrow_space_width * 4;
max_wide_space_num_elements = 0; for ( wide_peak_num = (unsigned
char) (max_narrow_num+1); wide_peak_num < HistSpaceNumPeaks;
wide_peak_num++ ) { wide_space_width =
HistSpacePeakAveWidth[wide_peak_num]; if (
(HistSpacePeakNumElements[wide_peak_num] >
max_wide_space_num_elements) && (wide_space_width >=
min_width) && (wide_space_width <= max_width) ) {
max_wide_space_num_elements = HistSpacePeakNumElements[wide_pea-
k_num]; max_wide_space_width = wide_space_width; } } /* If a wide
element was not found, try to find the biggest wide space ** with a
more generous wide:narrow ratio. Now use the range of 5:1 to 1.5:1.
*/ if (
max_wide_space_num_elements == 0 ) { min_width =
(3*max_narrow_space_width) /2; max_width = max_narrow_space_width *
5; max_wide_space_num_elements = 0; for ( wide_peak_num = (unsigned
char)(max_narrow_space_peak_num+1); wide_peak_num <
HistSpaceNumPeaks; wide_peak_num++ ) { wide_space_width =
HistSpacePeakAveWidth[wide_peak_num]; if (
(HistSpacePeakNumElements[wide_peak_num] >
max_wide_space_num_elements) && (wide_space_width >=
min_width) && (wide_space_width <= max_width) ) {
max_wide_space_num_elements = HistSpacePeakNumElements[wide_pea-
k_num]; max_wide_space_width = wide_space_width; } } } /* Determine
the distance between the wide and narrow space width. */
space_wide_narrow_delta = max_wide_space_width -
max_narrow_space_width; /****************************************-
**************** /***********LOOKING FOR BARS*********************-
******** */ /* Make sure a space elements has been found. */ if (
max_wide_space_num_elements != 0 ) { /* Look for bars with a
similar set of element widths. */ /* Find the bar peak with the
most number of elements and within ** the space width +- 0.5*space
width. */ min_width = max_narrow_space_width/2; max_width =
(3*max_narrow_space_width) /2; max_narrow_bar_num_elements = 0;
max_narrow_bar_peak_num = 0; for ( narrow_peak_num = 0;
narrow_peak_num < (HistBarNumpeaks - 1); narrow_peak_num++ ) {
narrow_bar_width = HistBarPeakAveWidth[narrow_peak_num]; if (
(HistBarPeakNumElements[narrow_peak_num] >
max_narrow_bar_num_elements) && (narrow_bar_width >=
min_width) && (narrow_bar_width <= max_width) ) {
max_narrow_bar_num_elements = HistBarPeakNumElements[narrow_pea-
k_num]; max_narrow_bar_peak_num = narrow_peak_num; } } /* If a
narrow bar was found, continue */ if ( max_narrow_bar num_elements
!= 0 ) { found_widths = TRUE; max_narrow_bar_width =
HistBarPeakAveWidth[max_narrow_bar_- peak_num]; /* Look for a wide
bar that fits the separation of the narrow and wide space. */
min_width = max_narrow_bar_width + (space_wide_narrow_delta/2);
max_width = max_narrow_bar_width + ((3*space_wide_narrow_delta)
/2); max_wide_bar_num_element- s = 0; for ( wide_peak_num =
(unsigned char)(max_narrow_bar_peak_n- um+1); wide_peak_num <
HistBarNumPeaks; wide_peak_num++ ) { wide_bar_width =
HistBarPeakAveWidth[wide_peak_num]; if (
(HistBarPeakNumElements[wide_peak_num] >
max_wide_bar_num_elements) && (wide_bar_width >=
min_width) && (wide_bar_width <= max_width) ) {
max_wide_bar_num_elements = HistBarPeakNumElements [wide_peak_num];
max_wide_bar_width = wide_bar_width; } } if (
max_wide_bar_num_elements == 0 ) { max_wide_bar_width =
max_narrow_bar_width + space_wide_narrow_delta; } } } /* If valid
widths were found, store them in the array. */ if ( found widths ==
TRUE ) { HistSpaceElementWidthsPtr[0] = max_narrow_space_width;
HistSpaceElementWidthsPtr[1] = max_wide_space_width;
HistBarElementWidthsPtr[0] = max_narrow_bar_width;
HistBarElementWidthsPtr[1] = max_wide_bar_width; } return
found_widths; }
/***********************************************************************-
***** * FUNCTION: FindMultiWidthElementWidths AUTHOR: Jon Brandt,
12/20/98 DESCRIPTION: This function goes through the list of peaks
and determines which 3 peaks support the widths for a multi-width
symbology. It is not required to find the fourth width in the peak
information. If it is found, it will be used. If it is not found, a
fourth width will be calculated for the output array. Width 1 and 3
are compared to width 2 to determine their validity. The following
ranges are acceptable for widths 1 and 3: minimum width 1 =
0.5*width2 - 1/8*width2 maximum width 1 = 0.5*width2 + 1/8*width2
minimum width 3 = 1.5*width2 - 1/4*width2 maximum width 3 =
1.5*width2 + 1/4*width2 The following ranges are used to look for
width 4 once the best widths for 1, 2, and 3 are determined:
minimum width 4 = width3 + 0.5*width2 - 1/4*width2 maximum width 4
= width3 + 0.5*width2 + 3/8*width2 If width 4 is not found, it is
calculated with the following formula: width 4 = width3 +
0.5*width2 All combinations of width1:width2:width3 are tried. If a
combination has more elements than any previous combinations, the
new combination is tested for the valid width1:width2:width3 range.
The combination that is in the range and has the most elements is
the winner of the search. PSEUDOCODE INPUTS: HistPeakNumElementsPtr
- Number of elements for histogram peaks HistPeakAveWidthPtr -
Average widths for histogram peaks HistNumPeaks - Number of peaks
OUTPUTS: HistElementWidthsptr - Binary Element width array that
will be filled in. BOOLEAN TRUE - Binary element widths were found
and loaded. BOOLEAN FALSE - Binary element widths were not found.
*************************************************************************-
**** / BOOLEAN FindMultiWidthElementWidths ( void ) { unsigned
short max_width1_space_num_elements; unsigned char max widthl space
peak_num; unsigned short max_width1_space_width; unsigned short
max_width2_space_num_eleme- nts; unsigned char
max_width2_space_peak_num; unsigned short max_width2_space_width;
unsigned short max_width3_space_num_elements; unsigned char
max_width3_space_peak_num; unsigned short max_width3_space_width;
unsigned short max_width4_space_num_elements; unsigned short
max_width4_space_width; unsigned short space_width3_width1_delta;
unsigned short space_ratio3_1_delta; unsigned short
max_width1_bar_num_elements; unsigned char max_width1_bar_peak_num;
unsigned short max_width1_bar_width; unsigned short
max_width2_bar_num_elements; unsigned char max_width2_bar_peak_num;
unsigned short max_width2_bar_width; unsigned short
max_width3_bar_num_elements; unsigned char max_width3_bar_peak_num;
unsigned short max_width3_bar_width; unsigned short
max_width4_bar_num_elements; unsigned short max_width4_bar_width;
unsigned short bar_width3_width_delta; unsigned short
bar_ratio3_1_delta; unsigned short space_bar_width3_widthl_delta;
unsigned short best_quality_level; unsigned short
new_quality_level; unsigned short best_space_width3_peak_num;
unsigned short best_bar_width3_peak_num; unsigned char
width1_peak_num; unsigned char width2_peak_num; unsigned char
width3_peak_num; unsigned char width4_peak_num; unsigned short
min_width; unsigned short max_width; unsigned short element_width;
unsigned short temp_store; BOOLEAN found_widths;
max_width1_space_num_elements = 0; found_widths = FALSE;
best_quality_level = 0.times.FFFF; /* Loop through all possible
width1 peaks. */ for ( max_width1_space_peak_num = 0;
max_width1_space_peak_num < (HistSpaceNumpeaks - 2);
max_width1_space_peak_num++ ) { /* store data for width1 space */
max_width1_space_num_elements =
HistSpacePeakNumElements[max_width1_space_peak_num];
max_width1_space_width = HistSpacePeakAveWidth[max_width1_space_pe-
ak_num]; /* Now try to find the biggest width2 space with a
width2:width1 ratio in ** the range of 1.5:1 to 2.5:1. */ min_width
= (3*max_width1_space_width) /2; max_width = min_width +
max_width1_space_width; max_width2_space_num_elements = 0; for (
width2_peak_num = (unsigned char)(max_width1_space_peak_num+1);
width2_peak_num < (HistSpaceNumPeaks - 1); width2_peak_num++ ) {
element_width = HistSpacePeakAveWidth[width2_peak_num]; if (
(HistSpacePeakNumElements[width2_peak_num] >
max_width2_space_num_elements) && (element_width >=
min_width) && (element_width <= max_width) ) {
max_width2_space_num_elements = HistSpacePeakNumElements
[width2_peak_num]; max_width2_space_width = element_width;
max_width2_space_peak_num = width2_peak_num; } } /* If a width2
space was found, try to find the biggest width3 space. ** Use a
width3:width1 ratio range of 2.5 to 3.5 */ if (
max_width2_space_num_elements != 0 ) { min_width =
max_width2_space_width + (max_width1_space_width/2); max_width =
min_width + max_width1_space_width; max_width3_space_num_elements =
0; for ( width3_peak_num = (unsigned
char)(max_width2_space_peak_num+1); width3_peak_num <
HistSpaceNumPeaks; width3_peak_num++ ) { element_width =
HistSpacePeakAveWidth[width3_peak_num]; if (
(HistSpacePeakNumElements[width3_peak_num] >
max_width3_space_num_elements) && (element_width >=
min_width) && (element_width <= max_width) ) {
max_width3_space_num_elements = HistSpacePeakNumElements[width3_pe-
ak_num]; max_width3_space_width = element_width;
max_width3_space_peak_num = width3_peak_num; } } /* If a width3
space was found, try to find the biggest width1 bar. ** Use a width
range of 0.5 space widthl to 1.5 space width1. */ if (
max_width3_space_num_elements != 0 ) { min_width =
max_width1_space_width/2; max_width = min_width +
max_width1_space_width; max_width1_bar_num_elements = 0; for (
width1_peak_num = 0; width1_peak_num < (HistBarNumPeaks - 2);
width1_peak_num++ ) { element_width =
HistBarPeakAveWidth[width1_peak_num]; if (
(HistBarPeakNumElements[width1_peak_num] >
max_width1_bar_num_elements) && (element_width >=
min_width) && (element_width <= max_width) ) {
max_width1_bar_num_elements = HistBarPeakNumElements
[width1_peak_num]; max_width1_bar_width = element_width;
max_width1_bar_peak_num = width1_peak_num; } } /* If a width1 bar
was found, try to find the biggest width2 bar. ** Use a
width2:width1 range of 1.5 to 2.5. */ if (
max_width1_bar_num_elements != 0 ) { min_width =
(3*max_width1_bar_width) /2; max_width = min_width +
max_width1_bar_width; max_width2_bar_num_elements = 0; for (
width2_peak_num = (unsigned char)(max_width1_bar_peak_num+1)- ;
width2_peak_num < (HistBarNumPeaks - 1); width2_peak_num++ ) {
element_width = HistBarPeakAveWidth[width2_peak_num]; if (
(HistBarPeakNumElements[width2_peak_num] >
max_width2_bar_num_elements) && (element_width >=
min_width) && (element_width <= max_width) ) {
max_width2_bar_num_elements = HistBarPeakNumElements[width2_peak_n-
um]; max_width2_bar_width = element_width; max_width2_bar_peak_num
= width2_peak_num; } } /* If a width2 bar was found, try to find
the biggest width3 bar. ** Use a width3:width1 range of 2.5 to 3.5.
*/ if ( max_width2_bar_num_elements != 0 ) { min_width =
max_width2_bar_width + max_width1_bar_width/2; max_width =
min_width + max_width1_bar_width; max_width3_bar_num_elements = 0;
for ( width3_peak_num = (unsigned char)(max_width2_bar_peak_num+1);
width3_peak_num < HistBarNumPeaks; width3_peak_num++ ) {
element_width = HistBarPeakAveWidth[width3_peak_num]; if (
(HistBarPeakNumElements[width3_peak_num] >
max_width3_bar_num_elements) && (element_width >=
min_width) && (element_width <= max_width) ) {
max_width3_bar_num_elements = HistBarPeakNumElements[width3_peak_n-
um]; max_width3_bar_width = element_width; max_width3_bar_peak_num
= width3_peak_num; } } /* If a width3 bar was found, try to find a
width4 space and bar. */ if ( max_width3_bar_num_elements != 0 ) {
found_widths = TRUE; /* Determine if this is a better set of widths
than previous widths.*/ /* Determine measurements of space quality
*/ space_width3_width1_delta = max_width3_space_width -
max_width1_space_width; temp_store =
max_width3_space_width/max_width1_space_width; if ( temp_store == 2
) { space_ratio3_1_delta = max_width1_space_width -
(max_width3_space_width%max_width1_space_width); } else if (
temp_store == 3 ) { space_ratio3_1_delta =
max_width3_space_width%max_width1_space_width; } else {
space_ratio3_1_delta = max_width1_space_width; } /* Determine
measurements of bar quality */ bar_width3_width1_delta =
max_width3_bar_width - max_width1_bar_width; temp_store =
max_width3_bar_width/ma- x_width1_bar_width; if ( temp_store == 2 )
{ bar_ratio3_1_delta = max_width1_bar_width -
(max_width3_bar_width%max_width1_bar_width); } else if ( temp_store
== 3 ) { bar_ratio3_1_delta =
max_width3_bar_width%max_width1_bar_width; } else {
bar_ratio3_1_delta = max_width1_bar_width; } /* calculate total new
quality */ if ( bar_width3_width1_delta <
space_width3_width1_delta ) { space_bar_width3_width1_delta =
space_width3_width1_delta - bar_width3_width1_delta; } else {
space_bar_width3_width1_delta = bar_width3_width1_delta -
space_bar_width3_width1_delta; } new_quality_level = (2 *
space_bar_width3_width1_delta) + bar_ratio3_1_delta +
space_ratio3_1_delta; /* If this width set has better quality, save
the widths ** and other information to find the 4th width. */ if (
new_quality_level < best_quality_level ) { best_quality_level =
new_quality_level; HistSpaceElementWidthsPtr[0] =
max_width1_space_width; HistSpaceElementWidthsPtr[1] =
max_width2_space_width; HistSpaceElementWidthsPtr[2] =
max_width3_space_width; HistBarElementWidthsptr[0] =
max_width1_bar_width; HistBarElementWidthsptr[1] =
max_width2_bar_width; HistBarElementWidthsptr[2] =
max_width3_bar_width; best_bar_width3_peak_num =
max_width3_bar_peak_num; best_space_width3_peak_num =
max_width3_space_peak_num; } } } } } } } /* If valid widths were
found, look for width 4. */ if ( found_widths == TRUE ) { /* Try to
find width4 space. */ min_width = HistSpaceElementWidthsPtr[2] +
(HistSpaceElementWidths- ptr[0]/2); max_width =
HistSpaceElementWidthsPtr[2] +
((3*HistSpaceElementWidthsPtr[0])/2); max_width4_space_num_elemen-
ts = 0; for ( width4_peak_num = (unsigned
char)(best_space_width3_peak_num+1); width4_peak_num <
HistSpaceNumPeaks; width4_peak_num++ ) { element_width =
HistSpacePeakAveWidth[width4_peak_num]; if (
(HistSpacePeakNumElements[width4_peak_num] >
max_width4_space_num_elements) && (element_width >=
min_width) && (element_width <= max_width) {
max_width4_space_num_elements = HistSpacePeakNumElements[width4_pe-
ak_num]; max_width4_space_width = element_width; } } /* Calculate
width4 space if it can't be found. */ if (
max_width4_space_num_elements == 0 ) { HistSpaceElementWidthsPtr[3]
= HistSpaceElementWidthsPtr[2] + HistSpaceElementWidthsPtr[0]; }
else {
HistSpaceElementWidthsPtr[3] = max_width4_space_width; } /* Try to
find width4 bar. */ min_width = HistBarElementWidthsPtr- [2] +
(HistBarElementWidthsPtr[0]/2); max_width =
HistBarElementWidthsPtr[2] + ((3*HistBarElementWidthsPtr[0]/2);
max_width4_bar_num_elements = 0; for ( width4_peak_num = (unsigned
char)(best_bar_width3_peak_num+1); width4_peak_num <
HistBarNumPeaks; width4_peak_num++ ) { element_width =
HistBarPeakAveWidth[width4_peak_num]; if (
(HistBarPeakNumElements[width4_peak_num] >
max_width4_bar_num_elements) && (element_width >=
min_width) && (element_width <= max_width) ) {
max_width4_bar_num_elements = HistBarPeakNumElements[width4_peak_n-
um]; max_width4_bar_width = element_width; } } /* Calculate width4
space if it can't be found. */ if ( max_width4_bar_num_elements ==
0 ) { HistBarElementWidthsPtr[3] = HistBarElementWidthsPtr[2] +
HistBarElementWidthsPtr[0]; } else { HistBarElementWidthsptr[3] =
max_width4_bar_width; } } return found_widths; } #ifndef
HAS_CAPTURE_EDGE_STRENGTH /***************************************-
************************************* * FUNCTION:
DecodeHistogramPeaks AUTHOR: Jon Brandt, 12/19/98, modified by R.
Turkal DESCRIPTION: This function finds multiwidth and binary
element widths using the peaks for this histogram. The confidence
level for the element widths are also determined. PSEUDOCODE Load
global variables for bars. Find binary element widths for bars.
Find multi-width element widths for bars. Load global variables for
spaces. Find binary element widths for spaces. Find multi-width
element widths for spaces. Calculate bar-space-binary-width-delta
to make sure binary bars and spaces agree in distance between
narrow and wide elements. Calculate bar-space-multi-width-delta to
make sure multi-width bars and spaces agree in distance between
width1 and width3 elements. INPUTS: HistBarPeakNumElements - Number
of elements for bar histogram peaks HistBarPeakAveWidth - Average
widths for bar histogram peaks HistBarNumPeaks - Number of bar
peaks HistSpacePeakNumElements - Number of elements for space
histogram peaks HistSpacePeakAveWidth - Average widths for space
histogram peaks HistSpaceNumPeaks - Number of space peaks
LABEL_ELEMENTS_INFO_TYPE *info_ptr - pointer to element information
for the current potential label. Some info will be filled in.
OUTPUTS: Some label element information structure members will be
updated. LABEL_ELEMENTS_INFO_TYPE *info_ptr binary_hist_confidence
- histogram confidence for binary symbologies
multiwidth_hist_confidence - hisogram confidence for multiwidth
symbologies binary_bar_widths - bar widths for binary symbologies
binary_space_widths - space widths for binary symbologies
multiwidth_bar_widths - bar widths for multiwidth symbologies
multiwidth_space_widths - space widths for multiwidth symbologies
*************************************************************************-
**** / void DecodeHistogramPeaks( LABEL_ELEMENTS_INFO_TYPE
*info_ptr ) { unsigned short bar_width_delta; unsigned short
space_width_delta; unsigned short binary_bar_space_width_delta;
unsigned short multiwidth_bar_space_width_delta; /* Find binary
element widths. */ HistBarElementWidthsPtr =
info_ptr->binary_bar_widths; HistSpaceElementWidthsPtr =
info_ptr->binary_space_widths; HistBinaryBarWidthsLoaded =
HistBinarySpaceWidthsLoaded = FindBinaryElementWidths(); /* Find
multi-width element widths. */ HistBarElementWidthsPtr =
info_ptr->multiwidth_bar_widt- hs; HistSpaceElementWidthsPtr =
info_ptr->multiwidth_space_widt- hs;
HistMultiwidthBarWidthsLoaded = HistMultiwidthSpaceWidthsLoaded =
FindMultiWidthElementWidths(); /* Calculate
bar-space-binary-width-delta to ** make sure binary bars and spaces
agree in distance ** between narrow and wide elements. ** First
make sure there are binary bar widths and space widths. */ if (
(HistBinaryBarWidthsLoaded == TRUE) &&
(HistBinarySpaceWidthsLoaded == TRUE) { /* There are bar and space
widths. ** Calculate distance between wide and narrow elements. */
bar_width_delta = info_ptr->binary_bar_widths[1] -
info_ptr->binary_bar_width- s[0]; space_width_delta =
info_ptr->binary_space_widths[1] -
info_ptr->binary_space_widths[0]; /* Calculate difference
between bars and spaces in ** wide-narrow distance. */ if (
bar_width_delta < space_width_delta ) {
binary_bar_space_width_delta = space_width_delta - bar_width_delta;
bar_width_delta = bar_width_delta / 2; } else {
binary_bar_space_width_delta = bar_width_delta - space_width_delta;
bar width delta =space width delta / 2; } /* If the difference
between bars and spaces in ** wide-narrow distance is greater than
50% of the smallest, ** throw out these results because the bars
and space widths ** don't go together. */ if (
binary_bar_space_width_delta > bar_width_delta ) {
HistBinaryBarWidthsLoaded = FALSE; HistBinarySpaceWidthsLoaded =
FALSE; binary_bar_space_width_delta = 0.times.FFFF; } } else /* We
don't have widths for bars and spaces. */ { /* Invalidate both bars
and space widths since we ** don't have both of them. */
HistBinaryBarWidthsLoaded = FALSE; HistBinarySpaceWidthsLoaded =
FALSE; binary_bar_space_width_delta = 0.times.FFFF; } /* Calculate
bar-space-multiwidth-width-delta to ** make sure multiwidth bars
and spaces agree in distance ** between widthl and width3. ** First
make sure there are multiwidth bar widths and space widths. */ if (
(HistMultiwidthBarWidthsLoaded == TRUE) &&
(HistMultiwidthSpaceWidthsLoaded == TRUE) ) { /* There are bar and
space widths. ** Calculate distance between width3 and width1
elements. */ bar_width_delta =
info_ptr->multiwidth_bar_widths[2] - info_ptr->multiwidth_b-
ar_widths[0]; space_width_delta = info_ptr->multiwidth_space_wi-
dths[2] - info_ptr->binary_space_widths[0]; /* Calculate
difference between bars and spaces in ** width3-width1 distance. */
if ( bar_width_delta < space_width_delta ) {
multiwidth_bar_space_width_delta = space_width_delta -
bar_width_delta; bar_width_delta = bar_width_delta / 2; } else {
multiwidth_bar_space_width_delta = bar_width_delta -
space_width_delta; bar_width_delta = space_width_delta / 2; } /* If
the difference between bars and spaces in ** width3-width1 distance
is greater than 50% of the smallest, ** throw out these results
because the bars and space widths ** don't go together. */ if (
multiwidth_bar_space_width_delta > bar_width_delta ) {
HistMultiwidthBarWidthsLoaded = FALSE; HistMultiwidthSpaceWidthsL-
oaded = FALSE; multiwidth_bar_space_width_delta = 0.times.FFFF; } }
else /* We don't have widths for bars and spaces. */ { /*
Invalidate both bars and space widths since we ** don't have both
of them. */ HistMultiwidthBarWidthsLoaded = FALSE;
HistMultiwidthSpaceWidthsL- oaded = FALSE;
multiwidth_bar_space_width_delta = 0.times.FFFF; } /* Determine
confidence level of binary and multi-width ** element widths. */
DetermineHistWidthsConfidence( info_ptr,
binary_bar_space_width_delta, multiwidth_bar_space_widt- h_delta );
} /**********************************************-
****************************** * FUNCTION:
RestartLabelElementHistogram AUTHOR: Jon Brandt, 12/13/98
DESCRIPTION: This function clears out the histograms and determines
the new bucket size. To find the new bucket size divide the maximum
element size by 16. The bucket size is stored in each histogram
data structure. INPUTS: info_ptr is a pointer to a label element
info data structure. biggest_element_in_label - Stores the biggest
element that has been seen in the label. OUTPUTS: info_ptr - the
label histogram data is cleared an initialized for the new label.
************************************************************************-
***** / void RestartLabelElementHistogram( LABEL_ELEMENTS_INFO_TYPE
*info_ptr) { unsigned short min_value; /* Initialize histogram for
new data */ InitLabelElementHistogram(
&(info_ptr->bar_histogram) ); InitLabelElementHistogram(
&(info_ptr->space_histogram) ); /* To determine the new
bucket size, divide the ** biggest element by 16. */ min_value =
biggest_element_in_label/16; / * store bucket size in bar and space
histogram. */ info_ptr->bar_histogram.bucket_size = min_value;
info_ptr->space_histogram.bucket_size = min_value; }
/************************************************************************-
**** * FUNCTION: UpdateLabelElementHistogram AUTHOR: Jon Brandt,
12/13/98 DESCRIPTION: This function uses the information in the
label element info structure to add information to the histogram
and decode the histogram. First it adds the label element
information to the bar and space histograms. Then it finds the
peaks in the bar and space histogram and calculates the average
element width for each peak. Then the peaks are decoded to
determine what peaks are the correct ones for binary and
multi-width symbologies. During the decoding of the peaks, the
confidence level of the widths for binary and multi-width are
determined. INPUTS: LABEL_ELEMENTS_INFO_TYPE *info_ptr - pointer to
element information for the current potential label. OUTPUTS:
info_ptr bar and space histograms are updated. info_ptr
binary_hist_confidence and multiwidth_hist_confidence are
determined. info_ptr binary_bar_widths, binary_space_widths,
multiwidth_bar_widths, and multiwidth_space_widths are determined.
*************************************************************************-
**** / void UpdateLabelElementHistogram( LABEL_ELEMENTS_INFO_TYPE
*info_ptr) { HistLblEndPtr = info_ptr->label_end; /* Update the
bar histogram with new elements. ** First set up global variables
for subroutine. */ HistLblStartPtr = info_ptr->label_start;
HistBucketSize = info_ptr->bar_histogram.bucket_size;
HistNumElementsPtr = info_ptr->bar_histogram.number_elements;
HistWidthSumPtr = info_ptr->bar_histogram.width_sum;
UpdateHistogramCntsAndSum (); /* Determine the peaks and average
width for each peak ** of the bar histogram. */
HistPeakNumElementsptr = HistBarPeakNumElements;
HistPeakAveWidthPtr = HistBarPeakAveWidth; FindHistogramPeaks ();
HistBarNumPeaks = HistNumPeaks; /* Update the space histogram with
new elements. ** First set up global variables for subroutine. */
HistLblStartPtr = info_ptr->label_start + 1; HistBucketSize =
info_ptr->space_histogram.bucket_size; HistNumElementsPtr =
info_ptr->space_histogram.number_elements; HistWidthSumPtr =
info_ptr->space_histogram.width_sum; UpdateHistogramCntsAndSum
(); /* Determine the peaks and average width for each peak ** of
the space histogram. */ HistPeakNumElementsPtr =
HistSpacePeakNumElements; HistPeakAveWidthPtr =
HistSpacePeakAveWidth; FindHistogramPeaks (); HistSpaceNumPeaks =
HistNumPeaks; /* Decode the histogram peaks to determine the
probable element ** widths for multi-width and binary symbologies.
** Determine confidence level of widths for multi-width ** and
binary symbologies. */ DecodeHistogramPeaks ( info_ptr ); }
/************************************************************************-
**** * FUNCTION: FindHistogramPeaks AUTHOR: Jon Brandt, 12/18/98,
modified by R.Turkal DESCRIPTION: This function searches the label
element histogram for peaks in the number of elements in a bucket.
2 bucket sums of the number of elements is calculated for each
bucket. A 2 bucket sum is the total of a bucket and the previous
bucket. Then the 2 bucket sum is used to find a peak. A peak is
defined as a 2 bucket sum that has more elements than both of it's
neighbors. If there are more than 1 bucket in a row with the same 2
bucket sum, the middle bucket is chosen. When a peak is found, the
average element width is calculated and stored in an array. The 2
bucket sume for the peak is also stored in an array. INPUTS:
HistNumElementsPtr = Histogram of the number of elements in a
bucket. HistWidthSumPtr = Histogram of the width total for all
elements of the bucket. OUTPUTS: HistNumPeaks - The number of peaks
will be determined. HistPeakNumElementsPtr - pointer to an array of
the 2 bucket sum for the peaks. This will be filled in.
HistPeakAveWidthPtr - pointer to an array of the average width for
the peaks. This will be filled in.
*************************************************************************-
**** / void FindHistogramPeaks(void) { unsigned short
last_two_bkt_num_el; unsigned short two_bkt_num_el; unsigned long
two_bkt_width; unsigned char num_repeat_peaks; unsigned char
peak_index; unsigned char bucket_num; BOOLEAN ascending;
last_two_bkt_num_el = 0; HistNumpeaks = 0; ascending = TRUE;
num_repeat_peaks = 0; /* Go through all the buckets of the
histogram. */ for (bucket_num = 0; bucket_num <
(NUMBER_OF_BUCKETS - 1); bucket_num++) { /* Calculate the 2 bucket
sum of the number of elements. */ two_bkt_num_el =
HistNumElementsPtr[bucket_num] + HistNumElementsPtr[bucket_num +
1]; /* If the new two bucket sum is greater than the previous ** we
are ascending. */ if ( two_bkt_num_el > last_two_bkt_num_el ) {
ascending = TRUE; last_two_bkt_num_el = two_bkt_num_el;
num_repeat_peaks = 0; } /* If this two bucket sum and the previous
are the same, ** we are on a plateau and need to record the number
of ** repeats. */ else if ( two_bkt_num_el == last_two_bkt_num_el )
{ num_repeat_peaks++; } /* If the new two bucket sum is less than
the previous ** we are descending. */ else if ( two_bkt_num_el <
last_two_bkt_num_el ) { last_two_bkt_num_el = two_bkt_num_el; /* If
we were previously ascending, store the ** peak we just passed. */
if ( ascending == TRUE ) { /* Determine the middle of the peak if
it ** has a plateau. */ peak_index = (unsigned char)(bucket_num - 1
- num_repeat_peaks + num_repeat_peaks/2); /* Determine the two
bucket sum of the number of elements ** from the middle of the
peak. Then store it in the ** peak store. */ two_bkt_num_el =
HistNumElementsPtr[peak_index] + HistNumElementsPtr[peak_index +
1]; HistPeakNumElementsPtr[HistNu- mpeaks] = two_bkt_num_el; /*
Determine the two bucket sum of the elements width ** sum from the
middle of the peak. Then store it ** in the peak store. */
two_bkt_width = HistWidthSumPtr[peak_index] +
HistWidthSumPtr[peak_index + 1]; two_bkt_width /= two_bkt_num_el;
HistPeakAveWidthPtr[HistNum- Peaks]= (unsigned short)two_bkt_width;
HistNumPeaks++; } else { /* Already descending so don't do
anything. */ } ascending = FALSE; num_repeat_peaks = 0; } /* If now
descending */ } /* loop
through buckets */ /* If the histogram ending ascending, store the
last ** two bucket sum as a peak. */ if ( (ascending == TRUE)
&& (last_two_bkt_num_el > 0) ) { /* Determine the middle
of the peak if it ** has a plateau. */ peak_index = (unsigned
char)(bucket_num - 1 - num_repeat_peaks + num_repeat_peaks/2); /*
Determine the two bucket sum of the number of elements ** from the
middle of the peak. Then store it in the ** peak store. */
two_bkt_num_el = HistNumElementsPtr[peak_index] +
HistNumElementsPtr[peak_index + 1]; HistPeakNumElementsPtr[HistNu-
mpeaks] = two_bkt_num_el; /* Determine the two bucket sum of the
elements width ** sum from the middle of the peak. Then store it **
in the peak store. */ two_bkt_width = HistWidthSumPtr[peak_index] +
HistWidthSumPtr[peak_index + 1]; two_bkt_width /= two_bkt_num_el;
HistPeakAveWidthPtr[HistNum- Peaks] = (unsigned
short)two_bkt_width; HistNumPeaks++; } /* Check for last peak */ }
/* End of function */
/************************************************************************-
**** * FUNCTION: DetermineHistWidthsConfidence AUTHOR: Jon Brandt,
12/20/98 DESCRIPTION: This function determines the confidence level
of the binary and multiwidth average element widths. It uses
information from the multiwidth and binary widths to determine the
confidence level. PSEUDOCODE INPUTS: LABEL_ELEMENTS_INFO_TYPE
*info_ptr - pointer to element information for the current
potential label. The average element widths will be referenced. The
confidence levels will be filled in. binary_bar_space_width_delta -
This is the difference in wide_narrow distance between bars and
spaces for binary element widths. The binary element widths are
more reliable when this number is low. multiwidth_bar_space_width-
_delta - This is the difference in wide_narrow distance between
bars and spaces for multiwidth element widths. The multiwidth
element widths are more reliable when this number is low.
HistMultiwidthBarWidthsLoaded - This indicates if there are widths
available for multiwidth symbologies. HistBinaryBarWidthsLoaded -
This indicates if there are widths available for binary
symbologies. HistBarNumpeaks - This indicates how many bar peaks
were identified in the histogram HistSpaceNumPeaks - This indicates
how many space peaks were identified in the histogram OUTPUTS:
LABEL_ELEMENTS_INFO_TYPE *info_ptr The confidence level members of
this structure will be filled in.
*************************************************************************-
**** / void DetermineHistWidthsConfidence( LABEL_ELEMENTS_INFO_TYPE
*info_ptr, unsigned short binary_bar_space_width_delta, unsigned
short multiwidth_bar_space_width_delta ) { unsigned short
min_delta; /* Check if element widths are loaded for multiwidth and
binary. */ if ( (HistMultiwidthBarWidthsLoaded == TRUE) &&
(HistBinaryBarWidthsLoaded == TRUE) ) { /* If the binary is using
the multiwidth width1 and width2 ** for it's narrow and wide
widths, give more confidence to ** the multiwidth. Also, if
multiwidth delta is within 25% ** of the binary delta, we will
assume the symbology is a multiwidth. */ min_delta =
(5*binary_bar_space_width_delta) /4; if ( (
(info_ptr->binary_bar_widths[0] == info_ptr-
>multiwidth_bar_widths[0]) &&
(info_ptr->binary_bar_widths[- 1] == info_ptr-
>multiwidth_bar_widths[1]) &&
(info_ptr->binary_space_widths[0] == info_ptr-
>multiwidth_space_widths[0]) &&
(info_ptr->binary_space_wid- ths[1] == info_ptr-
>multiwidth_space_widths[1]) ) .vertline. .vertline. (
multiwidth_bar_space_width_delta < min_delta ) ) { /* Since this
is multiwidth but we also have binary widths, ** the binary
symbologies will be given some confidence. */
info_ptr->binary_hist_confidence = HIST_CONFIDENCE_LOW_POSITIVE;
/* Only give the highest rating if there are exactly the ** correct
number of histogram peaks for multiwidth. */ if ( (HistBarNumPeaks
> 4) .vertline. .vertline. (HistSpaceNumPeaks > 4) ) {
info_ptr->multiwidth_hist_confidence = HIST_CONFIDENCE_MEDIUM_P-
OSITIVE; } else /* There are exactly the correct number of peaks.
*/ { info_ptr->multiwidth_hist_confidence =
HIST_CONFIDENCE_HIGH_POSITIVE; } } else /* There is more confidence
in binary than multiwidth. */ { /* There are at least 4 widths
which is too many for a binary ** symbology so binary has medium
confidence. */ info_ptr->binary_hist_confidence =
HIST_CONFIDENCE_MEDIUN_POSIT- IVE; /* Multiwidth has low confidence
*/ info_ptr->multiwidth_hist_confidence =
HIST_CONFIDENCE_LOW_POSI- TIVE; } } /* Check if element widths are
loaded only for multiwidth. */ else if
(HistMultiwidthBarWidthsLoaded == TRUE) { /* There are enough
histogram peaks for binary but they don't ** fit the symbology.
Give a low negative confidence. */
info_ptr->binary_hist_confidence =HIST_CONFIDENCE_LOW_NEGATIVE;
/* Only give the highest rating if there are exactly the ** correct
number of histogram peaks for multiwidth. */ if ( (HistBarNumpeaks
> 4) .vertline. .vertline. (HistSpaceNumPeaks > 4) ) {
info_ptr->multiwidth_hist_confidence = HIST_CONFIDENCE_MEDIUM_P-
OSITIVE; } else /* There are exactly the correct number of peaks.
*/ { info_ptr->multiwidth_hist_confidence =
HIST_CONFIDENCE_HIGH_POSITIVE; } } /* Check if element widths are
loaded only for binary. */ else if (HistBinaryBarWidthsLoaded ==
TRUE) { /* Only give the highest rating if there are exactly the **
correct number of histogram peaks for binary. ** Multiwidth will
get a little confidence if there are ** three widths. */ if (
(HistBarNumPeaks > 2) .vertline. .vertline. (HistSpaceNumPeaks
> 2) ) { info_ptr->multiwidth_hist_confidence =
HIST_CONFIDENCE_LOW_NEGATIVE; info_ptr->binary_hist_confidence =
HIST_CONFIDENCE_MEDIUM_POSITIVE; } else /* There are exactly the
correct number of peaks for binary ** but there is no way this
could be multiwidth. */ { info_ptr->multiwidth_hist_confidence =
HIST_CONFIDENCE_HIGH_NEG- ATIVE;
info_ptr->binary_hist_confidence =
HIST_CONFIDENCE_HIGH_POSITIVE; } } else /* There are no widths
loaded for binary or multiwidth. */ { /* Only give a little
confidence if there are enough peaks ** for a symbology type. **
Binary and multiwidth are possible with 3 widths. */ if (
(HistBarNumPeaks > 2) .vertline. .vertline. (HistSpaceNumPeaks
> 2) ) { info_ptr->multiwidth_hist_confidence =
HIST_CONFIDENCE_LOW_NEGA- TIVE; info_ptr->binary_hist_confidence
= HIST_CONFIDENCE_LOW_NEGATIVE; } /* Give a little confidence to
binary if there are enough widths */ else if ( (HistBarNumPeaks
> 1) .vertline. .vertline. (HistSpaceNumPeaks > 1) ) {
info_ptr->multiwidth_hist_confidence =
HIST_CONFIDENCE_HIGH_NEGATIVE; info_ptr->binary_hist_confidenc-
e = HIST_CONFIDENCE_LOW_NEGATIVE; } else /* There is only 1 peak
for bars and spaces. No confidence ** is given. */ {
info_ptr->multiwidth_hist_confidence =
HIST_CONFIDENCE_HIGH_NEGATIVE; info_ptr->binary_hist_confidenc-
e = HIST_CONFIDENCE_HIGH_NEGATIVE; } } }
;************************************************************************-
**** * ;FUNCTION: UpdateHistogramCntsAndSum ; ;AUTHOR: Jon Brandt,
12/17/98, modified by R. Turkal ; ;DESCRIPTION: ; This function
goes through every other element of the label to ; update the
number of elements and element width sum for the ; histogram. ; For
each element this function 1st checks if the edge strength
associated ; with the element is greater than the edge strength
threshold. If the edge strength ; is greated then the threshold it
then calculates the index into the histogram. Then it ; updates the
number of elements for that bucket and adds the element width to
the width ; sum for the bucket. If the edge strength is less than
the threshold the corresponding ; element data is not added to the
histogram. ; INPUTS: ; ; unsigned short *HistLblStartPtr - first
bar of the label to be added. ; unsigned short *HistLblEndPtr -
last bar of the label to be added. ; unsigned short HistBucketSize
- bucket size of this histogram. ; unsigned short
*HistNumElementsptr - histogram bucket ptr for number of elements ;
unsigned long *HistWidthSumPtr - histogram bucket for the width
sum. ; stvStrengthEdge - if set to 1 looking at STV (bar) elements,
otherwise looking ; at RTV (space) elements ; StrengthPtr - set to
edge strength corresponding to the start of the potential ; label
data ; ; ;OUTPUTS: ; unsigned short *HistNumElementsptr - number of
elements histogram will be updated. ; unsigned long
*HistWidthSumPtr - width sum histogram will be updated. ; ;REGISTER
USAGE ; register D: element width and scratch ; register E: scratch
; register IX: divisor for index determination and pointer to edge
strength data. ; register IY: Pointer to current element of label.
; register IZ: Pointer to start of number of elements histogram ;
and Pointer to start of element width sum histogram. ;
;***********************************-
***************************************** *
_UpdateHistogramCntsAndSum: pshm k,x,y,z ;Set up RAM Page ldab
#RAM_PAGE tbek tbxk tbyk tbzk bsr _FindSignalStrengthThresholds
;compute signal strength threshold ; restart the average edge
strength on each possible label ldx _StrengthPtr+2 ; get the
strength counts pointer ldd 0,x ; get the strength count ldx
+TL,7_averageStrength+2 ; get the average strength pointer std 0,x
;store the 1st edge strength value so average works out correctly
;Set up Y with the first element of the label ldy
_HistLblStartPtr+2 ADD_ELEMENT_TO_HIST: ldx _StrengthPtr+2 ; get
the strength counts pointer ldd 0,x ; get the strength count aix #4
; adjust the strength counts pointer stx _StrengthPtr+2 ; and save
it away cpd _strengthThreshold ; compare against threshold brclr
_edgeType,#1,RTV_EDGE_STRENGTH ;if = 1 we're dealing a STV strength
value, ; else we're dealing with an RTV strength value bcs
ADD_ELEMENT_TO_HIST1 ; if carry is clear then stv strength is too
large ; (larger STV number = weaker_edge) bra INC_TWO_LBL_ELEMENTS
; RTV_EDGE_STRENGTH: bcs INC_TWO_LBL_ELEMENTS ; if carry set RTV
strength value is too small so don't add this ; element count to
the histogram (smaller RTV number = weaker edge)
ADD_ELEMENT_TO_HIST1: ldx _averageStrength+2 ; get the average
strength pointer addd 0,x ; compute average edge strength 1srd ;
divide by 2 std 0,x ; and save average away ;Divide the element by
the bucket size to get ;the index into the histogram. Index result
;ends up in X. ldd 0,y ldx _HistBucketSize idiv ;Check if index is
within histogram size. ;If it is too big, advance 2 elements cpx
#NUMBER_OF_BUCKETS jbcc INC_TWO_LBL_ELEMENTS ;Increment correct
bucket for this element width. ;Load Z with start of the histogram
for number of elements. ldz _HistNumElementsPtr+2 ;Put index in D
and multiply it by 2 since ;the number of elements is a 2 byte
store. xgdx asld ;Advance Z to the correct bucket. adz ;Increment
the bucket count for this element. incw 0,z ;Add element width to
correct bucket for this element width. ;Load Z with start of the
histogram for element width sum. ldz _HistWidthSumPtr+2 ;index*2 is
already in D ;Multiply it by 2 again since the element width sum
;is a 4 byte store. asld ;Advance Z to the correct bucket. adz
;Load E:D width element width ldd 0,y clre ;Add current sum to E:D
and store it back in histogram. addd 2,z adce 0,z std 2,z ste 0,z
;Advance 2 elements so we continue processing ;the same element
type(if we are doing bars go to ;the next bar). Each element is a 2
byte store. INC_TWO_LBL_ELEMENTS: aiy #4 cpy _HistLblEndPtr+2 jbls
ADD_ELEMENT_TO_HIST ;Return pulm k,x,y,z rts
;*****************************************************************-
*********** * ;FUNCTION: FindSignalStrengthThresholds ; ;AUTHOR; R.
Turkal ; DESCRIPTION: ; This function used to compute the RTV and
STV edge strength tolerances which ; are used to determine if an
element count will be added to the label histogram. ; This function
goes through the edge strength buffer, determines the strongest ;
RTV and STV edges, and then calculates the thresholds. ; ; This
function is called twice for each potential label found (i.e. on
each leading ; and trailing QZ). It is called once for the RTV
counts and once for the STV counts. ; In this manner we are always
using a dynamic edge strengt threshold for each ; potential label.
; ;INPUTS: ; stvStrengthEdge - if set to 1 calculate the STV
threshold, otherwise calculate ; the RTV threshold. ;
HistLblStartPtr - set to the start of the potential label data ; ;
HistLblEndPtr - set to the end of potential label data ; ;
StrengthPtr - set to edge strength corresponding to the start of
the potential ; label data ; ;OUTPUTS: ; strLimit - set to the
threshold to use. It is used for both the RTV and STV ; threshold.
; ;REGISTER USAGE ; registers A,B,D,E,X,Y are scratch and used for
multiple purposes. ; register Y points to potential label data and
is used as a counter to indicate ; when all interesting data has
been examined. ; register X points to the edge strength buffer and
is used to examine the various ; edge strength values. ;
;************************************************************************-
**** */ _FindSignalStrengthThresholds: ;Set up Y with the first
element of the label ldy _HistLblStartPtr+2 ldx _StrengthPtr+2 ;
get the strength counts pointer brclr _edgeType,#1,GET_RTV_STRENGTH
;if = 1 we're dealing with a STV strength value.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;; ; The following code is
used to compute the STy edge strength tolerance.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-
;;;; ;;;;;;;;;;; ldd _stvBaseLine ;get the stv base line value
STV_STRENGTH_LOOP: cpd 0,x ;compare against next edge strength
value bcs SET_POINTERS_1 ;if carry clear new stv strength is
smaller (stronger) ldd 0,x ;get new strength to compare against
(strongest signal so far) SET_POINTERS_1: aix #4 aiy #4 cpy
_HistLblEndPtr+2 jbls STV_STRENGTH_LOOP ; The strongest rtv signal
is in d lde _stvBaseLine ;get stv base line measurement sde ;e =
strongest stv edge xgde ;d = strongest stv edge lsrd ;d = .5
strongest edge lsrd ;d = .25 strongest edge lde _stvBaseLine ;get
stv base line measurement sde ;e = stvBaseLine - .25 of strongest
stv value lsrd ;d = .125 strongest edge sde ;e =
stvBaseLine - .375 of strongest stv value = stv threshold ste
_strengthThreshold ;store stv threshold for use by histogram rts
;done ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-
;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;; ; The following code is
used to compute the RTV edge strength tolerance.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-
;;;; ;;;;;;;;;;; GET_RTV_STRENGTH: ldd _rtvBaseLine ;get the rtv
base line value RTV_STRENGTH_LOOP: cpd 0,x ;compare against next
edge strength value bcc SET_POINTERS_2 ;if carry set new rtv
strength is larger (stronger) ldd 0,x ;get new strength to compare
against (strongest signal so far) SET_POINTERS_2: aix #4 aiy #4 cpy
_HistLblEndPtr+2 jbls RTV_STRENGTH_LOOP ; The strongest rtv signal
is in d subd _rtvBaseLine ;d = strongest edge lsrd ;d = .5
strongest edge lsrd ;d = .25 strongest edge lde _rtvBaseLine ;get
rtv base line measurement ade ;e = rtvBaseLine + .25 of strongest
rtv value lsrd ;d = .125 strongest edge ade ;e = rtvBaseLine + .375
of strongest rtv value = rtv threshold ste _strengthThreshold
;store rtv threshold for use by histogram rts ;done .else
* * * * *