I'm writing a program that will analyze a video frame-by-frame. The program is supposed to calculate the height of an object that is varying through time. I used the fact that the top of the object is a white color, so I would print out the position of a white pixel to find the position of the top and, from there, measure the height of the object. I was able to write such a program, but the for loop that iterates every frame (about 10,000 frames per video) is lagging behind the whole program. It would take almost a day to come up with the height of the object in each frame. My question is, is there a better and more efficient way to approach this problem?
capture = cv2.VideoCapture("/Users/beadpile/Desktop/aman/bpile.mp4")
_, frame = capture.read()
MovieBase = MovieName
angles=[]
y_base = 247
x_center = 569
x_edgeL = 51
x_edgeR = 1087
for i in range(0,1000):
capture.set(cv2.CAP_PROP_POS_FRAMES, i)
_, frame = capture.read()
white = [255,255,255]
# Get X and Y coordinates of all white color pixels
X,Y = np.where(np.all(frame==white,axis=2))
XX=list(X)
YY=list(Y)
xpoints = np.array(X)
ypoints = np.array(Y)
test_list=list(zip(xpoints,ypoints))
#get x,y coordinate of the white pixels found at the top of the object
subcoords = [(x, y) for x, y in test_list if y==min(YY)]
s=[]
for j in subcoords:
s.append(j[0])
#find average value of the x coordinate of the values coordinates from subcoordds
xax=sum(s)/len(subcoords)
slope=(y_base-min(YY))/(xax-x_edgeL)
#gets angle that extends from one point to the top of the object
aangle=math.degrees(math.atan(slope))
angles.append(aangle)
print(angles)
You assume that the image only has white pixels in the pile, but you have other pixels that are white meanwhile outside of the pile. You have to clean those pixels first.
After you clean those pixels
Your code is slow, because you abandon numpy, by using lists.
This code shows the height and width of the pile, from the cleaned image using only numpy, which is fast, because takes advantage of SIMD in the CPU.
import numpy as np
import requests
import cv2
# Download the image from stackoverflow
#url = "https://i.sstatic.net/y6mbR.jpg" # Original image
url = "https://i.sstatic.net/xLG0M.jpg" # Cleaned image
response = requests.get(url, stream=True)
img_array = np.array(bytearray(response.raw.read()), dtype=np.uint8)
img = cv2.imdecode(img_array, -1)
# Find white pixels
white = np.array([255, 255, 255], dtype=np.uint8)
white_pixels = np.all(img == white, axis=-1)
white_columns = white_pixels.max(axis=0)
white_rows = white_pixels.max(axis=1)
white_rows_indexes = np.where(white_rows == True)[0]
print(f"height of pile = {white_rows_indexes[-1]-white_rows_indexes[0]+1}")
white_column_indexes = np.where(white_columns == True)[0]
print(f"Width of pile = {white_column_indexes[-1]-white_column_indexes[0]+1}")
cv2.imshow('Image', white_pixels.astype(np.uint8)*255)
cv2.waitKey(0)
cv2.destroyAllWindows()