1

I am currently working on a project which makes use of a Raspberry Pi and its Camera Module v2.1.

I need to scan some barcodes with the camera of which I am using the OpenCV and pyzbar libraries.

I am running into some trouble with the image that OpenCV is returning, example below:

Image returned from running libcamera-hello: libcamera image

Image returned from running my script: script image

As you can see the images are very different, the OpenCV image is more zoomed in.

I've tried resizing the image and even changing the size of the frame but it doesn't seem to help, the image just gets stretched!

Does anyone have any ideas on why this might be happening?

My script for capturing the images is below:

import cv2
from pyzbar import pyzbar
from gpiozero import Button

from readBarcodeData import read_text

button = Button(25)

def read_barcodes(frame):
    barcodes = pyzbar.decode(frame)
    for barcode in barcodes:
        x, y , w, h = barcode.rect
        barcode_info = barcode.data.decode('utf-8')
        cv2.rectangle(frame, (x, y),(x+w, y+h), (0, 255, 0), 2)

        with open("barcode_result.txt", mode ='w') as file:
            file.write(str(barcode_info).replace("'", ""))
        

    return frame


def main():
    while True:
        if button.is_pressed:
            camera = cv2.VideoCapture(0)
            ret, frame = camera.read()
            
            while ret:
                ret, frame = camera.read()
                frame = read_barcodes(frame)
                cv2.imshow('Barcode Scanner', frame)
                if cv2.waitKey(0) & 0xFF == 27:
                    break
                break
                
            camera.release()
            cv2.destroyAllWindows()
            read_text()
        

if __name__ == '__main__':
    main()


EDIT: I have also tried capturing an image using the following code:

import cv2

vid = cv2.VideoCapture(0)
  
while(True):
      
    # Capture the video frame
    ret, frame = vid.read()
  
    # Display the resulting frame
    cv2.imshow('frame', frame)
      
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
  
# After the loop release the cap object
vid.release()
# Destroy all the windows
cv2.destroyAllWindows()

But I still get a cropped image.

EDIT 2: Returned properties from the video capture:

CV_CAP_PROP_FRAME_WIDTH: '640.0'
CV_CAP_PROP_FRAME_HEIGHT : '480.0'
[ WARN:0] global /tmp/pip-wheel-j62hpwu1/opencv-python_19cf39855c924932a2df50dd2b502cd2/opencv/modules/videoio/src/cap_v4l.cpp (1911) getProperty VIDEOIO(V4L2:/dev/video0): Unable to get camera FPS
CAP_PROP_FPS : '-1.0'
CAP_PROP_POS_MSEC : '911170.05'
CAP_PROP_FRAME_COUNT  : '-1.0'
CAP_PROP_BRIGHTNESS : '-1.0'
CAP_PROP_CONTRAST : '-1.0'
CAP_PROP_SATURATION : '-1.0'
CAP_PROP_HUE : '-1.0'
CAP_PROP_GAIN  : '-1.0'
CAP_PROP_CONVERT_RGB : '1.0'
ATN
  • 107
  • 1
  • 1
  • 11
  • Probably you are cropping the image with line frame = read_barcodes(frame) can you try barcodeImage = read_barcodes(frame) instead? – Micka Dec 23 '21 at 22:34
  • @Micka thanks but that doesn't seem to work. I tried changing the line you suggested and also changing the ```cv2.imshow('Barcode Scanner', frame)``` to include barcodeImage also but it outputs the same crop – ATN Dec 24 '21 at 08:39
  • Sure, because probably read_barcodes(frame) returns the crop... Just imshow frame instead?!! – Micka Dec 24 '21 at 11:12
  • @Micka unfortunately this also returns a cropped/zoomed in image. I tested a regular image capture with no barcode reading code and it still outputs a cropped image, I really have no idea why! – ATN Dec 24 '21 at 15:01
  • What command did you use for `libcamera`? You may be comparing a still photo with a video... different processing pipeline, different resolution, different noise reduction, different compression. – Mark Setchell Dec 24 '21 at 15:24
  • @MarkSetchell I used libcameras ```libcamera-hello -t 0``` command so it was showing video as well – ATN Dec 24 '21 at 15:26
  • Ah sorry, didnt see the read_barcode code at all. Yes, that doesn't crop. Can you print the videocapture properties? Resolution etc. – Micka Dec 24 '21 at 20:28
  • @Micka apologies for the delay in reponse, I have edited my question with some properties I could output. – ATN Dec 30 '21 at 16:55
  • Is your libcamera-hello image 640x480, too? – Micka Dec 30 '21 at 19:26
  • @Micka no the libcamera image seems to shoot at the max camera resolution (1920x1080 for video). I can manually set the resolution of cv2 but it seems to just blow the image up to that resolution rather than take a higher resolution image. – ATN Dec 31 '21 at 09:05
  • How do you set the resolution? – Micka Dec 31 '21 at 09:17
  • Is there any reason why you want to use VideoCapture? Have a look at https://www.pyimagesearch.com/2015/03/30/accessing-the-raspberry-pi-camera-with-opencv-and-python/ they suggest not to use it for the pi camera module. – Micka Dec 31 '21 at 09:20
  • 1
    @Micka I started to use VideoCapture as thats what I was taught, I am starting to use PiCamera now though and have got as far as it taking an image (full size, no crop!). Now trying to get it to read the barcodes, will post back if I manage it! – ATN Dec 31 '21 at 09:32

1 Answers1

0

I managed to "fix" this by using the PiCamera library to capture the image and then run it through cv2:

Code for reading in PiCamera image is below:

import cv2
from time import sleep
from pyzbar import pyzbar
from gpiozero import Button
from picamera.array import PiRGBArray
import picamera

from readBarcodeData import read_text

button = Button(25)



def read_barcodes(frame):
    barcodes = pyzbar.decode(frame)
    for barcode in barcodes:
        x, y , w, h = barcode.rect
        barcode_info = barcode.data.decode('utf-8')
        cv2.rectangle(frame, (x, y),(x+w, y+h), (0, 255, 0), 2)

        with open("barcode_result.txt", mode ='w') as file:
            file.write(str(barcode_info).replace("'", ""))
        

    return frame


def main():
    while True:
        if button.is_pressed:
            with picamera.PiCamera() as camera:
                rawCapture = PiRGBArray(camera)
                #camera.resolution = (3280, 2464)
                camera.start_preview()
                #sleep(1)
                camera.capture(rawCapture, format="bgr")
                img = rawCapture.array
            #camera = cv2.VideoCapture(0)
            
            #ret, frame = camera.read()
            ret = True
            
            while ret:
                #ret, frame = img
                frame = read_barcodes(img)
                #cv2.imshow('Barcode Scanner', frame)
                #print(frame.shape)
                #if cv2.waitKey(0) & 0xFF == 27:
                    #break
                break
                
            cv2.destroyAllWindows()
            read_text()
        

if __name__ == '__main__':
    main()


The image captured by PiCamera seems to return the full image with no cropping so works a treat.

ATN
  • 107
  • 1
  • 1
  • 11