Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to increase speed of video playback within Python using openCV

I am writing a program that draws a line on a video where the first pixels of the railing are encountered, my problem is that the video playback is sluggish.

enter image description here Screenshot for reference of what the video looks like. During the video the camera is moved closer but because of the slow speed, I have to wait a few minutes to see the change, but when filming took place, it was moved every few seconds.

I assume the issue is the fact that the for loops are operating on every single frame of the video but I am not sure.

What solution could I implement to speed up my program?

import cv2

cap = cv2.VideoCapture('video.mp4')

while(cap.isOpened()):

    ret, frame = cap.read()
    canny = cv2.Canny(frame, 85, 255)
    height, width = canny.shape

    first_black_array = []

    for x in range(width):
        first_black_pixel_found = 0
        for y in range(height):
            if first_black_pixel_found == 0:
                if canny[y,x] == 255:
                    first_black_array.append(height - y)
                    first_black_pixel_found = 1
                    cv2.line(frame,(x,y),(x,y),(0,255,0),1)

    cv2.imshow('frame',frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

Thanks!

like image 484
Gentem Avatar asked Nov 07 '22 19:11

Gentem


1 Answers

This is the problem...

for x in range(width):
    for y in range(height):
         if canny[y,x] == 255:

Numpy.argmax is the solution...

for x in range(width-1):
    # Slice the relevant column from the image
    # The image 'column' is a tall skinny image, only 1px thick
    column = np.array(canny[:,x:x+1])
    # Use numpy to find the first non-zero value
    railPoint = np.argmax(column)

Full Code:

import cv2, numpy as np, time
# Get start time
start = time.time()
# Read in the image
img = cv2.imread('/home/stephen/Desktop/rail.jpg')[40:,10:-10]
# Canny filter
canny = cv2.Canny(img, 85, 255)
# Get height and width
height, width = canny.shape
# Create list to store rail points
railPoints = []
# Iterate though each column in the image
for position in range(width-1):
    # Slice the relevant column from the image
    # The image 'column' is a tall skinny image, only 1px thick
    column = np.array(canny[:,position:position+1])
    # Use numpy to find the first non-zero value
    railPoint = np.argmax(column)
    # Add the railPoint to the list of rail points
    railPoints.append(railPoint)
    # Draw a circle on the image
    cv2.circle(img, (position, railPoint), 1, (123,234,123), 2)
cv2.imshow('img', img)                      
k = cv2.waitKey(1)
cv2.destroyAllWindows()
print(time.time() - start)

My solution using Numpy took 6ms and your solution took 266ms. rail output

like image 95
Stephen Meschke Avatar answered Nov 14 '22 21:11

Stephen Meschke