diff --git a/QGCApplication.pro b/QGCApplication.pro index ddea4015aa34b68ddadb8cc01f3591103d03bdd3..08f0eeedd77d57bad01e6a1f90571ca39a678e11 100644 --- a/QGCApplication.pro +++ b/QGCApplication.pro @@ -290,6 +290,7 @@ HEADERS += \ src/comm/QGCJSBSimLink.h \ src/comm/QGCXPlaneLink.h \ src/QGCDockWidget.h \ + src/ui/CameraView.h \ src/ui/HILDockWidget.h \ src/ui/MultiVehicleDockWidget.h \ src/ui/QGCHilConfiguration.h \ @@ -393,6 +394,7 @@ SOURCES += \ src/comm/QGCJSBSimLink.cc \ src/comm/QGCXPlaneLink.cc \ src/QGCDockWidget.cc \ + src/ui/CameraView.cc \ src/ui/HILDockWidget.cc \ src/ui/MultiVehicleDockWidget.cc \ src/ui/QGCHilConfiguration.cc \ diff --git a/src/ui/CameraView.cc b/src/ui/CameraView.cc new file mode 100644 index 0000000000000000000000000000000000000000..635770a19d62e711a1055c796ac37eca6c471217 --- /dev/null +++ b/src/ui/CameraView.cc @@ -0,0 +1,250 @@ +/*===================================================================== + +QGroundControl Open Source Ground Control Station + +(c) 2009, 2010 QGROUNDCONTROL PROJECT + +This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + +======================================================================*/ + +/** + * @file + * @brief Implementation of CameraView + * @author Lorenz Meier + * + */ + +#include "CameraView.h" +#include +#include + +CameraView::CameraView(int width, int height, int depth, int channels, QWidget* parent) : QGLWidget(parent) +{ + rawImage = NULL; + rawBuffer1 = NULL; + rawBuffer2 = NULL; + rawLastIndex = 0; + image = NULL; + imageStarted = false; + // Init to black image + //setImageSize(width, height, depth, channels); + receivedWidth = width; + receivedHeight = height; + receivedDepth = depth; + receivedChannels = channels; + imageId = -1; + + // Fill with black background + QImage fill = QImage(width, height, QImage::Format_Indexed8); + fill.setColorCount(1); + fill.setColor(0, qRgb(70, 200, 70)); + fill.fill(CameraView::initialColor); + glImage = QGLWidget::convertToGLFormat(fill); + + resize(fill.size()); + + // Set size once + setFixedSize(fill.size()); + setMinimumSize(fill.size()); + setMaximumSize(fill.size()); + // Lock down the size + setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); +} + +CameraView::~CameraView() +{ + delete rawImage; + delete image; +} + +void CameraView::addUAS(UASInterface* uas) +{ + // TODO Enable multi-uas support + connect(uas, SIGNAL(imageStarted(int,int,int,int,int)), this, SLOT(startImage(int,int,int,int,int))); + connect(uas, SIGNAL(imageDataReceived(int,const unsigned char*,int,int)), this, SLOT(setPixels(int,const unsigned char*,int,int))); +} + +void CameraView::setImageSize(int width, int height, int depth, int channels) +{ + // Allocate raw image in correct size + if (width != receivedWidth || height != receivedHeight || depth != receivedDepth || channels != receivedChannels || image == NULL) { + // Set new size + if (width > 0) receivedWidth = width; + if (height > 0) receivedHeight = height; + if (depth > 1) receivedDepth = depth; + if (channels > 1) receivedChannels = channels; + + rawExpectedBytes = (receivedWidth * receivedHeight * receivedDepth * receivedChannels) / 8; + bytesPerLine = rawExpectedBytes / receivedHeight; + // Delete old buffers if necessary + rawImage = NULL; + if (rawBuffer1 != NULL) delete rawBuffer1; + if (rawBuffer2 != NULL) delete rawBuffer2; + + rawBuffer1 = (unsigned char*)malloc(rawExpectedBytes); + rawBuffer2 = (unsigned char*)malloc(rawExpectedBytes); + rawImage = rawBuffer1; + // TODO check if old image should be deleted + + // Set image format + // 8 BIT GREYSCALE IMAGE + if (depth <= 8 && channels == 1) { + image = new QImage(receivedWidth, receivedHeight, QImage::Format_Indexed8); + // Create matching color table + image->setColorCount(256); + for (int i = 0; i < 256; i++) { + image->setColor(i, qRgb(i, i, i)); + //qDebug() << __FILE__ << __LINE__ << std::hex << i; + } + + } + // 32 BIT COLOR IMAGE WITH ALPHA VALUES (#ARGB) + else { + image = new QImage(receivedWidth, receivedHeight, QImage::Format_ARGB32); + } + + // Fill image with black pixels + image->fill(CameraView::initialColor); + glImage = QGLWidget::convertToGLFormat(*image); + + qDebug() << __FILE__ << __LINE__ << "Setting up image"; + + // Set size once + setFixedSize(receivedWidth, receivedHeight); + setMinimumSize(receivedWidth, receivedHeight); + setMaximumSize(receivedWidth, receivedHeight); + // Lock down the size + setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); + resize(receivedWidth, receivedHeight); + } + +} + +void CameraView::startImage(int imgid, int width, int height, int depth, int channels) +{ + this->imageId = imgid; + //qDebug() << "CameraView: starting image (" << width << "x" << height << ", " << depth << "bits) with " << channels << "channels"; + + // Copy previous image to screen if it hasn't been finished properly + finishImage(); + + // Reset image size if necessary + setImageSize(width, height, depth, channels); + imageStarted = true; +} + +void CameraView::finishImage() +{ + if (imageStarted) { + commitRawDataToGL(); + imageStarted = false; + } +} + +void CameraView::commitRawDataToGL() +{ + //qDebug() << __FILE__ << __LINE__ << "Copying raw data to GL buffer:" << rawImage << receivedWidth << receivedHeight << image->format(); + if (image != NULL) { + QImage::Format format = image->format(); + QImage* newImage = new QImage(rawImage, receivedWidth, receivedHeight, format); + if (format == QImage::Format_Indexed8) { + // Create matching color table + newImage->setColorCount(256); + for (int i = 0; i < 256; i++) { + newImage->setColor(i, qRgb(i, i, i)); + //qDebug() << __FILE__ << __LINE__ << std::hex << i; + } + } + + glImage = QGLWidget::convertToGLFormat(*newImage); + delete image; + image = newImage; + // Switch buffers + if (rawImage == rawBuffer1) { + rawImage = rawBuffer2; + //qDebug() << "Now buffer 2"; + } else { + rawImage = rawBuffer1; + //qDebug() << "Now buffer 1"; + } + } + paintGL(); +} + +void CameraView::saveImage(QString fileName) +{ + image->save(fileName); +} + +void CameraView::saveImage() +{ + //Bring up popup + QString fileName = "output.png"; + saveImage(fileName); +} + +void CameraView::setPixels(int imgid, const unsigned char* imageData, int length, unsigned int startIndex) +{ + // FIXME imgid can be used to receive and then display multiple images + // the image buffer should be converted into a n image buffer. + Q_UNUSED(imgid); + + // qDebug() << "at" << __FILE__ << __LINE__ << ": Received startindex" << startIndex << "and length" << length << "(" << startIndex+length << "of" << rawExpectedBytes << "bytes)"; + + if (imageStarted) { + //if (rawLastIndex != startIndex) qDebug() << "PACKET LOSS!"; + + if (startIndex+length > rawExpectedBytes) { + qDebug() << "CAMERAVIEW: OVERFLOW! startIndex:" << startIndex << "length:" << length << "image raw size" << ((receivedWidth * receivedHeight * receivedChannels * receivedDepth) / 8) - 1; + } else { + memcpy(rawImage+startIndex, imageData, length); + + rawLastIndex = startIndex+length; + + // Check if we just reached the end of the image + if (startIndex+length == rawExpectedBytes) { + //qDebug() << "CAMERAVIEW: END OF IMAGE REACHED!"; + finishImage(); + rawLastIndex = 0; + } + } + + // for (int i = 0; i < length; i++) + // { + // for (int j = 0; j < receivedChannels; j++) + // { + // unsigned int x = (startIndex+i) % receivedWidth; + // unsigned int y = static_cast((startIndex+i) / receivedWidth); + // qDebug() << "Setting pixel" << x << "," << y << "to" << (unsigned int)*(rawImage+startIndex+i); + // } + // } + } +} + +void CameraView::paintGL() +{ + glDrawPixels(glImage.width(), glImage.height(), GL_RGBA, GL_UNSIGNED_BYTE, glImage.bits()); +} + +void CameraView::resizeGL(int w, int h) +{ + glViewport(0, 0, w, h); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, w, 0, h, -1, 1); + glMatrixMode(GL_MODELVIEW); +} diff --git a/src/ui/CameraView.h b/src/ui/CameraView.h new file mode 100644 index 0000000000000000000000000000000000000000..e8291944cfc3eb302273d8e4857ef8e148a17b26 --- /dev/null +++ b/src/ui/CameraView.h @@ -0,0 +1,80 @@ +/*===================================================================== + +PIXHAWK Micro Air Vehicle Flying Robotics Toolkit + +(c) 2009 PIXHAWK PROJECT + +This file is part of the PIXHAWK project + + PIXHAWK is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + PIXHAWK is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with PIXHAWK. If not, see . + +======================================================================*/ + +/** + * @file + * @brief Brief Description + * + * @author Lorenz Meier + * + */ + +#ifndef CAMERAVIEW_H +#define CAMERAVIEW_H + +#include +#include +#include "UASInterface.h" + +class CameraView : public QGLWidget +{ + Q_OBJECT +public: + CameraView(int width = 640, int height = 480, int depth = 8, int channels = 1, QWidget* parent = NULL); + ~CameraView(); + + void setImageSize(int width, int height, int depth, int channels); + void paintGL(); + void resizeGL(int w, int h); + +public slots: + void addUAS(UASInterface* uas); + void startImage(int imgid, int width, int height, int depth, int channels); + void setPixels(int imgid, const unsigned char* imageData, int length, unsigned int startIndex); + void finishImage(); + void saveImage(); + void saveImage(QString fileName); + +protected: + // Image buffers + unsigned char* rawBuffer1; + unsigned char* rawBuffer2; + unsigned char* rawImage; + unsigned int rawLastIndex; + unsigned int rawExpectedBytes; + unsigned int bytesPerLine; + bool imageStarted; + static const unsigned char initialColor = 0; + QImage* image; ///< Double buffer image + QImage glImage; ///< Displayed image + int receivedDepth; + int receivedChannels; + int receivedWidth; + int receivedHeight; + QMap images; ///< Reference to the received images + int imageId; ///< ID of the currently displayed image + + void commitRawDataToGL(); +}; + +#endif // CAMERAVIEW_H diff --git a/src/ui/MainWindow.h b/src/ui/MainWindow.h index 8ac81d059a2d9f1898b4d926327d06506644b6fb..da1e2de63712aabb89433f0bf4646e7858e35bc2 100644 --- a/src/ui/MainWindow.h +++ b/src/ui/MainWindow.h @@ -41,6 +41,7 @@ This file is part of the QGROUNDCONTROL project #include "LinkManager.h" #include "LinkInterface.h" #include "UASInterface.h" +#include "CameraView.h" #if (defined QGC_MOUSE_ENABLED_WIN) | (defined QGC_MOUSE_ENABLED_LINUX) #include "Mouse6dofInput.h" #endif // QGC_MOUSE_ENABLED_WIN