Initial commit

This commit is contained in:
ZockerKatze
2025-02-27 16:04:23 +01:00
commit 623051c116
15 changed files with 2041 additions and 0 deletions

137
opencamcpp/CMakeLists.txt Normal file
View File

@@ -0,0 +1,137 @@
cmake_minimum_required(VERSION 3.16)
project(opencam LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
# Add OpenCV directory to CMAKE_PREFIX_PATH
list(APPEND CMAKE_PREFIX_PATH "/usr/local")
# Find Qt5
find_package(Qt5 COMPONENTS
Core
Gui
Widgets
Network
REQUIRED
)
# Find OpenCV
find_package(OpenCV REQUIRED)
message(STATUS "OpenCV version: ${OpenCV_VERSION}")
message(STATUS "OpenCV libraries: ${OpenCV_LIBS}")
message(STATUS "OpenCV include dirs: ${OpenCV_INCLUDE_DIRS}")
# Check for CUDA support in OpenCV
if(";${OpenCV_LIBS};" MATCHES ";opencv_cudaimgproc;")
message(STATUS "OpenCV CUDA support found")
find_package(CUDA REQUIRED)
enable_language(CUDA)
set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};-O3)
add_definitions(-DWITH_CUDA)
set(HAS_CUDA TRUE)
else()
message(STATUS "OpenCV was built without CUDA support. GPU acceleration will be disabled.")
set(HAS_CUDA FALSE)
endif()
# Add source files
add_executable(${PROJECT_NAME}
main.cpp
)
# Link libraries
target_link_libraries(${PROJECT_NAME} PRIVATE
Qt5::Core
Qt5::Gui
Qt5::Widgets
Qt5::Network
${OpenCV_LIBS}
)
if(HAS_CUDA)
target_link_libraries(${PROJECT_NAME} PRIVATE
${CUDA_LIBRARIES}
)
endif()
# Include directories
target_include_directories(${PROJECT_NAME} PRIVATE
${OpenCV_INCLUDE_DIRS}
)
if(HAS_CUDA)
target_include_directories(${PROJECT_NAME} PRIVATE
${CUDA_INCLUDE_DIRS}
)
endif()
# Installation rules
install(TARGETS ${PROJECT_NAME}
RUNTIME DESTINATION bin
COMPONENT applications
)
# Function to safely install a library and its dependencies
function(install_library lib_path)
if(EXISTS "${lib_path}")
file(REAL_PATH "${lib_path}" real_path)
install(FILES "${real_path}"
DESTINATION lib
COMPONENT libraries
)
# Get library dependencies
execute_process(
COMMAND ldd "${real_path}"
OUTPUT_VARIABLE LDD_OUTPUT
)
# Extract and install dependencies
string(REGEX MATCHALL "/[^)]*\\.so[^)]*" DEPS "${LDD_OUTPUT}")
foreach(dep ${DEPS})
if(EXISTS "${dep}" AND NOT "${dep}" MATCHES "^/lib" AND NOT "${dep}" MATCHES "^/usr/lib")
install(FILES "${dep}"
DESTINATION lib
COMPONENT libraries
)
endif()
endforeach()
endif()
endfunction()
# Install OpenCV libraries
foreach(lib ${OpenCV_LIBS})
get_target_property(lib_location ${lib} LOCATION)
if(lib_location)
install_library("${lib_location}")
endif()
endforeach()
# Install Qt plugins
if(Qt5_DIR)
file(GLOB_RECURSE QT_PLUGINS "${Qt5_DIR}/../../../plugins/*.so")
foreach(plugin ${QT_PLUGINS})
get_filename_component(plugin_path "${plugin}" DIRECTORY)
get_filename_component(plugin_dir "${plugin_path}" NAME)
install(FILES "${plugin}"
DESTINATION plugins/${plugin_dir}
COMPONENT plugins
)
endforeach()
endif()
# Print configuration summary
message(STATUS "")
message(STATUS "Configuration Summary")
message(STATUS "--------------------")
message(STATUS "OpenCV version: ${OpenCV_VERSION}")
message(STATUS "CUDA support: ${HAS_CUDA}")
message(STATUS "Qt version: ${Qt5_VERSION}")
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
message(STATUS "C++ compiler: ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}")
message(STATUS "Installation prefix: ${CMAKE_INSTALL_PREFIX}")
message(STATUS "")

View File

@@ -0,0 +1,22 @@
{
"version": 3,
"configurePresets": [
{
"hidden": true,
"name": "Qt",
"cacheVariables": {
"CMAKE_PREFIX_PATH": "$env{QTDIR}"
},
"vendor": {
"qt-project.org/Qt": {
"checksum": "wVa86FgEkvdCTVp1/nxvrkaemJc="
}
}
}
],
"vendor": {
"qt-project.org/Presets": {
"checksum": "67SmY24ZeVbebyKD0fGfIzb/bGI="
}
}
}

View File

@@ -0,0 +1,40 @@
{
"version": 3,
"configurePresets": [
{
"name": "Qt-Debug",
"inherits": "Qt-Default",
"binaryDir": "${sourceDir}/out/build/debug",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_CXX_FLAGS": "-DQT_QML_DEBUG"
},
"environment": {
"QML_DEBUG_ARGS": "-qmljsdebugger=file:{ff00bfed-29c2-47f8-b4aa-00b2873b1a26},block"
}
},
{
"name": "Qt-Release",
"inherits": "Qt-Default",
"binaryDir": "${sourceDir}/out/build/release",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"hidden": true,
"name": "Qt-Default",
"inherits": null,
"vendor": {
"qt-project.org/Default": {
"checksum": "VoalogTkyWuFomeO1TLFx0olLJ4="
}
}
}
],
"vendor": {
"qt-project.org/Presets": {
"checksum": "azRZtZDqJVYwlIJYZufPfOYPwkE="
}
}
}

View File

@@ -0,0 +1,90 @@
#!/bin/bash
# Exit on error
set -e
# Function to copy library and its dependencies
copy_dependencies() {
local binary="$1"
local target_dir="$2"
# Create target directory if it doesn't exist
mkdir -p "$target_dir"
# Get all dependencies
ldd "$binary" | while read -r line; do
# Extract the library path
if [[ $line =~ '=>' ]]; then
lib_path=$(echo "$line" | awk '{print $3}')
else
lib_path=$(echo "$line" | awk '{print $1}')
fi
# Skip system libraries and non-existent files
if [[ -f "$lib_path" && ! "$lib_path" =~ ^/lib && ! "$lib_path" =~ ^/usr/lib ]]; then
cp -L "$lib_path" "$target_dir/"
fi
done
}
# Create AppDir structure
mkdir -p AppDir/usr/{bin,lib,share/applications,share/icons/hicolor/256x256/apps}
# Build the application
mkdir -p build
cd build
cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release
make -j$(nproc)
# Install to AppDir
make DESTDIR=../AppDir install
cd ..
# Copy desktop file and icon
cp opencam.desktop AppDir/usr/share/applications/
cp icon.png AppDir/usr/share/icons/hicolor/256x256/apps/opencam.png
# Copy Qt plugins
mkdir -p AppDir/usr/plugins
for plugin_dir in platforms imageformats xcbglintegrations; do
if [ -d "/usr/lib/x86_64-linux-gnu/qt5/plugins/$plugin_dir" ]; then
cp -r "/usr/lib/x86_64-linux-gnu/qt5/plugins/$plugin_dir" AppDir/usr/plugins/
fi
done
# Copy dependencies for the main executable
copy_dependencies "AppDir/usr/bin/opencam" "AppDir/usr/lib"
# Copy dependencies for Qt plugins
find AppDir/usr/plugins -type f -name "*.so" | while read plugin; do
copy_dependencies "$plugin" "AppDir/usr/lib"
done
# Create AppRun script
cat > AppDir/AppRun << 'EOF'
#!/bin/bash
HERE="$(dirname "$(readlink -f "${0}")")"
export LD_LIBRARY_PATH="${HERE}/usr/lib:${LD_LIBRARY_PATH}"
export QT_PLUGIN_PATH="${HERE}/usr/plugins"
export QT_QPA_PLATFORM_PLUGIN_PATH="${HERE}/usr/plugins/platforms"
exec "${HERE}/usr/bin/opencam" "$@"
EOF
chmod +x AppDir/AppRun
# Download linuxdeploy if not present
if [ ! -f linuxdeploy-x86_64.AppImage ]; then
wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
chmod +x linuxdeploy-x86_64.AppImage
fi
if [ ! -f linuxdeploy-plugin-qt-x86_64.AppImage ]; then
wget https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage
chmod +x linuxdeploy-plugin-qt-x86_64.AppImage
fi
# Create the AppImage
export OUTPUT="OpenCam-x86_64.AppImage"
./linuxdeploy-x86_64.AppImage --appdir AppDir --plugin qt --output appimage
echo "AppImage created successfully: $OUTPUT"

View File

@@ -0,0 +1,83 @@
#!/bin/bash
# Exit on error
set -e
# Function to check CUDA installation
check_cuda() {
if ! command -v nvcc &> /dev/null; then
echo "CUDA not found! Please install CUDA toolkit first."
exit 1
fi
echo "Found CUDA installation: $(nvcc --version | head -n1)"
}
# Function to check GPU
check_gpu() {
if ! command -v nvidia-smi &> /dev/null; then
echo "No NVIDIA GPU found or drivers not installed!"
exit 1
fi
echo "Found GPU: $(nvidia-smi -L)"
}
# Check CUDA and GPU
check_cuda
check_gpu
# Get CUDA compute capability
CUDA_ARCH=$(nvidia-smi --query-gpu=compute_cap --format=csv,noheader)
echo "GPU Compute Capability: $CUDA_ARCH"
# Create build directory
cd ~/opencv_build/opencv
mkdir -p build
cd build
# Configure OpenCV build
cmake -D CMAKE_BUILD_TYPE=RELEASE \
-D CMAKE_INSTALL_PREFIX=/usr/local \
-D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib/modules \
-D WITH_CUDA=ON \
-D WITH_CUDNN=OFF \
-D OPENCV_DNN_CUDA=ON \
-D ENABLE_FAST_MATH=1 \
-D CUDA_FAST_MATH=1 \
-D CUDA_ARCH_BIN=$CUDA_ARCH \
-D WITH_CUBLAS=1 \
-D WITH_TBB=ON \
-D WITH_V4L=ON \
-D WITH_QT=ON \
-D WITH_OPENGL=ON \
-D WITH_GSTREAMER=ON \
-D OPENCV_GENERATE_PKGCONFIG=ON \
-D OPENCV_PC_FILE_NAME=opencv.pc \
-D OPENCV_ENABLE_NONFREE=ON \
-D INSTALL_PYTHON_EXAMPLES=OFF \
-D INSTALL_C_EXAMPLES=OFF \
-D BUILD_EXAMPLES=OFF \
-D BUILD_opencv_cudacodec=OFF \
-D OPENCV_ENABLE_MEMALIGN=ON \
-D WITH_OPENEXR=ON \
-D OPENCV_ENABLE_MEMALIGN=ON \
-D WITH_EIGEN=ON \
-D ENABLE_PRECOMPILED_HEADERS=OFF \
..
# Build using all available CPU cores
make -j$(nproc)
# Install
sudo make install
sudo ldconfig
# Print OpenCV installation information
echo "OpenCV installation completed!"
echo "OpenCV version: $(pkg-config --modversion opencv4)"
echo "Installation location: $(pkg-config --variable=prefix opencv4)"
# Create a pkg-config path file
sudo sh -c 'echo "/usr/local/lib/pkgconfig" > /etc/ld.so.conf.d/opencv.conf'
sudo ldconfig
echo "Setup complete! You can now use OpenCV with CUDA support."

BIN
opencamcpp/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

7
opencamcpp/icon.svg Normal file
View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="256" viewBox="0 0 256 256">
<circle cx="128" cy="128" r="120" fill="#2196F3"/>
<circle cx="128" cy="128" r="90" fill="#1976D2"/>
<circle cx="128" cy="128" r="45" fill="#FFFFFF"/>
<circle cx="128" cy="128" r="25" fill="#1976D2"/>
</svg>

After

Width:  |  Height:  |  Size: 359 B

311
opencamcpp/main.cpp Normal file
View File

@@ -0,0 +1,311 @@
#include <opencv2/opencv.hpp>
#ifdef WITH_CUDA
#include <opencv2/cudaimgproc.hpp>
#include <opencv2/cudawarping.hpp>
#include <opencv2/cudaobjdetect.hpp>
#include <opencv2/cudabgsegm.hpp>
#include <opencv2/cudacodec.hpp>
#include <opencv2/core/cuda.hpp>
#endif
#include <QApplication>
#include <QMainWindow>
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>
#include <QComboBox>
#include <QMessageBox>
#include <QProgressDialog>
#include <QTimer>
#include <QThread>
#include <QString>
#include <QFile>
#include <QProgressBar>
#include <QDialog>
#include <memory>
#include <vector>
#include <string>
#include <thread>
#include <atomic>
#include <queue>
#include <mutex>
#include <condition_variable>
class FrameProcessor : public QThread {
Q_OBJECT
public:
FrameProcessor(QObject* parent = nullptr) : QThread(parent), running(false) {
#ifdef WITH_CUDA
// Initialize CUDA device
cv::cuda::setDevice(0);
stream = cv::cuda::Stream();
#endif
}
void startProcessing() {
running = true;
if (!isRunning()) start();
}
void stopProcessing() {
running = false;
wait();
}
void setNet(cv::dnn::Net& net) {
std::lock_guard<std::mutex> lock(netMutex);
this->net = net;
}
void queueFrame(const cv::Mat& frame) {
std::lock_guard<std::mutex> lock(queueMutex);
frameQueue.push(frame);
condition.notify_one();
}
signals:
void frameProcessed(QImage image);
protected:
void run() override {
while (running) {
cv::Mat frame;
{
std::unique_lock<std::mutex> lock(queueMutex);
condition.wait(lock, [this] { return !frameQueue.empty() || !running; });
if (!running) break;
frame = frameQueue.front();
frameQueue.pop();
}
if (frame.empty()) continue;
#ifdef WITH_CUDA
// GPU processing path
cv::cuda::GpuMat gpuFrame;
gpuFrame.upload(frame, stream);
cv::cuda::GpuMat gpuResized;
cv::cuda::resize(gpuFrame, gpuResized, cv::Size(416, 416), 0, 0, cv::INTER_CUBIC, stream);
// Download for DNN processing (until we implement CUDA DNN)
cv::Mat resized;
gpuResized.download(resized, stream);
#else
// CPU processing path
cv::Mat resized;
cv::resize(frame, resized, cv::Size(416, 416), 0, 0, cv::INTER_CUBIC);
#endif
// Object detection
cv::Mat blob;
cv::dnn::blobFromImage(resized, blob, 1/255.0, cv::Size(416, 416), cv::Scalar(0,0,0), true, false);
{
std::lock_guard<std::mutex> lock(netMutex);
net.setInput(blob);
std::vector<cv::Mat> outs;
net.forward(outs, net.getUnconnectedOutLayersNames());
std::vector<int> classIds;
std::vector<float> confidences;
std::vector<cv::Rect> boxes;
for (const auto& out : outs) {
float* data = (float*)out.data;
for (int j = 0; j < out.rows; ++j, data += out.cols) {
cv::Mat scores = out.row(j).colRange(5, out.cols);
cv::Point classIdPoint;
double confidence;
cv::minMaxLoc(scores, 0, &confidence, 0, &classIdPoint);
if (confidence > 0.5) {
int centerX = (int)(data[0] * frame.cols);
int centerY = (int)(data[1] * frame.rows);
int width = (int)(data[2] * frame.cols);
int height = (int)(data[3] * frame.rows);
int left = centerX - width / 2;
int top = centerY - height / 2;
classIds.push_back(classIdPoint.x);
confidences.push_back((float)confidence);
boxes.push_back(cv::Rect(left, top, width, height));
}
}
}
std::vector<int> indices;
cv::dnn::NMSBoxes(boxes, confidences, 0.5, 0.4, indices);
for (size_t i = 0; i < indices.size(); ++i) {
int idx = indices[i];
cv::Rect box = boxes[idx];
cv::rectangle(frame, box, cv::Scalar(0, 255, 0), 2);
}
}
#ifdef WITH_CUDA
// Convert to RGB on GPU
cv::cuda::GpuMat gpuRGB;
cv::cuda::cvtColor(gpuFrame, gpuRGB, cv::COLOR_BGR2RGB, 0, stream);
cv::Mat rgb;
gpuRGB.download(rgb, stream);
#else
// Convert to RGB on CPU
cv::Mat rgb;
cv::cvtColor(frame, rgb, cv::COLOR_BGR2RGB);
#endif
// Convert to QImage
QImage qimg(rgb.data, rgb.cols, rgb.rows, rgb.step, QImage::Format_RGB888);
emit frameProcessed(qimg.copy());
}
}
private:
std::atomic<bool> running;
#ifdef WITH_CUDA
cv::cuda::Stream stream;
#endif
cv::dnn::Net net;
std::queue<cv::Mat> frameQueue;
std::mutex queueMutex;
std::mutex netMutex;
std::condition_variable condition;
};
class CameraApp : public QMainWindow {
Q_OBJECT
public:
CameraApp(QWidget* parent = nullptr) : QMainWindow(parent) {
setWindowTitle("GPU-Accelerated Object Detection");
setGeometry(100, 100, 1280, 720);
#ifdef WITH_CUDA
// Check CUDA device
int deviceCount = cv::cuda::getCudaEnabledDeviceCount();
if (deviceCount == 0) {
QMessageBox::warning(this, "Warning", "No CUDA capable devices found. Falling back to CPU processing.");
} else {
cv::cuda::printCudaDeviceInfo(0);
}
#endif
setupUI();
initializeObjectDetection();
processor = new FrameProcessor(this);
connect(processor, &FrameProcessor::frameProcessed, this, &CameraApp::updateFrame);
}
~CameraApp() {
stopCamera();
if (processor) {
processor->stopProcessing();
delete processor;
}
}
private slots:
void startCamera() {
if (!cap.isOpened()) {
cap.open(currentCamera);
cap.set(cv::CAP_PROP_FRAME_WIDTH, 1920);
cap.set(cv::CAP_PROP_FRAME_HEIGHT, 1080);
cap.set(cv::CAP_PROP_FPS, 120); // Request maximum FPS
#ifdef WITH_CUDA
// Try to use CUDA video decoder if available
cap.set(cv::CAP_PROP_CUDA_DEVICE, 0);
#endif
if (!cap.isOpened()) {
QMessageBox::critical(this, "Error", "Failed to open camera!");
return;
}
}
processor->startProcessing();
timer->start(0); // Run as fast as possible
}
void stopCamera() {
timer->stop();
processor->stopProcessing();
if (cap.isOpened()) {
cap.release();
}
}
void captureFrame() {
if (!cap.isOpened()) return;
cv::Mat frame;
cap >> frame;
if (frame.empty()) return;
processor->queueFrame(frame);
}
void updateFrame(const QImage& image) {
QPixmap pixmap = QPixmap::fromImage(image);
videoLabel->setPixmap(pixmap.scaled(videoLabel->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
}
private:
void setupUI() {
QWidget* centralWidget = new QWidget(this);
setCentralWidget(centralWidget);
QVBoxLayout* layout = new QVBoxLayout(centralWidget);
videoLabel = new QLabel(this);
videoLabel->setMinimumSize(640, 480);
layout->addWidget(videoLabel);
cameraSelect = new QComboBox(this);
detectCameras();
layout->addWidget(cameraSelect);
startButton = new QPushButton("Start Camera", this);
connect(startButton, &QPushButton::clicked, this, &CameraApp::startCamera);
layout->addWidget(startButton);
stopButton = new QPushButton("Stop Camera", this);
connect(stopButton, &QPushButton::clicked, this, &CameraApp::stopCamera);
layout->addWidget(stopButton);
timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &CameraApp::captureFrame);
}
void detectCameras() {
for (int i = 0; i < 10; ++i) {
cv::VideoCapture temp(i);
if (temp.isOpened()) {
cameraSelect->addItem("Camera " + QString::number(i), i);
temp.release();
}
}
}
void initializeObjectDetection() {
// Download and load YOLO model (implementation similar to Python version)
// ...
}
QLabel* videoLabel;
QComboBox* cameraSelect;
QPushButton* startButton;
QPushButton* stopButton;
QTimer* timer;
cv::VideoCapture cap;
int currentCamera = 0;
FrameProcessor* processor;
};
#include "main.moc"
int main(int argc, char* argv[]) {
QApplication app(argc, argv);
CameraApp window;
window.show();
return app.exec();
}

View File

@@ -0,0 +1,10 @@
[Desktop Entry]
Type=Application
Name=OpenCam
Comment=Real-time object detection using OpenCV and YOLO
Exec=opencam
Icon=opencam
Categories=Graphics;Video;
Keywords=camera;detection;opencv;yolo;
Terminal=false
StartupNotify=true