1

Getting frame from webcam using opencv, then plotting it. I draw a rectangle in the center of the plot, and then get the selected area and show in another plot (enlarged by interpolation)

import matplotlib.pyplot as plt
import matplotlib.animation as animation

import cv2

boxSize = 150
enlargeBy = 3

def getBoxCoordinates(cap, size):
    width = cap.get(3)
    height = cap.get(4)
    x1 = int(width / 2) - int(size / 2)
    y1 = int(height / 2) - int(size / 2)
    x2 = int(width / 2) + int(size / 2)
    y2 = int(height / 2) + int(size / 2)

    return [(x1, y1), (x2, y2)]

def getBox(cap, boxSize, frame, enlargeBy):
    [(x1, y1), (x2, y2)] = getBoxCoordinates(cap, boxSize);

    # Get pixels in box
    box_img = frame[y1 + 1:y2, x1 + 1:x2]  # +1 cuz it excludes initial pixel interval
    return cv2.resize(box_img, None, fx=enlargeBy, fy=enlargeBy,
                      interpolation=cv2.INTER_LINEAR)  # different interpolation methods

cap = cv2.VideoCapture(0);
ret, frame = cap.read()

figWidth = 20
figHeight = 8
fig = plt.figure(figsize=(figWidth, figHeight))


enlarged = getBox(cap, boxSize, frame, enlargeBy)
[(x1, y1), (x2, y2)] = getBoxCoordinates(cap, boxSize);
cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 0, 255), lineType=1)


video_plot = plt.subplot2grid((figHeight, figWidth), (0, 0), colspan=4, rowspan=4)
video_plot.axis('off')
video_plot.set_title("Camera feed")
video = video_plot.imshow(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))


box_plot = plt.subplot2grid((figHeight, figWidth), (0, 4), colspan=4, rowspan=4)
box_plot.axis('off')
box_plot.set_title("Box")
box = box_plot.imshow(cv2.cvtColor(enlarged, cv2.COLOR_BGR2RGB)) #frame just to start


def updatefig(i):
    ret, frame = cap.read()
    cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 0, 255), lineType=1)

    enlarged = getBox(cap, boxSize, frame, enlargeBy)

    video.set_data(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
    box.set_data(cv2.cvtColor(enlarged, cv2.COLOR_BGR2RGB))

    return [video, box]

ani = animation.FuncAnimation(fig, updatefig, interval=20, frames=200, blit=True)

plt.tight_layout()
plt.show()


cv2.destroyAllWindows()


plt.show()

The weird problem I'm having is that the rectangle that I'm drawing on the frame isn't showing properly: it only shows one or a few of the sides. I've noticed that this changes when the figure dimensions change, e.g. with the code above it shows me the bottom and left sides only, if I change:

figWidth = 10

then I see the bottom, right and top but not the left.

No idea what can exactly is causing this and how to fix.

1 Answer 1

2

The cv2.rectangle is drawn as pixels into the image. Now the problem is that you probably have much more pixels in the image that you can show on screen with the imshow plot. E.g. having 1200 pixels in the cv image, and showing this image on 300 pixels on screen requires matplotlib to interpolate 4 real pixels into 1 screen pixel, giving a 75% chance of loosing the one pixel you'd like to show.

The obvious solution would be to make the line of the rectangle thicker.

cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 0, 255), thickness=3)

This will however have the sideeffect to have the rectangle's line in the zoom-in picture as well:

enter image description here

Therefore, another option may be to draw the rectangle with matplotlib on top of the imshow plot. This rectangle only needs to be drawn once, but needs to be part of the returned list from updatefig.

...
video = video_plot.imshow(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
rectangle = plt.Rectangle((x1,y1), x2-x1, y2-y1, edgecolor="gold", fill=False)
video_plot.add_patch(rectangle)
...

def updatefig(i):
    ret, frame = cap.read()
    enlarged = getBox(cap, boxSize, frame, enlargeBy)
    video.set_data(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
    box.set_data(cv2.cvtColor(enlarged, cv2.COLOR_BGR2RGB))
    return [video, box, rectangle]

enter image description here

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.