'How to increase speed of video playback within Python using openCV [duplicate]

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!



Solution 1:[1]

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

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1