Barcodscanner mit der Web-Cam, tkinter und pyzbar

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
Antworten
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Hallo,

hier ein Barcodescanner.

Code: Alles auswählen

#! /usr/bin/env python
# -*- coding: utf-8

import tkinter as tk
import cv2
from PIL import Image, ImageTk, ImageDraw
from functools import partial
from pyzbar.pyzbar import decode

WIDTH = 320
HEIGHT = 240
DEFAULT_CAM_ID = -1

class BarCodeCam(object):

    PROPID_WIDTH = 3
    PROPID_HEIGHT = 4
    
    def __init__(self, cam_id = DEFAULT_CAM_ID):
        self.cam = cv2.VideoCapture(cam_id)
        if not self.cam.isOpened():
           raise RuntimeError("can not open camera {0!r}".format(
                cam_id))
        self.width = int(self.cam.get(self.PROPID_WIDTH))
        self.height = int(self.cam.get(self.PROPID_HEIGHT))
        self.target_marks = ((self.width / 2 - 200, 
                              self.height / 2, 
                              self.width / 2 - 125, 
                              self.height / 2,
                              4, "blue"),
                             (self.width / 2 + 125, 
                              self.height / 2, 
                              self.width / 2 + 200, 
                              self.height / 2,
                              4, "blue"),
                             (self.width / 2 -200, 
                              self.height / 2 -25, 
                              self.width / 2 - 200, 
                              self.height / 2 + 25,
                              4, "blue"),
                             (self.width / 2 + 200, 
                              self.height / 2 -25, 
                              self.width / 2 + 200, 
                              self.height / 2 + 25,
                              4, "blue"),
                             (self.width / 2 - 125, 
                              self.height / 2 - 125, 
                              self.width / 2 - 125, 
                              self.height / 2 + 125,
                              4, "green"),
                             (self.width / 2 + 125, 
                              self.height / 2 - 125, 
                              self.width/ 2 + 125, 
                              self.height / 2 + 125,
                              4, "green"),
                             (self.width / 2 - 125, 
                              self.height / 2 - 125, 
                              self.width / 2  + 125, 
                              self.height / 2 - 125,
                              4, "green"),
                             (self.width / 2 - 125, 
                              self.height/ 2 + 125, 
                              self.width / 2 + 125, 
                              self.height/ 2 + 125,
                              4, "green"))
                
        self.data = None
            
    @property
    def size(self):
        return self.width, self.height
                
    def __enter__(self):
        return self

    def __exit__(self, *args):
        self.release()
        
    def get_text(self, lang = "deu"):
        return pyocr.tesseract.image_to_string(
                                self.get_image(),
                                lang=lang,
                                builder=pyocr.builders.TextBuilder())
                               
    def get_image(self, border = True):
        self.data = None
        frame = self.get_frame()
        image = Image.frombytes("RGB", 
                                self.size,
                                frame, 
                                "raw", 
                                "BGR")
        image_draw = ImageDraw.Draw(image)
        if border:
            self.draw_target_mark(image_draw)
            
        for barcode in decode(self.get_frame()):
            self.data = barcode.data
            (x, y, w, h) = barcode.rect
            image_draw.rectangle((x, y, x + w, y + h), width = 4, outline="red")
        return image
        
    def draw_target_mark(self, image_draw):
        for line_properities in self.target_marks:
            x_1, y_1, x_2, y_2, width, color = line_properities 
            image_draw.line((x_1, y_1, x_2, y_2), width = width, fill = color)
        
    def get_frame(self):
        state, frame = self.cam.read()
        if not state:
            raise RuntimeError("could not read image")
        else:
            return frame
            
    def release(self):
        self.cam.release()

class OCRCamUI(tk.Frame):
    def __init__(self, parent, bar_code_cam, width, height, 
        update_interval = 20):
        tk.Frame.__init__(self, parent)
        self.parent = parent
        self.bar_code_cam = bar_code_cam
        self.barcode_text = None
        self.width = width
        self.height = height
        self.update_interval = update_interval
        self.after_id = None
        self.tk_image = None
        self.top_level = False
        self.image_label = tk.Label(self)
        self.image_label.pack()
        
    def run(self):
        try:
            tk_image = self.bar_code_cam.get_image().resize((self.width, 
                self.height))
        except RuntimeError:
            self.raise_cam_id_error()
            return
        self.tk_image = ImageTk.PhotoImage(tk_image)
        self.image_label.config(image = self.tk_image)
        if self.bar_code_cam.data and self.top_level == False:
            self.top_level = True
            self.get_data()
        self.after_id = self.after(self.update_interval, self.run)
        
        
    def get_data(self):
        top = tk.Toplevel()
        
        def set_toplevel():
            self.top_level = False
            top.destroy()
            
        top.protocol("WM_DELETE_WINDOW", set_toplevel)
        top.title("BARCODE SCAN")
        text_box=tk.Text(top)
        text_box.pack()
        try:
            text_box.insert(tk.END, self.bar_code_cam.data)
        except RuntimeError as e:
            print(e)
            text_box.insert(tk.END, "NO CAM")
        text_box.tag_config("sel", background = "skyblue")
        text_box.bind("<ButtonRelease-1>", partial(self.paste_to_clipboard, 
                                                   top, 
                                                   text_box))
        
    def paste_to_clipboard(self, top, text_box, event):
        top.clipboard_clear()
        try:
            self.parent.clipboard_append(text_box.get(tk.SEL_FIRST, 
                                                      tk.SEL_LAST))
        except tk.TclError:
            top.title("BARCODE--> NO TEXT SELECTED")
        else:
            top.title("BARCODE--> TEXT COPIED TO CLIPBOARD")
            
    def raise_cam_id_error(self):
        self.after_cancel(self.after_id)
        self.image_label.config(image = "", text = '> NO CAM <', 
            font = 'Arial 60')
        
    def release(self):
        self.after_cancel(self.after_id)
        self.parent.destroy()
        
def main():
    root = tk.Tk()
    root.title("BARCODE CAM")
    root.resizable(0, 0)

    try:
        with BarCodeCam() as bar_code_cam:
            bar_code_cam_ui = OCRCamUI(root, bar_code_cam, WIDTH, HEIGHT)
            bar_code_cam_ui.pack()
            bar_code_cam_ui.run()
            root.protocol("WM_DELETE_WINDOW", bar_code_cam_ui.release)
            root.mainloop()
    except RuntimeError:
        tk.Label(root, text = "can not open camera {0!r}".format(
                DEFAULT_CAM_ID), font = "Arial 20", height = 10).pack()
        root.mainloop()

if __name__ == "__main__":
    main()
Gruß Frank
Antworten