pythonでWEBカメラを使ってバーコードを読み取る


ウェブカメラでぴぴっとAmazon中古価格相場とか調べることができたら不要本の処分がはかどりそうだということで適当に実装してみた。



を読み取ると、




left side character(1) not found: 1111111
left side character(1) not found: 1111111
left side character(1) not found: 1111111
left side character(1) not found: 1111111
9784873113364

バーコード(JANコード)の規格は
http://www.barcode.ne.jp/about_barcode/code/jan.html
に詳しい。必要なことは全部書いてある。


ハマったところ

  • VideoCaptureがNullを返す OR 真っ黒な画像を返すことがある
    cam = VideoCapture.Device(devnum=deviceNumber)
    cam.setResolution(640, 480)
    cam.getImage()
    time.sleep(1)
    
    img = None
    while True:
        img = cam.getImage()
        if None != img:
            break
        time.sleep(1)

みたいに対処した。

  • WEBカメラの性能がプアすぎてどうにもこうにも

適当な本のバーコード部分を拡大コピーして対処。画像でバーコード部分の上にハサミが置いてあるのはコピー故にたわむのを押さえている…。




コードべたっと貼り付け。
ちょーっと手抜き過ぎですな。実際に使うときはもちっとまじめにやらないといけない。

# -*- coding: utf-8 -*-

import math
import PIL
import Image
import ImageEnhance
import VideoCapture
import time

#settings
deviceNumber = 0
height = 800
width  = 600

cdic_odd =   {'0001101': 0,
              '0011001': 1,
              '0010011': 2,
              '0111101': 3,
              '0100011': 4,
              '0110001': 5,
              '0101111': 6,
              '0111011': 7,
              '0110111': 8,
              '0001011': 9}

cdic_even =  {'0100111': 0,
              '0110011': 1,
              '0011011': 2,
              '0100001': 3,
              '0011101': 4,
              '0111001': 5,
              '0000101': 6,
              '0010001': 7,
              '0001001': 8,
              '0010111': 9}

cdic_right = {'1110010': 0,
              '1100110': 1,
              '1101100': 2,
              '1000010': 3,
              '1011100': 4,
              '1001110': 5,
              '1010000': 6,
              '1000100': 7,
              '1001000': 8,
              '1110100': 9}

pdic       = {'OOOOOO': 0,
              'OOEOEE': 1,
              'OOEEOE': 2,
              'OOEEEO': 3,
              'OEOOEE': 4,
              'OEEOOE': 5,
              'OEEEOO': 6,
              'OEOEOE': 7,
              'OEOEEO': 8,
              'OEEOEO': 9}

def getJAN(img, threthold):
    width  = img.size[0]
    height = img.size[1]
    
    h = (height / 2)
    
    line = []
    
    for i in xrange(width):
        v = img.getpixel( (i, h) )
        v = float(255 - v) / 255
        line.append(v)
    
    for i in xrange( len(line) ):
        if 0.98 < line[i]:
            del line[:i]
            break
    
    lineLen = len(line)
    for i in xrange(lineLen):
        if 0.98 < line[lineLen - i - 1]:
            del line[lineLen - i:]
            break
    
    rate = float(len(line) - 1) / 95
    temp = []
    for i in xrange(95):
        start = i * rate
        end   = start + rate
        val = 0
        for j in xrange( int(math.ceil(start)), int(end) ):
            val += line[j]
        p = start - int(start)
        if 0 < p:
            val += line[int(start)] *  (1 - p)
        p = end   - int(end)
        if 0 < p:
            val += line[int(end)]   * p
        temp.append(val)
    line = temp
    
    temp = []
    for i in line:
        if rate * threthold < i:
            temp.append(1)
        else:
            temp.append(0)
    line = temp
    
    OE   = ''
    left = []
    for i in xrange(1, 7):
        v = ''
        sPos = 3 + ( (i - 1) * 7)
        for j in xrange(sPos, sPos + 7):
            v += str(line[j])
        if cdic_even.has_key(v):
            OE += 'E'
            left.append(cdic_even[v])
        elif cdic_odd.has_key(v):
            OE += 'O'
            left.append(cdic_odd[v])
        else:
            raise Exception('left side character(%s) not found: %s' % (i, v) )
    if pdic.has_key(OE):
        left.insert(0, pdic[OE])
    else:
        raise Exception('prefix character not found: %s' % OE)
    
    right = []
    for i in xrange(1, 6):
        v = ''
        sPos = 50 + ( (i - 1) * 7)
        for j in xrange(sPos, sPos + 7):
            v += str(line[j])
        if cdic_right.has_key(v):
            right.append(cdic_right[v])
        else:
            raise Exception('right side character(%s) not found: %s' % (i, v) )
        
    JAN = left + right
    oddSum  = 0
    evenSum = 0
    for i in xrange(len(JAN)):
        if 0 == i % 2:
            evenSum += JAN[i]
        else:
            oddSum  += JAN[i]
    
    CC = int( str( (oddSum * 3) + evenSum )[-1] )
    if CC < 10:
        CC = 10 - CC
    else:
        CC = 0
    
    for i in xrange(1, 1):
        v = ''
        sPos = 115 + ( (i - 1) * 7)
        for j in xrange(sPos, sPos + 7):
            v += str(line[j])
        if ( not cdic_right.has_key(v) ) or (cdic_right[v] != CC):
            raise Exception('modular check error: %s' % v)
    
    JAN.append(CC)
    JANStr = ''
    for i in JAN:
        JANStr += `i`
    return JANStr

lastJAN = None
def capture():
    
    cam = VideoCapture.Device(devnum=deviceNumber)
    cam.setResolution(640, 480)
    cam.getImage()
    time.sleep(1)
    
    img = None
    while True:
        img = cam.getImage()
        if None != img:
            break
        time.sleep(1)
    
    #img = Image.open('test.jpg')
    img = img.resize( (height, width), PIL.Image.ANTIALIAS )

    #img.save('preview1.jpg')
    img = img.convert("L")
    enhancer = ImageEnhance.Brightness(img)
    img = enhancer.enhance(1.6)
    enhancer = ImageEnhance.Contrast(img)
    img = enhancer.enhance(1.8)
    #img.save('preview2.jpg')


    for i in xrange(10):
        try:
            JAN = getJAN(img, 0.3 + (0.05 * i) )
        except Exception, e:
            print e
            continue
        global lastJAN
        if JAN == lastJAN:
            return
        lastJAN = JAN
        return JAN
    
def main():
    while True:
        JAN = capture()
        if JAN:
            print JAN
        break

if __name__ == "__main__":
    main()