A comprehensive template project for pulling video from a camera using OpenCV and GStreamer, designed to process and analyze each frame in a multi-threaded environment safely.
- Prerequisites
- Build Instructions
- Run Instructions
- Configuration
- Project Structure
- Usage Example
- License
- OpenCV
- GStreamer
- CMake
- spdlog
- fmt
Ensure you have these libraries installed on your system before proceeding with the build instructions.
-
Clone the repository:
git clone https://github.com/itzikChaver/OpenCV-GStreamer-template.git cd OpenCV-GStreamer-template
-
Create a build directory:
mkdir build cd build
-
Run CMake to configure the project:
cmake ..
-
Build the project:
make
-
Ensure your camera is connected and the device is correctly specified in
config/decklink_pipeline.txt
. -
Run the executable:
```sh ./OpenCV_GStreamer_template ```
- The project will run and use the default pipeline found in the gstreamer_pipeline.txt file, it can be changed to draw from a camera connected to the computer (for example a webcam).
```sh ./OpenCV_GStreamer_template <input_name> [camera_number] ```
<input_name>
: The name of the input source (The name of the company that produces the capture card).[camera_number]
: The camera number to be used for Decklink capture.
```sh ./OpenCV_GStreamer_template <video_file_name> ```
<video_file_name>
: The name of the video file source.
```sh ./OpenCV_GStreamer_template <image_file_name> ```
<image_file_name>
: The name of the image file source.
The GStreamer pipeline configuration for decklink capture card is stored in config/decklink_pipeline.txt
.
Default GStreamer pipeline. Example:
videotestsrc pattern=ball ! videoconvert ! video/x-raw, format=BGR ! appsink
The project is organized into several classes, each handling a specific part of the process:
- ArgumentParser: Handles parsing and validation of command-line arguments.
- PipelineCreator: Manages the creation of GStreamer pipelines for video capture.
- VideoProcessor: Processes video frames, including displaying and analyzing each frame.
- VideoCapture: Processes video capture, managing video capture.
argument_parser.h
andargument_parser.cpp
pipeline_creator.h
andpipeline_creator.cpp
video_processor.h
andvideo_processor.cpp
video_capture.h
andvideo_capture.cpp
Here is an example of how to integrate image analytics in the video processing loop. Assume you have an image analytics function analyzeImage
:
void analyzeImage(const cv::Mat& image)
{
// Perform your image analysis here
cv::Mat result = image.clone(); // Example of processing
// ... Your analytics code ...
cv::imshow("Analytics Result", result);
}
In the processVideo
function of VideoProcessor
, you can integrate the image analytics function:
void VideoProcessor::processVideo(cv::VideoCapture &videoCapture, cv::VideoWriter &writer, std::atomic<bool> &stopProgram) {
cv::Mat frame;
while (!stopProgram.load())
{
auto start_time = std::chrono::high_resolution_clock::now();
if (!videoCapture.read(frame)) {
if (videoCapture.get(cv::CAP_PROP_POS_FRAMES) >= videoCapture.get(cv::CAP_PROP_FRAME_COUNT)) {
spdlog::info("Video playback completed.");
} else {
spdlog::error("Unable to read frame from video capture");
}
break;
}
auto read_time = std::chrono::high_resolution_clock::now();
// Update global image for multi-threaded access
GlobalImage::updateImage(frame);
// Process and display image
processAndDisplayImage(frame, writer);
// Analyze image in a separate thread
std::thread analysisThread([]() {
cv::Mat image = GlobalImage::getImage();
analyzeImage(image);
});
analysisThread.detach();
auto process_time = std::chrono::high_resolution_clock::now();
auto read_duration = std::chrono::duration_cast<std::chrono::milliseconds>(read_time - start_time);
auto process_duration = std::chrono::duration_cast<std::chrono::milliseconds>(process_time - read_time);
auto total_duration = std::chrono::duration_cast<std::chrono::milliseconds>(process_time - start_time);
spdlog::info("Read time: {} ms, Process time: {} ms, Total time: {} ms", read_duration.count(), process_duration.count(), total_duration.count());
if (cv::waitKey(30) >= 0) {
break;
}
}
}
This project is licensed under the MIT License - see the LICENSE file for details.