Professional Documents
Culture Documents
Barcodes
Barcodes
Aug 29 2007 2
• Code39 (Sometimes called 3 from 9) barcodes use 9 bars
to represent each symbol.
• The bars can be black or white.
• The bars are either narrow or wide.
• Wide bars must be 2.1 to 3 times larger than narrow bars.
• Each symbol pattern starts and ends with a black bar.
• A valid barcode starts and ends with the STAR (*) symbol,
which is used as a delimiter.
Aug 29 2007 3
• Code39 (Sometimes called 3 from 9) barcodes use 9 bars
to represent each symbol.
• The bars can be black or white.
• The bars are either narrow or wide.
• Wide bars must be 2.1 to 3 times larger than narrow bars.
• Each symbol pattern starts and ends with a black bar.
• A valid barcode starts and ends with the STAR (*) symbol,
which is used as a delimiter.
Aug 29 2007 4
• How many bars is in a barcode that encodes 3 symbols?
• Although each symbol pattern starts and ends with a black
bar, patterns must be separated by a white bar (typically
narrow), so each symbol except the last is represented
with 10 bars in total. (The last symbol has 9 bars, and
does not need a separator after it.)
• Don't forget the Start and Stop symbol!
Aug 29 2007 5
• How many bars is in a barcode that encodes 3 symbols?
• Although each symbol pattern starts and ends with a black
bar, patterns must be separated by a white bar (typically
narrow), so each symbol except the last is represented
with 10 bars in total. (The last symbol has 9 bars, and
does not need a separator after it.)
• Don't forget the Start and Stop symbol!
Aug 29 2007 6
All of the symbol patterns:
Aug 29 2007 9
It's sort of messy!
Aug 29 2007 10
Step 1: Lets clean it up!
Aug 29 2007 11
Step 1: Lets clean it up!
Aug 29 2007 12
Threshold Code
Aug 29 2007 13
Threshold Code
def threshold(pic):
for i in getPixels(pic):
g = getGreen(i)
if( g < 127):
setRed(i,0)
setGreen(i,0)
setBlue(i,0)
else:
setRed(i,255)
setGreen(i,255)
setBlue(i,255)
return(pic)
Aug 29 2007 14
Threshold Code: How to improve it!
Aug 29 2007 15
Now what?
Aug 29 2007 16
Now what?
Aug 29 2007 17
Our Image:
X=255
X=0 Width = 256
Y=0
Height =
192
Y=191
Aug 29 2007 18
Our Image: Middle
X=255
X=0 Width = 256
Y=0
Middle =
Height = Height / 2
192
Y=191
Aug 29 2007 19
Code to save pixel values along a horizontal scanline:
def makeScanLine(bwPic):
return(values)
Aug 29 2007 20
Code to save pixel values along a horizontal scanline:
def makeScanLine(bwPic):
height = getHeight(bwPic)
mid = height // 2
width = getWidth(bwPic)
values = []
for x in range(0, width):
pix = getPixel(bwPic, x, mid)
val = getGreen(pix)
values.append(val)
return(values)
Aug 29 2007 21
Example Scanline Data:
[0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 255, 255,
255, 255, 255, 255, 255, 255, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255,
255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 255, 255, 255,
255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255,
255, 255, 255, 255, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0,
0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 255, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0,
0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255,
255, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 255, 255,
255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0,
0, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255]
Note the large runs of white at the beginning and end of the barcode!
Aug 29 2007 22
How to improve our data?
• Scanline data presents the raw pixel data, but it's not very
easy to understand.
• Lets scan for “runs” of pixels of the same color.
• Convert this:
[0,0, 255,255,255,255,255, 0,0, 255,255, 0,0,0,0, 255,255,
0,0,0,0, 255,255, 0,0,0,0]
Aug 29 2007 23
How to improve our data?
• Scanline data presents the raw pixel data, but it's not very
easy to understand.
• Lets scan for “runs” of pixels of the same color.
• Convert this:
[0,0, 255,255,255,255,255, 0,0, 255,255, 0,0,0,0, 255,255,
0,0,0,0, 255,255, 0,0,0,0]
to this:
[ (2,0), (5,255), (2,0), (2,255), (4,0), (2,255), (4,0), (2,255),
(2,0)]
Aug 29 2007 24
How to improve our data?
• Scanline data presents the raw pixel data, but it's not very
easy to understand.
• Lets scan for “runs” of pixels of the same color.
• Convert this:
[0,0, 255,255,255,255,255, 0,0, 255,255, 0,0,0,0, 255,255,
0,0,0,0, 255,255, 0,0,0,0]
to this:
[ (2,0), (5,255), (2,0), (2,255), (4,0), (2,255), (4,0), (2,255),
(2,0)]
Which could be read as:
“bWbwBwBwb”
Aug 29 2007 25
Code to spot runs of the same color
def parseScanline(scanLine):
return(barData)
Aug 29 2007 26
Code to spot runs of the same color
def parseScanline(scanLine):
barData = []
previous = scanLine[0]
length = 0
Aug 29 2007 27
Don't forget to record the last run!
def parseScanline(scanLine):
barData = []
previous = scanLine[0]
length = 0
Aug 29 2007 29
Some real data!
Aug 29 2007 30
Some real data! With real-world problems!
• Wait! What's that black bar doing at the front of our image
(2,0) before all that white space (26,255)?
Aug 29 2007 31
Some real data!
• Wait! What's that black bar doing at the front of our image
(2,0) before all that white space (26,255)?
Zoom in:
Aug 29 2007 32
Some real data!
Zoom in:
Aug 29 2007 33
Another problem!
• Wait! What are those single pixel black and white bars
doing in the middle of our image?
• Actual scanline data:
[ (2, 0), (26, 255), (3, 0), (8, 255), (3, 0), (3, 255), (8, 0),
(4, 255), (8, 0), (4, 255), (2, 0), (4, 255), (8, 0), (4, 255),
(4, 0), (8, 255), (2, 0), (4, 255), (4, 0), (4, 255), (8, 0),
(2, 255), (1, 0), (1, 255), (6, 0), (4, 255), (4, 0), (8, 255),
(8, 0), (4, 255), (2, 0), (4, 255), (4, 0), (4, 255), (2, 0),
(8, 255), (4, 0), (4, 255), (8, 0), (4, 255), (7, 0), (3, 255),
(4, 0), (39, 255) ]
Aug 29 2007 34
Another problem!
• Wait! What are those single pixel black and white bars
doing in the middle of our image?
• Actual scanline data:
[ (2, 0), (26, 255), (3, 0), (8, 255), (3, 0), (3, 255), (8, 0),
(4, 255), (8, 0), (4, 255), (2, 0), (4, 255), (8, 0), (4, 255),
(4, 0), (8, 255), (2, 0), (4, 255), (4, 0), (4, 255), (8, 0),
(2, 255), (1, 0), (1, 255), (6, 0), (4, 255), (4, 0), (8, 255),
(8, 0), (4, 255), (2, 0), (4, 255), (4, 0), (4, 255), (2, 0),
(8, 255), (4, 0), (4, 255), (8, 0), (4, 255), (7, 0), (3, 255),
(4, 0), (39, 255) ]
Zoom in:
Aug 29 2007 35
Another problem!
Zoom in:
Aug 29 2007 36
Code to remove single pixel errors:
• We want:
[ (4, 255), (8, 0), (2, 255), (6, 0), (4, 255) ]
Aug 29 2007 37
Code to remove single pixel errors:
def removeSingles(barData):
return(newBarData)
Aug 29 2007 38
Code to remove single pixel errors:
def removeSingles(barData):
newBarData =[]
for item in barData:
length = item[0]
if (length != 1):
newBarData.append(item)
return(newBarData)
Aug 29 2007 39
Good data, but how to find Wide and Narrow bars?
[(2, 0), (26, 255), (3, 0), (8, 255), (3, 0), (3, 255), (8, 0), (4, 255), (8, 0), (4, 255),
(2, 0), (4, 255), (8, 0), (4, 255), (4, 0), (8, 255), (2, 0), (4, 255), (4, 0), (4, 255),
(8, 0), (2, 255), (6, 0), (4, 255), (4, 0), (8, 255), (8, 0), (4, 255), (2, 0), (4, 255),
(4, 0), (4, 255), (2, 0), (8, 255), (4, 0), (4, 255), (8, 0), (4, 255), (7, 0), (3, 255),
(4, 0), (255, 39)]
[2, 26, 3, 8, 3, 3, 8, 4, 8, 4, 2, 4, 8, 4, 4, 8,
2, 4, 4, 4, 8, 2, 6, 4, 4, 8, 8, 4, 2, 4, 4, 4, 2,
8, 4, 4, 8, 4, 7, 3, 4, 39]
Aug 29 2007 40
Good data, but how to find Wide and Narrow bars?
Aug 29 2007 41
Good data, but how to find Wide and Narrow bars?
Aug 29 2007 42
Good data, but how to find Wide and Narrow bars?
Aug 29 2007 45
Code to find the width threshold:
def calculateWidthThreshold(barData):
return( threshold )
Aug 29 2007 46
Code to find the width threshold:
def calculateWidthThreshold(barData):
#Load just the widths!
barWidths = []
for x in barData:
barWidths.append(x[0])
barWidths.sort()
#Find the size of a narrow bar!
medianIdx = len(barWidths) // 2
narrowSize= barWidths[medianIdx]
#Go to the 3/4 point, find the size of a wide bar!
wideIdx = medianIdx + (medianIdx // 2)
wideSize = barWidths[wideIdx]
#Calculate the threshold
dist = (wideSize – narrowSize) // 2
threshold = narrowSize + dist
return( threshold )
Aug 29 2007 47
Decoding the bars!
Aug 29 2007 48
Decoding the bars!
def decodeBars(barData,widthThreshold):
return(barString)
Aug 29 2007 49
Decoding the bars!
def decodeBars(barData,widthThreshold):
barString = ""
for bar in barData:
if(bar[1] == 255): #It's a white bar!
if(bar[0] >= widthThreshold):
#It's a wide white bar!
barString = barString + "W"
else:
#It's a narrow white bar
barString = barString + "w"
else: #It's a black bar!
if(bar[0] >= widthThreshold):
#It's a wide black bar!
barString = barString + "B"
else:
#it's a narrow black bar!
barString = barString + "b"
return(barString)
Aug 29 2007 50
Parsing the barcode string
• Actual barString:
bWbWbwBwBwbwBwbWbwbwBwBwbWBwbw
bwbWbwBwBwbW
• Now we just have to parse this string to find our
barcode!
• All (valid) barcodes start with the pattern:
“bWbwBwBwb” or the “*” symbol
• Lets go looking for it!
Aug 29 2007 51
Parsing the barcode string
• There it is!
bWbWbwBwBwbwBwbWbwbwBwBwbWBw
bwbwbWbwBwBwbW
Aug 29 2007 52
Parsing the barcode string
bWbWbwBwBwbwBwbWbwbwBwBwbWBw
bwbwbWbwBwBwbW
Aug 29 2007 53
Parsing the barcode string
BwbWbwBwBwbwBwbWbwbwBwBwbWBw
bwbwbWbwBwBwbW
• So if we look up “BwbWbwbwB” we can figure
out what our first symbol is!
Aug 29 2007 54
All of the symbol patterns:
code39dict = {
'BwbWbwbwB': "1",
}
answer = code39dict[“BwbWbwbwB”]
print answer
“1”
Our first symbol is a 1!
Aug 29 2007 57
Parsing the barcode string
...wBwbWbwbwBwBwbWBwbwbwbWbwBwB
wbW
• Our second symbol is a “5”
Aug 29 2007 58
Parsing the barcode string
Aug 29 2007 59
Code to find the start symbol!
def findCode39(barString):
Aug 29 2007 60
Code to find the start symbol!
def findCode39(barString):
Aug 29 2007 63