TypeError: 'bytes' object cannot be interpreted as an integer

Question:

I use OpenCV to read a barcode and send it to an Arduino via serial communication using package pyserial.
The goal is to make a robotic arm move the object (much like in amazon warehouses).

When sending the bytes it shows this error:

C:UsersarccovenvScriptspython.exe D:PythonpythonProjecttest.py 
Traceback (most recent call last):
  File "D:PythonpythonProjecttest.py", line 45, in <module>
    img = decode(img)
          ^^^^^^^^^^^
  File "D:PythonpythonProjecttest.py", line 19, in decode
    ser.write (a)
  File "C:UsersarccovenvLibsite-packagesserialserialwin32.py", line 310, in write
    data = to_bytes(data)
           ^^^^^^^^^^^^^^
  File "C:UsersarccovenvLibsite-packagesserialserialutil.py", line 68, in to_bytes
    return bytes(bytearray(seq))
                 ^^^^^^^^^^^^^^
TypeError: 'bytes' object cannot be interpreted as an integer
detected barcode: Decoded(data=b'43770929851162', type='I25', rect=Rect(left=62, top=0, width=694, height=180), polygon=[Point(x=62, y=1), Point(x=62, y=179), Point(x=756, y=180), Point(x=756, y=0)], quality=181, orientation='UP')
Type: I25
Data: b'43770929851162'


Process finished with exit code 1

Code

Code where I tried to send the bytes array to serial.

from pyzbar import pyzbar
import cv2
import serial

ser = serial.Serial("COM3", 9600)

def decode(image):
    # decodes all barcodes from an image
    decoded_objects = pyzbar.decode(image)
    for obj in decoded_objects:
        # draw the barcode
        print("detected barcode:", obj)
        image = draw_barcode(obj, image)
        # print barcode type & data
        print("Type:", obj.type)
        print("Data:", obj.data)
        print()
        a = (bytes([obj.data]))
        ser.write(bytes(a))

    return image


def draw_barcode(decoded, image):
    # n_points = len(decoded.polygon)
    # for i in range(n_points):
    #     image = cv2.line(image, decoded.polygon[i], decoded.polygon[(i+1) % n_points], color=(0, 255, 0), thickness=5)
    # uncomment above and comment below if you want to draw a polygon and not a rectangle
    image = cv2.rectangle(image, (decoded.rect.left, decoded.rect.top),
                            (decoded.rect.left + decoded.rect.width, decoded.rect.top + decoded.rect.height),
                            color=(0, 255, 0),
                            thickness=5)
    return image


if __name__ == "__main__":
    from glob import glob

    barcodes = glob("barcode*.png")
    for barcode_file in barcodes:
        # load the image to opencv
        img = cv2.imread(barcode_file)
        # decode detected barcodes & get the image
        # that is drawn
        img = decode(img)
        # show the image
        cv2.imshow("img", img)
        cv2.waitKey(0)
Asked By: Arcco Playz

||

Answers:

Debug and consult the docs

Let’s do 3 things to solve your issue:

  1. Clarify the output expected from pyzbar’s docs of the decode function.
  2. Debug the existing code by adding print statements for output and types
  3. Clarify the input expected by pyserial’s docs of the write function.

Expected output from pyzbar.decode(image)

pyzbar.decode(image) returns an array of Decoded named-tuples. Each tuple has an attribute named data which contains bytes like b'some bytes'. An example of the returned objects can be seen in the project’s GitHub README in section Example Usage.

See also What does the 'b' character do in front of a string literal?.

Debugging details

So in your code the following debug printing output of obj.data should look similar to b'...' (bytes) and type(obj.data) should be printed as <class 'bytes'>:

# debug output
print(obj.data)
print(type(obj.data))

For the obj of type Decoded your given output shows the attribute data to have type bytes (denoted by prefix "b"). So apparently the decoded data contains as sequence of digits, a barcode of type I25 for Interleaved 2 of 5:

Decoded(data=b'43770929851162', type='I25',

Expected input for pyserial’s write(data)

The method write(data) accepts

Write the bytes data to the port. This should be of type bytes (or compatible such as bytearray or memoryview). Unicode strings must be encoded (e.g. 'hello'.encode('utf-8').

Changed in version 2.5: Accepts instances of bytes and bytearray when available (Python 2.6 and newer) and str otherwise.

So following example should work, since it passes bytes to the function:

ser.write(b'bytes')

Issues

Let’s analyze your faulty lines:

a = (bytes([obj.data]))  # obsolete conversion

# your first attempt
ser.write(bytes(a))  # raises TypeError

# also your second attempt
ser.write(a.encode())  # raises AttributeError

Given obj.data is of needed type bytes already, then:

  1. [obj.data] is a list of bytes
  2. bytes([obj.data]) raises:

    TypeError: ‘bytes’ object cannot be interpreted as an integer

  3. in your first attempt bytes(a) is equivalent with bytes( (bytes([obj.data])) ) which seems a bit obsolete
  4. in your second attempt of passing a.encode() as argument to the write function you got an error. The encode function only works on string. But a is a list, so the statement a.encode() raises this AttributeError.

In Python’s interactive REPL you can reproduce each error, try out:

  • bytes([bytes()]) for the first TypeError
  • list().encode() for the second AttributeError

Solution

for obj in pyzbar.decode(image):
    ser.write(obj.data)  # assume obj.data is of type bytes

See also

Related questions:

Answered By: hc_dev
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.