0

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:\Users\arcco\venv\Scripts\python.exe D:\Python\pythonProject\test.py 
Traceback (most recent call last):
  File "D:\Python\pythonProject\test.py", line 45, in <module>
    img = decode(img)
          ^^^^^^^^^^^
  File "D:\Python\pythonProject\test.py", line 19, in decode
    ser.write (a)
  File "C:\Users\arcco\venv\Lib\site-packages\serial\serialwin32.py", line 310, in write
    data = to_bytes(data)
           ^^^^^^^^^^^^^^
  File "C:\Users\arcco\venv\Lib\site-packages\serial\serialutil.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)
Arcco Playz
  • 23
  • 1
  • 6
  • Welcome to SO! Please [edit] and paste the **complete error-output (incl. stack trace)** and comment in your code, where the error originates. What was your **research here on SO?** I found similar [python 3.x - python3 pySerial TypeError: unicode strings are not supported, please encode to bytes](https://stackoverflow.com/questions/35642855/python3-pyserial-typeerror-unicode-strings-are-not-supported-please-encode-to) – hc_dev Dec 13 '22 at 16:51
  • Please add debugging-info, e.g. what is the type / output of `print("Type of Decoded.data:", type(obj.data))` ? Then research what types are accepted by method `pyserial.write()` ? – hc_dev Dec 13 '22 at 17:02
  • Hi, I am new to SO. I have updated it with the entire error-output. The methods in the forum have already been tried but didn't work. Hope this helps. Can you please elaborate about how to add the type of decoded data. Thanks in advance – Arcco Playz Dec 13 '22 at 17:07
  • `a = (bytes([obj.data]))` are the `[` brackets necessary here? That could be what's causing the error `TypeError: 'bytes' object cannot be interpreted as an integer` – kconsiglio Dec 13 '22 at 17:51
  • @ArccoPlayz Thanks for the error-output. But now you updated the code to `ser.write (a.encode())`, to that the title with original TypeError does not fit anymore. – hc_dev Dec 13 '22 at 18:27
  • Thanks for improving your question according to [ask]. Now, please [edit] to make sure that title, error (either TypeError or AttributeError) and code all fit together. Out of curiosity: Is it a [vinyl record](https://www.barcodelookup.com/43770929851162) that you scanned ️ – hc_dev Dec 13 '22 at 19:35
  • Thank you for your response. I have in fact corrected the error output with the one that shows TypeError. It indeed is a vinal record. – Arcco Playz Dec 14 '22 at 07:31

1 Answers1

1

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:

hc_dev
  • 8,389
  • 1
  • 26
  • 38