Search code examples
pythonpandasnumpyopencvcanny-operator

Detect specific coordinates on video code python


So I'm a beginner in this sphere of coding. I've written some code that uses openCV to detect the edges of my bubble thats being blown out.

Video of the bubble

The end result outputs many x and y coordinates, but they're a bit weird and hard to work with and it overall looks like it doesnt match the coordinates that they're supposed to be, maybe I'm wrong.

The thing that I'm trying to do is get 3 points:

  1. Get coordinates of max value of y in every moment of time, so at 1s y is n, at 1.1s y is n1, and so on.

  2. Get the same for the two coordinates of x, so x1 and x2 (the most left and most right coordinates of the edge of the bubble).

import cv2
import numpy as np
import pandas as pd

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

listx = []
listy = []

ret, frame = cap.read()
height, width, _ = frame.shape
x_center, y_center = width // 2, height // 2
x_min, x_max = x_center - 50, x_center + 50
y_min, y_max = y_center - 50, y_center + 50

while ret:
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    edges = cv2.Canny(gray, 50, 150)

    # Find contours
    contours, _ = cv2.findContours(edges.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    for contour in contours:
        for point in contour:
            x, y = point.ravel()
            if x < x_min or x > x_max or y < y_min or y > y_max:
                listx.append(x)
                listy.append(y)
                cv2.drawContours(frame, [contour], -1, (0, 255, 0), 1)

    cv2.imshow('Contours from video', frame)

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

cap.release()

cv2.destroyAllWindows()

min_x = min(listx)
max_x = max(listx)
min_y = min(listy)
max_y = max(listy)

print("Minimum x:", min_x)
print("Maximum x:", max_x)
print("Minimum y:", min_y)
print("Maximum y:", max_y)

data = {'x': listx, 'y': listy}
df = pd.DataFrame(data)

df.to_excel('contours_data.xlsx', index=False)

I tried using pandas to get the time stamps, that didn't work, now the code outputs all x and y values into excel. Please help, I can't seem to get it done.


Solution

  • You can use VideoCapture.get to retrieve some information about frame number (cv2.CAP_PROP_POS_FRAMES) or time (cv2.CAP_PROP_POS_MSEC). You can check additional properties of VideoCaptureProperties.

    Full code:

    import cv2
    import numpy as np
    import pandas as pd
    
    cap = cv2.VideoCapture('bubble_cut_1mov.mov')
    
    listx = []
    listy = []
    listf = []  # HERE, frame number
    listt = []  # HERE, timestamp
    
    ret, frame = cap.read()
    height, width, _ = frame.shape
    x_center, y_center = width // 2, height // 2
    x_min, x_max = x_center - 50, x_center + 50
    y_min, y_max = y_center - 50, y_center + 50
    
    while ret:
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        edges = cv2.Canny(gray, 50, 150)
    
        # Find contours
        contours, _ = cv2.findContours(edges.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    
        for contour in contours:
            for point in contour:
                x, y = point.ravel()
                f = cap.get(cv2.CAP_PROP_POS_FRAMES)  # HERE
                t = cap.get(cv2.CAP_PROP_POS_MSEC)  # HERE
                if x < x_min or x > x_max or y < y_min or y > y_max:
                    listx.append(x)
                    listy.append(y)
                    listf.append(f)  # HERE
                    listt.append(t)  # HERE
                    cv2.drawContours(frame, [contour], -1, (0, 255, 0), 1)
    
        cv2.imshow('Contours from video', frame)
    
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
        ret, frame = cap.read()
    
    cap.release()
    
    cv2.destroyAllWindows()
    
    min_x = min(listx)
    max_x = max(listx)
    min_y = min(listy)
    max_y = max(listy)
    
    print("Minimum x:", min_x)
    print("Maximum x:", max_x)
    print("Minimum y:", min_y)
    print("Maximum y:", max_y)
    
    data = {'f': listf, 't': listt, 'x': listx, 'y': listy}  # HERE
    df = pd.DataFrame(data)
    
    df.to_excel('contours_data.xlsx', index=False)
    

    Output:

    >>> df
                 f             t    x    y
    0          1.0      0.000000  478  610
    1          1.0      0.000000  477  611
    2          1.0      0.000000  473  611
    3          1.0      0.000000  472  612
    4          1.0      0.000000  469  612
    ...        ...           ...  ...  ...
    250139  1449.0  24133.333333  513  623
    250140  1449.0  24133.333333  509  623
    250141  1449.0  24133.333333  508  622
    250142  1449.0  24133.333333  501  622
    250143  1449.0  24133.333333  500  621