Rope skipping counter application based on OpenCV and PyQt5

Rope skipping counter application based on OpenCV and PyQt5

Introduction

This article will introduce a jump rope counter application based on OpenCV and PyQt5. The program can use a computer camera to detect rope skipping and count the number of skips. This article will introduce the implementation method and implementation details of the program, including the use of background subtraction algorithm and contour detection algorithm.

Background subtraction algorithm

Background subtraction algorithm is a commonly used image processing technique for extracting moving objects from videos captured by static cameras. The algorithm is based on the assumption that the background of the camera is static and the moving object is dynamic. Therefore, by taking the difference between the current frame image and the background frame image, a binary image of the moving target can be obtained.

In this procedure, we used the MOG2 background subtraction algorithm. This algorithm is a background subtraction algorithm based on Gaussian mixture model. It models the gray value of each pixel as a mixture of multiple Gaussian distributions, where each Gaussian distribution represents a different background or foreground region. Whether each pixel belongs to the foreground area is determined by comparing the pixel value of the current frame image with the pixel value of the background model.

Contour detection algorithm

A contour detection algorithm is an algorithm for detecting the contours of objects in an image. In this program, we use the findContours function in OpenCV to detect the contour of the rope skipping action. This function takes a binary image and some parameters, and returns a list of contours. A contour is a series of consecutive points that represent the boundaries of an object. By counting the number of contours, we can determine the number of jumps.

Application implementation

This program uses the Python programming language and the PyQt5 GUI framework. The program interface is divided into two parts: the video display area and the skipping rope counter.

The Video class is the core component of the program, which is responsible for processing the video frames and using the background subtraction algorithm and contour detection algorithm to detect the rope skipping action. The Video class inherits the QThread class, so it can run in a separate thread to avoid blocking the main thread.

The implementation of the program is basically the following steps:

1. Initialize the program interface and Video class.

2. Start the Video thread and start video capture.

3. In each video frame, extract the foreground region using a background subtraction algorithm.

4. Use the contour detection algorithm to detect the contour of the rope skipping action.

5. Count the number of rope skipping and update the counter.

6. Display the video frame on the interface.

7. Wait for the next frame of video and repeat the above steps.

Complete code

import cv2
from PyQt5 import QtCore, QtGui, QtWidgets
import numpy as np

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        # Set the main window properties
        MainWindow. setObjectName("MainWindow")
        MainWindow. resize(800, 600)

        #Add Central Widget
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")

        # Add Widget to display video
        self.video_widget = QtWidgets.QLabel(self.centralwidget)
        self.video_widget.setGeometry(QtCore.QRect(100, 100, 640, 480))
        self.video_widget.setFrameShape(QtWidgets.QFrame.Box)
        self.video_widget.setText("")
        self.video_widget.setAlignment(QtCore.Qt.AlignCenter)
        self.video_widget.setObjectName("video_widget")

        # Add a Label to display the number of skipping ropes
        self.result_label = QtWidgets.QLabel(self.centralwidget)
        self.result_label.setGeometry(QtCore.QRect(275, 30, 250, 50))
        font = QtGui. QFont()
        font. setPointSize(20)
        font. setBold(True)
        font. setWeight(75)
        self.result_label.setFont(font)
        self.result_label.setAlignment(QtCore.Qt.AlignCenter)
        self.result_label.setObjectName("result_label")

        # Set the Central Widget of the main window to self.centralwidget
        MainWindow.setCentralWidget(self.centralwidget)




class MainWindow(QtWidgets. QMainWindow):
    def __init__(self):
        super().__init__()
        # Create the UI object
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        # create video object and connect signal
        self.video = Video(self.ui.video_widget)
        self.video.frame_update.connect(self.ui.video_widget.setPixmap)
        self.video.count_update.connect(self.ui.result_label.setText)

        # start video
        self. video. readFrame()




class Video(QtCore. QObject):
    frame_update = QtCore.pyqtSignal(QtGui.QPixmap)
    count_update = QtCore.pyqtSignal(str)

    def __init__(self, widget):
        super().__init__()
        self.cap = cv2.VideoCapture("jumping rope 2.mp4")
        self.fgbg = cv2.createBackgroundSubtractorMOG2()
        self.count = 0
        self. jumping = False
        self.widget = widget
        self.timer = QtCore.QTimer()

        # connect timer signal
        self.timer.timeout.connect(self.readFrame)

        # read a frame every 100 milliseconds
        self. timer. start(100)

    def readFrame(self):
        ret, frame = self.cap.read()
        if not ret:
            self. timer. stop()
            return

        fgmask = self.fgbg.apply(frame)

        thresh = cv2.threshold(fgmask, 50, 255, cv2.THRESH_BINARY)[1]

        contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        if len(contours) > 0:
            largest_contour = max(contours, key=cv2.contourArea)
            if cv2.contourArea(largest_contour) > 1000:
                if not self. jumping:
                    self. jumping = True
                    self.count += 1
            else:
                self. jumping = False

        cv2.putText(frame, "Count: {}".format(self.count), (10, 50),
                    cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2, cv2.LINE_AA)

        # Convert opencv image format to QPixmap
        h, w, ch = frame.shape
        bytes_per_line = ch * w
        convert_to_Qt_format = QtGui.QImage(frame.data, w, h, bytes_per_line, QtGui.QImage.Format_RGB888)
        p = convert_to_Qt_format.scaled(640, 480, QtCore.Qt.KeepAspectRatio)
        pixmap = QtGui.QPixmap.fromImage(p)

        # Send a new frame signal
        self.frame_update.emit(pixmap)

        # send count signal
        self.count_update.emit("Rope skipping times: %d" % self.count)






if __name__ == "__main__":
    import sys
    app = QtWidgets. QApplication(sys. argv)
    MainWindow = MainWindow()
    MainWindow. show()
    sys. exit(app. exec_())


Detection effect

Conclusion

This article introduces the implementation method and implementation details of a skipping rope counter application based on OpenCV and PyQt5. By using the background subtraction algorithm and the contour detection algorithm, the program can accurately detect the rope skipping action and count the number of rope skipping. This program can be used not only for jump rope counting, but also for other applications that need to detect moving objects.