diff --git a/include/animation.h b/include/animation.h index acf6ddf4866faad70ba4f6c117b33b69fdb18de2..51a79bfdd1286b06a5f5a3e8ab484ecd39dd2a7f 100644 --- a/include/animation.h +++ b/include/animation.h @@ -59,6 +59,15 @@ they can be represented in QT. class Petrack; +/** + * @brief The Animation class manages the sequence + * + * The Animation class manages the sequence. Currently supported + * are video files of different formats (via OpenCV/FFMPEG), + * image sequences and camera livestreams. Every access to metadata + * (FPS, resolution, etc.) and to the sequene itself is managed by + * this class. + */ class Animation{ public: diff --git a/include/autoCalib.h b/include/autoCalib.h index 635a83c8fedec7924f62b967ad7055983aeb9426..c9a103cd1fd57dd8f9ae5ef9e5033f84fb9576a2 100644 --- a/include/autoCalib.h +++ b/include/autoCalib.h @@ -27,6 +27,20 @@ class Petrack; class Control; +/** + * @brief Class for intrinsic calibration + * + * If we know certain parameters of the camera, such as focal + * length, radial and tangent distortion etc. we can calculate + * where a point in the real world will be projected onto the + * image plane and with additional information (e.g. person + * height), the inverse is true as well. Determining these + * parameters is called intrinsic calibration. + * + * This class runs the intrinsic calibration of the camera + * based on a chessboard-pattern. The dimensions of the chessboard + * are settable by the user, but no other pattern is currently supported. + */ class AutoCalib { public: diff --git a/include/backgroundFilter.h b/include/backgroundFilter.h index ca0f5bbe3ea4ec7cf62254ca9f8a7b088eceed45..5ec6c4b027d6c2cbdddbea5f7dff4d4579c02293 100644 --- a/include/backgroundFilter.h +++ b/include/backgroundFilter.h @@ -43,7 +43,7 @@ private: //Ptr<BackgroundSubtractor> mBgModel; bool mUpdate; // if 0, kein update des models, sonst schon - pet::StereoContext** mStereoContext; // zeiger auf den zeiger in petrack mit stereocontext + pet::StereoContext** mStereoContext; ///< zeiger auf den zeiger in petrack mit stereocontext cv::Mat mBgPointCloud; cv::Mat mForeground; QString mLastFile; @@ -67,13 +67,12 @@ public: void setStereoContext(pet::StereoContext **sc); pet::StereoContext** stereoContext(); - cv::Mat getForeground(); // nutzen, wenn ueber ganzes bild foreground benutzt wird; NULL, wenn keine background subtraction aktiviert - bool isForeground(int i, int j); // nutzen, wenn einzelne pixel abgefraget werden + cv::Mat getForeground(); ///< nutzen, wenn ueber ganzes bild foreground benutzt wird; NULL, wenn keine background subtraction aktiviert + bool isForeground(int i, int j); void reset(); cv::Mat act(cv::Mat &img, cv::Mat &res); -// IplImage* act(IplImage *img, IplImage *res); void maskBg(cv::Mat &mat, float val); }; diff --git a/include/calibFilter.h b/include/calibFilter.h index 19b391446ab36aff42961d430b75337a894bbf67..9c1e22a067ad357dae54a5c4045033d9c8090e56 100644 --- a/include/calibFilter.h +++ b/include/calibFilter.h @@ -23,7 +23,12 @@ #include "filter.h" - +/** + * @brief Undistortion filter + * + * This class is a filter which undistorts the image using the camera matrix from intrinsic calibration. + * It caches the mapping from distorted to undistorted image. + */ class CalibFilter : public Filter { private: diff --git a/include/extrCalibration.h b/include/extrCalibration.h index 092b7830e43881008187438d2ce6bb92fba700a2..bca9028730962c87e042583a99ac183f05af911d 100644 --- a/include/extrCalibration.h +++ b/include/extrCalibration.h @@ -39,7 +39,17 @@ class Petrack; class Control; - +/** + * @brief The ExtrCalibration class manages the extrinsic calibration + * + * If the aperture of our camera is not the origin of our world coordinate + * system, we need to know the position of the camera in space to properly + * reason about the position of points on the image plane in the real world. + * To estimate the translation and rotation of the camera with respect to a + * chosen world coordinate system with the help of a few specified points is + * called the Perspective-n-Point problem. This class loads such a set of points + * and solves PnP with the help of OpenCV. + */ class ExtrCalibration { diff --git a/include/filter.h b/include/filter.h index 67bc0f53e02dc117fc90020a334be9a9f1b092d8..be0294f1c3c3beba3d4f94d31fa0648ad9888eac 100644 --- a/include/filter.h +++ b/include/filter.h @@ -26,6 +26,15 @@ class Filter; +/** + * @brief Class for Filter-parameters + * + * This class is made to hold parameters for filters. + * It has a minimum and maximum value and notifies the + * associated filter of changes. + * + * @todo make a template out of it, so different types are supported + */ class Parameter { private: @@ -57,6 +66,16 @@ public: //------------------------------------------------------------ +/** + * @brief Base class for every image filter + * + * This class is the base class for every image filter, + * like the CalibFilter or Background filter. The + * interface this class defines includes a unified way + * to apply the different filters, caching of the results, + * activation/deactivation as well as automated detection + * of changed parameters. + */ class Filter { private: bool mChg; // if filter paramater were changed diff --git a/include/helper.h b/include/helper.h index b3036c9ab11f3563d561b92739ea6819ad74c960..559fb37717e3a612c458d63f8f95a5048d09a053 100644 --- a/include/helper.h +++ b/include/helper.h @@ -226,8 +226,15 @@ inline QTextStream& operator>>(QTextStream& s, QColor& col) #include <QFileInfo> #include <QString> #include <QStringList> -// ueberprueft die ;-getrennten Dateinamen auf existenz und gibt ersten zurueck -// interessant fuer relativen und absoluten pfad +/** + * @brief checks the ;-separated file names for existence and returns the first + * + * Interesting for working with absolute <em>and</em> relative paths. + * + * @param fileList + * @param relToFileName + * @return first file to exist + */ inline QString getExistingFile(const QString &fileList, const QString &relToFileName) { QStringList list; diff --git a/include/player.h b/include/player.h index 86ef443bae8f935f15d30121a7fe9600160f7a50..37fe999b78d207032ecfee586906d20a5671f65d 100644 --- a/include/player.h +++ b/include/player.h @@ -49,6 +49,16 @@ enum class PlayerState{ PAUSE }; +/** + * @brief The Player class controls the playing and processing of the Animation/Sequence + * + * The Player controls the playback and recordings of the Animation. + * It does not hold the sequence itself. That is done in Animation. However, the + * actual processing of the Animation is tied to it being played since the player + * runs Petrack::updateImage() as part of its play-loop. So processing means + * playing. But processing can be turned off by the user, so playing does not + * neccessarily mean processing. + */ class Player : public QWidget { Q_OBJECT diff --git a/include/tracker.h b/include/tracker.h index 255783b2dda765b3d5962754cb01a55ef7da99db..9cf6c5441752015419995244cbc3e2b6d33cf0f6 100644 --- a/include/tracker.h +++ b/include/tracker.h @@ -444,15 +444,18 @@ inline std::ostream& operator<<(std::ostream& s, const TrackPerson& tp) //---------------------------------------------------------------------------- -// using tracker: -// 1. initial recognition -// 2. next frame track existing track points -// 3. new recognition and check if exist otherwise include new -// (4. delete inner tracking point, which does not recognized over a longer time) -// 5. backward tracking from firstFrame() on -// 6. calculate color over tracking (accumulated over tracking while procedure above) path and set height -// 7. recalc coord with real coord with known height - +/** + * @brief Class orchestrating tracking and related stuff + * + * using tracker: + * 1. initial recognition + * 2. next frame track existing track points + * 3. new recognition and check if exist otherwise include new + * (4. delete inner tracking point, which does not recognized over a longer time) + * 5. backward tracking from firstFrame() on + * 6. calculate color over tracking (accumulated over tracking while procedure above) path and set height + * 7. recalc coord with real coord with known height + */ class Tracker : public QList<TrackPerson> { private: diff --git a/src/animation.cpp b/src/animation.cpp index 3d3bf43126fdf5a851fa94ce5890f935ba62bee3..bd717b0386ad7d30e480d8d9f97b73a48e509320 100644 --- a/src/animation.cpp +++ b/src/animation.cpp @@ -110,19 +110,19 @@ Animation::~Animation() /* Common Implementation of Video and Sequence of Images **/ /**********************************************************************/ -// Returns a pointer to the next frame of the animation +/// Returns the next frame of the animation Mat Animation::getNextFrame() { return getFrameAtIndex(mCurrentFrame+1); } -// Returns a pointer to the previous frame of the animation +/// Returns the previous frame of the animation Mat Animation::getPreviousFrame() { return getFrameAtIndex(mCurrentFrame-1); } -// Returns a pointer to the frame at the index index +/// Returns the frame at the index index Mat Animation::getFrameAtIndex(int index) { if (mCameraLiveStream) @@ -145,14 +145,18 @@ Mat Animation::getFrameAtIndex(int index) return Mat(); } -// Returns a pointer to the frame at the position position -// positions is a double between 0 and 1 that indicates the position in the animation +/** + * @brief Returns the frame at the position position + * + * @param position double between 0 and 1 that indicates the position in the animation + * @return the frame at the indicated position + */ Mat Animation::getFrameAtPos(double position) { return getFrameAtIndex((int) (getSourceInFrameNum()+(position*(getNumFrames()-1)))); } -// Returns a pointer to the current frame +/// Returns the current frame Mat Animation::getCurrentFrame() { return mImage; @@ -160,6 +164,7 @@ Mat Animation::getCurrentFrame() /** * @brief Skips (grabs) the given number of frames (default 1) + * * @param num Number of frames to skip. */ void Animation::skipFrame(int num) @@ -176,8 +181,12 @@ void Animation::skipFrame(int num) } } -// reads the .time file of bumblebee xb3 experiments -// returns, if timefile could be read +/** + * @brief reads the .time file of bumblebee xb3 experiments + * + * @param timeFileName + * @return if timefile could be read + */ bool Animation::openTimeFile(QString &timeFileName) { QFile file(timeFileName); @@ -252,7 +261,7 @@ bool Animation::openTimeFile(QString &timeFileName) } } -// returns -1, if not set by time file +/// returns -1, if not set by time file int Animation::getFirstFrameSec() { return mFirstSec; @@ -262,8 +271,12 @@ int Animation::getFirstFrameMicroSec() return mFirstMicroSec; } -// get actual Time -// fuer default: frame = -1 wird aktueller frame genommen +/** + * @brief Get actual time of the given frame + * + * @param frame frame for which to determine time; -1 means current frame + * @return string with real time at given frame + */ QString Animation::getTimeString(int frame) { if (frame == -1) @@ -285,8 +298,11 @@ QString Animation::getTimeString(int frame) } } -// Opens an animation given the filename of a video or an image. -// Returns true if the animation was open succesfully +/** + * @brief Opens an animation given the filename of a video or an image + * @param fileName + * @return true if the animation was open succesfully + */ bool Animation::openAnimation(QString fileName) { @@ -325,7 +341,8 @@ bool Animation::openAnimation(QString fileName) else return false; } -// Opens a camera livestream + +/// Opens a camera livestream bool Animation::openCameraStream(int camID) { if( !mVideoCapture.open(camID) ) @@ -350,7 +367,7 @@ bool Animation::openCameraStream(int camID) return true; } -// Returns the number of frames in the current animation +/// Returns the number of frames in the current animation int Animation::getNumFrames() { if (mVideo || mImgSeq || mStereo) @@ -365,7 +382,7 @@ int Animation::getMaxFrames() return 0; } -// Returns the index of the current frame +/// Returns the index of the current frame int Animation::getCurrentFrameNum() { return mCurrentFrame; @@ -380,7 +397,7 @@ void Animation::setSourceInFrameNum(int in) mSourceInFrame = in; mMainWindow->updateSourceInOutFrames(); } -// Returns the sourceIn frame number +/// Returns the sourceIn frame number int Animation::getSourceInFrameNum() { return mSourceInFrame; @@ -395,13 +412,13 @@ void Animation::setSourceOutFrameNum(int out) mSourceOutFrame = out; mMainWindow->updateSourceInOutFrames(); } -// Returns the sourceOut frame number +/// Returns the sourceOut frame number int Animation::getSourceOutFrameNum() { return mSourceOutFrame; } -// Returns the filename of the current frame +/// Returns the filename of the current frame QString Animation::getCurrentFileName() { if (mCameraLiveStream) @@ -418,7 +435,7 @@ QString Animation::getCurrentFileName() return mFileBase + "." + mFileSuffix; //".avi"; //QString() } -// Returns the FPS of the current animation +/// Returns the FPS of the current animation double Animation::getFPS() { if (mCameraLiveStream) @@ -450,7 +467,7 @@ void Animation::setFPS(double fps) mFps = fps; } -// Returns the size of the original frames (could made bigger after filtering) +/// Returns the size of the original frames (could made bigger after filtering) QSize Animation::getSize() { if (mVideo || mImgSeq) @@ -463,7 +480,7 @@ QSize Animation::getSize() } } -// free's all the data in animation +/// free's all the data in animation void Animation::free() { if (mImgSeq) @@ -511,7 +528,7 @@ void Animation::reset() // else return mFilter->apply(image); //mFilter->setOnCopy(false); geht nicht // } -// filename without sequence number and suffix : image0001-left.png => image-left +/// filename without sequence number and suffix : image0001-left.png => image-left QString Animation::getFileBase() { return mFileBase; @@ -692,8 +709,11 @@ bool Animation::openAnimationPhoto(QString fileName) return true; } -// Implementation of getFrameAtIndex for photo series -// Returns a pointer to the frame at index index in the serie +/** + * @brief Implementation of getFrameAtIndex for photo series + * @param index + * @return the frame at given index in the series + */ Mat Animation::getFramePhoto(int index) { if ((index != mCurrentFrame) || mImage.empty()) @@ -772,8 +792,15 @@ Mat Animation::getFramePhoto(int index) return mImage; //applyFilter(mImage); } -// Gets Size and Frame number information of the recently open animation -// It is thought to be called once just at the opening of an animation + +/** + * @brief Gets Size and Frame number information of the recently open animation + * + * This methods gets size and length in frames of the current animation. It + * should be called just once. Afterwards the saved values can be used. + * + * @return If data could be succesfully read + */ bool Animation::getInfoPhoto() { bool rc = false; @@ -963,8 +990,8 @@ bool Animation::openAnimationStereoVideo(QString fileName) } #endif -// Implementation of the openAnimation function for videos -// Opens an animation from a video file +/// Implementation of the openAnimation function for videos +/// Opens an animation from a video file bool Animation::openAnimationVideo(QString fileName) { ///CvCapture *capture = NULL; @@ -1070,8 +1097,8 @@ bool Animation::openAnimationVideo(QString fileName) return true; } -// Implementation of getFrameAtIndex for videos -// Returns a pointer to the frame at index index in the video +/// Implementation of getFrameAtIndex for videos +/// Returns the frame at given index in the video Mat Animation::getFrameVideo(int index) { @@ -1229,8 +1256,8 @@ Mat Animation::getFrameVideo(int index) return mImage; } -// Gets Size and Frame number information of the recently open animation -// It is thought to be called once just at the opening of an animation +/// Gets Size and Frame number information of the recently open animation +/// It is thought to be called once just at the opening of an animation bool Animation::getInfoVideo(QString /*fileName*/) { // Set the size of the frames @@ -1409,7 +1436,7 @@ bool Animation::getCameraInfo() return true; } -// Free's the video data +/// Free's the video data void Animation::freeVideo() { // Release the capture device diff --git a/src/autoCalib.cpp b/src/autoCalib.cpp index 47e3037436007b6202281e51248c4d79537dd911..2da073133196e0235b43de2a73f546f25d6c6731 100644 --- a/src/autoCalib.cpp +++ b/src/autoCalib.cpp @@ -33,7 +33,7 @@ using namespace::cv; using namespace std; -#define SHOW_CALIB_MAINWINDOW // definieren, wenn das Schachbrett im Mainwindow und nicht separat angezeigt werden soll: +#define SHOW_CALIB_MAINWINDOW ///< definieren, wenn das Schachbrett im Mainwindow und nicht separat angezeigt werden soll: // fuehrt nach Calibration dazu dass play des originalvideos abstuerzt, insb wenn intr apply nicht ausgewaehlt war AutoCalib::AutoCalib() @@ -105,6 +105,16 @@ bool AutoCalib::openCalibFiles() return false; } +/** + * @brief Loads CalibFiles, detects Chessboard corners and calibrates with these + * + * This function loads the calib files specified by the user. In these images + * chessboard corners are detected and refined (cv::sornerSubPix). If this + * detection is successful at least in one image, the detected points are used + * for the intrinsic calibration of the camera. + * + * Also sets the GUI elements to the calculated value. + */ void AutoCalib::autoCalib() { if (mMainWindow) @@ -122,18 +132,12 @@ void AutoCalib::autoCalib() int flags = 0; vector<Point2f> corners; vector<vector<Point2f> > image_points; -// Mat corners; -// CvSeq* image_points_seq = NULL; -// CvPoint2D32f* image_points_buf = NULL; -// double _camera_matrix[9], _dist_coeffs[8]; - Mat camera_matrix = Mat::eye(3, 3, CV_64F);//, _camera_matrix); - Mat dist_coeffs = Mat::zeros(1, 8, CV_64F);//, _dist_coeffs); + Mat camera_matrix = Mat::eye(3, 3, CV_64F); + Mat dist_coeffs = Mat::zeros(1, 8, CV_64F); Mat extr_params; double reproj_errs; Mat view, view_gray; bool found = false; -// CvMemStorage* storage = NULL; -// int elem_size; Mat origImg; Size imgSize; @@ -142,11 +146,6 @@ void AutoCalib::autoCalib() origImg = mMainWindow->getImg().clone(); // must be cloned, because mIplImg will be deleted in updateImage #endif -// elem_size = board_size.width*board_size.height*sizeof(image_points_buf[0]); -// storage = cvCreateMemStorage(MAX( elem_size*4, 1 << 16)); -// image_points_buf = (CvPoint2D32f*)cvAlloc(elem_size); -// image_points_seq = cvCreateSeq(0, sizeof(CvSeq), elem_size, storage); - QProgressDialog progress("Calculating intrinsic camera parameters...", "Abort calculation", 0, mCalibFiles.size(), mMainWindow); progress.setWindowModality(Qt::WindowModal); // blocks main window @@ -159,11 +158,8 @@ void AutoCalib::autoCalib() qApp->processEvents(); if (progress.wasCanceled()) break; - //cout << mCalibFiles.at(i).toStdString() << endl; //toAscii() .data() Local8Bit().constData() << endl; // cannot load image - //if (!(view = cvLoadImage(mCalibFiles.at(i).toAscii(), 1))) - // if (!(view = cvLoadImage(mCalibFiles.at(i).toLatin1(), CV_LOAD_IMAGE_COLOR))) view = imread(mCalibFiles.at(i).toStdString(),IMREAD_COLOR); if (view.empty()) { @@ -173,55 +169,28 @@ void AutoCalib::autoCalib() // reset view to animation image if (!origImg.empty()) { -// Mat ii = mMainWindow->getImg(); -// cvReleaseImage(&ii); // neue zeile, da in updateimage nicht mehr geloescht wird mMainWindow->updateImage(origImg); // now the last view will be deleted } #endif return; } -// debout << "Size: " << view.rows << "x" << view.cols << endl; + // muss nur bei einem bild gemacht werden if (i==0) imgSize = Size(view.rows,view.cols); -// debout << "Size: " << imgSize.width << "x" << imgSize.height << endl; + // search for chessboard corners found = findChessboardCorners(view,board_size,corners,CALIB_CB_ADAPTIVE_THRESH); -// found = cvFindChessboardCorners(view, board_size, -// image_points_buf, &count, CV_CALIB_CB_ADAPTIVE_THRESH); - - // if not found try other board_size -// if( !found ) -// { -// debout << "Try other chessboard size..." << endl; -// if( board_size.width == 9 ) -// { -// board_size.width = 8; -// }else -// { -// board_size.width = 9; -// } -// found = cvFindChessboardCorners(view, board_size, -// image_points_buf, &count, CV_CALIB_CB_ADAPTIVE_THRESH); -// } -// debout << "found: " << found << endl; + if (found) { // improve the found corners' coordinate accuracy -// view_gray = cvCreateImage(imgSize, 8, 1); cvtColor(view,view_gray,COLOR_BGR2GRAY); -// cvCvtColor(view, view_gray, CV_BGR2GRAY); cornerSubPix(view_gray,corners,Size(11,11), Size(-1,-1),TermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER,30,0.1)); -// cvFindCornerSubPix(view_gray, image_points_buf, count, cvSize(11,11), -// cvSize(-1,-1), cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 30, 0.1)); -// cvReleaseImage(&view_gray); -// cvSeqPush(image_points_seq, image_points_buf); - image_points.push_back(corners); drawChessboardCorners(view,board_size,corners,found); -// cvDrawChessboardCorners(view, board_size, image_points_buf, count, found); #ifndef SHOW_CALIB_MAINWINDOW namedWindow("img", CV_WINDOW_AUTOSIZE ); // 0 wenn skalierbar sein soll @@ -230,8 +199,6 @@ void AutoCalib::autoCalib() #endif #ifdef SHOW_CALIB_MAINWINDOW // show image in view to show calculation -// IplImage* ii = mMainWindow->getIplImage(); -// cvReleaseImage(&ii); // neue zeile, da in updateimage nicht mehr geloescht wird mMainWindow->updateImage(view); #endif qApp->processEvents(); // to allow events and update sceen for viewing new image @@ -239,8 +206,6 @@ void AutoCalib::autoCalib() } else debout << "Calibration pattern not found in: "<< mCalibFiles.at(i).toStdString() << endl; - - //cvReleaseImage(&view); // not allowed, because view will be deleted in updateImage } if( !min_one_pattern_found ) @@ -301,18 +266,31 @@ void AutoCalib::autoCalib() // reset view to animation image if (!origImg.empty()) { -// IplImage* ii = mMainWindow->getIplImage(); -// cvReleaseImage(&ii); // neue zeile, da in updateimage nicht mehr geloescht wird mMainWindow->updateImage(origImg); // now the last view will be deleted } #endif } } - + + +/** + * @brief Runs intrinsic calibration with given parameters + * + * + * @param image_points[in] detected and refined chessboard-corners + * @param img_size + * @param board_size[in] size of chessboard in fields (e.g. 6x8) + * @param square_size[in] size of single square on chessboard pattern + * @param aspect_ratio + * @param flags[in] Flags for calibration; user input assembled in autoCalib() + * @param camera_matrix[out] + * @param dist_coeffs[out] distortion coefficients + * @param reproj_errs[out] + * @return + */ int AutoCalib::runCalibration(vector<vector<Point2f> > image_points, Size img_size, Size board_size, float square_size, float aspect_ratio, int flags, - Mat &camera_matrix, Mat &dist_coeffs, double *reproj_errs)//, Mat &extr_params)//, - //double *reproj_errs)//, double* avg_reproj_err) + Mat &camera_matrix, Mat &dist_coeffs, double *reproj_errs) { int code; @@ -332,30 +310,6 @@ int AutoCalib::runCalibration(vector<vector<Point2f> > image_points, Size img_si vector<Mat> rot_vects, trans_vects; -// for(i = 0; i < image_count; i++) -// { -// CvPoint2D32f* src_img_pt = (CvPoint2D32f*)reader.ptr; -// CvPoint2D32f* dst_img_pt = ((CvPoint2D32f*)image_points->data.fl) + i*point_count; -// CvPoint3D32f* obj_pt = ((CvPoint3D32f*)object_points->data.fl) + i*point_count; - -// for(j = 0; j < board_size.height; j++) -// for(k = 0; k < board_size.width; k++) -// { -// *obj_pt++ = cvPoint3D32f(j*square_size, k*square_size, 0); -// *dst_img_pt++ = *src_img_pt++; -// } -// CV_NEXT_SEQ_ELEM(image_points_seq->elem_size, reader); -// } - -// cvSet(point_counts, cvScalar(point_count)); - -// *extr_params = cvCreateMat(image_count, 6, CV_32FC1); -// cvGetCols(*extr_params, &rot_vects, 0, 3); -// cvGetCols(*extr_params, &trans_vects, 3, 6); - -// cvZero(camera_matrix); -// cvZero(dist_coeffs); - if(flags & CV_CALIB_FIX_ASPECT_RATIO) { camera_matrix.ptr<double>(0)[0] = aspect_ratio; @@ -363,23 +317,8 @@ int AutoCalib::runCalibration(vector<vector<Point2f> > image_points, Size img_si } *reproj_errs = calibrateCamera(object_points,image_points,img_size,camera_matrix,dist_coeffs,rot_vects,trans_vects,flags); -// cvCalibrateCamera2(object_points, image_points, point_counts, -// img_size, camera_matrix, dist_coeffs, -// &rot_vects, &trans_vects, flags); - - code = 1;//cvCheckArr(camera_matrix, CV_CHECK_QUIET) && -// cvCheckArr(dist_coeffs, CV_CHECK_QUIET) && -// cvCheckArr(*extr_params, CV_CHECK_QUIET); - -// *reproj_errs = cvCreateMat(1, image_count, CV_64FC1); - //*avg_reproj_err = - // compute_reprojection_error( object_points, &rot_vects, &trans_vects, - // camera_matrix, dist_coeffs, image_points, point_counts, *reproj_errs ); - -// cvReleaseMat(&object_points); -// cvReleaseMat(&image_points); -// cvReleaseMat(&point_counts); + code = 1; return code; } diff --git a/src/backgroundFilter.cpp b/src/backgroundFilter.cpp index f67b0823894bd8c842d05585bf52bd15c9cd47cd..2b817c47ddfa0a1aaa0b1c84d76a7c9a67a62bb6 100644 --- a/src/backgroundFilter.cpp +++ b/src/backgroundFilter.cpp @@ -29,15 +29,12 @@ #include "control.h" extern Control *cw; -// Entfernung zum Hintergrund, um als Vordergrund angesehen zu werden -// darf nicht zu gross werden, da sonst an waenden problem -// z-Wert in m (nicht cm!) -//wenn z-wert 1m unter defaultgroesse -//#define FOREGROUND_DISTANCE ((mDefaultHeight/100.-1.0) > 0. ? (mDefaultHeight/100.-1.0): 0.) +/// Entfernung zum Hintergrund, um als Vordergrund angesehen zu werden +/// darf nicht zu gross werden, da sonst an waenden problem #define FOREGROUND_DISTANCE 0.4 -// kleine Bereiche werden eliminiert, dies koennte in Abhaengigkeit von der disparity gemacht werden!!!!!!!! -// Anzahl der Pixel, die ein Vordergrund aufweisen muss +/// kleine Bereiche werden eliminiert, dies koennte in Abhaengigkeit von der disparity gemacht werden!!!!!!!! +/// Anzahl der Pixel, die ein Vordergrund aufweisen muss #define MIN_FOREGROUND_AREA -1000 // war:-400 //#define SHOW_TMP_IMG @@ -72,17 +69,24 @@ Mat BackgroundFilter::getForeground() // nutzen, wenn ueber ganzes bild foregrou return mForeground; } -// i entlang zeile, j entlang spalte -// zur Effizientssteigerung ohne ueberpruefung der grenzen!!! -bool BackgroundFilter::isForeground(int i, int j) // nutzen, wenn einzelne pixel abgefraget werden +/** + * @brief Determines if pixel is in foreground. Use for single pixels. + * + * Does not check if pixel position is valid! (For efficiency) + * + * @param coloumn + * @param row + * @return true if foreground + */ +bool BackgroundFilter::isForeground(int coloumn, int row) { - if (!mForeground.empty()) // && i >= 0 && i < mForeground->width && j >= 0 && j < mForeground->height) - return (bool) mForeground.data[j*mForeground.cols+i]; // 0 background, 1 foreground + if (!mForeground.empty()) + return (bool) mForeground.data[row*mForeground.cols+coloumn]; // 0 background, 1 foreground else return false; } -// zuruecksetzen, wenn zB helligkeit veraendert wird oder schaerfe +/// zuruecksetzen, wenn zB helligkeit veraendert wird oder schaerfe void BackgroundFilter::reset() { // funktioniert nicht wirklich diff --git a/src/backgroundItem.cpp b/src/backgroundItem.cpp index 68a72da9e6eda6ed4c816ca4ff514070dc00fca6..7085e829318f0c49c17bba969b897a0974af762f 100644 --- a/src/backgroundItem.cpp +++ b/src/backgroundItem.cpp @@ -38,10 +38,15 @@ BackgroundItem::BackgroundItem(QWidget *wParent, QGraphicsItem * parent) // einzig move koennte interessant sein, um grid zu verschieben?! // setAcceptsHoverEvents(true); } -// // bounding box wird durch linke obere ecke und breite/hoehe angegeben -// // wenn an den rand gescrollt wurde im view, dann wird durch das dynamische anpassen -// // bei trans und scale zwar zuerst alles neu gezeichnet durch update, -// // aber beim verkleinern des scrollbereichs nur der teil von tracker neu gezeichnet + +/** + * @brief Bounding box of drawn to area. + * + * This bounding box is used to determine if this Item needs to be redrawn or not. + * See the official Qt Docs for QGraphicsItem + * + * @return (updated) bounding rect of this item + */ QRectF BackgroundItem::boundingRect() const { if (mMainWindow->getImage()) diff --git a/src/calibFilter.cpp b/src/calibFilter.cpp index 89120cfbf20cc3079510d2590ad1adb22ef7c0c8..10015724cfd80ac17cfbfc036325288e4ad5f93d 100644 --- a/src/calibFilter.cpp +++ b/src/calibFilter.cpp @@ -87,6 +87,16 @@ CalibFilter::CalibFilter() getK6()->setFilter(this); } +/** + * @brief Undistorts the image. + * + * This method calculates and caches the mapping for undistortion. + * The mapping is applied to the input image. + * + * @param img[in] + * @param res[out] + * @return undistorted image + */ Mat CalibFilter::act(Mat &img, Mat &res) { if(this->changed() || map1.empty() || map2.empty()) diff --git a/src/codeMarkerItem.cpp b/src/codeMarkerItem.cpp index 6dc49b64e1a2582a174686ef413506ad5927c6df..a891f0039afa9b3272e64b0080883d651d3a06da 100644 --- a/src/codeMarkerItem.cpp +++ b/src/codeMarkerItem.cpp @@ -38,36 +38,23 @@ CodeMarkerItem::CodeMarkerItem(QWidget *wParent, QGraphicsItem * parent) : QGraphicsItem(parent) { mMainWindow = (class Petrack*) wParent; -// mImage = NULL; - //setAcceptsHoverEvents(true); - - // setEnabled(false); // all mouse events connot access this item, but it will be seen - // einzig move koennte interessant sein, um grid zu verschieben?! -// setAcceptsHoverEvents(true); } -// // bounding box wird durch linke obere ecke und breite/hoehe angegeben -// // wenn an den rand gescrollt wurde im view, dann wird durch das dynamische anpassen -// // bei trans und scale zwar zuerst alles neu gezeichnet durch update, -// // aber beim verkleinern des scrollbereichs nur der teil von tracker neu gezeichnet + + +/** + * @brief Bounding box of drawn to area. + * + * This bounding box is used to determine if this Item needs to be redrawn or not. + * See the official Qt Docs for QGraphicsItem + * + * @return (updated) bounding rect of this item + */ QRectF CodeMarkerItem::boundingRect() const { if (mMainWindow->getImage()) -// return QRectF(mUlc.x(),mUlc.y(),mMainWindow->width(),mMainWindow->height()); return QRectF(-mMainWindow->getImageBorderSize(), -mMainWindow->getImageBorderSize(), mMainWindow->getImage()->width(), mMainWindow->getImage()->height()); -// return QRectF(-mMainWindow->getImageBorderSize(), -mMainWindow->getImageBorderSize(), mImage->width(), mImage->height()); else return QRectF(0, 0, 0, 0); -// // bounding box wird in lokalen koordinaten angegeben!!! (+-10 wegen zahl "1") -// if (mControlWidget->getCalibCoordShow()) -// return QRectF(-110., -110., 220., 220.); -// else ; - -// return QRectF(0., 0., 0., 0.); - -// // sicher ware diese boundingbox, da alles -// // return QRectF(xMin, yMin, xMax-xMin, yMax-yMin); -// // eigentlich muesste folgende Zeile reichen, aber beim ranzoomen verschwindet dann koord.sys. -// // return QRectF(mControlWidget->getCalibCoordTransX()/10.-scale, mControlWidget->getCalibCoordTransY()/10.-scale, 2*scale, 2*scale); } void CodeMarkerItem::setRect(Vec2F& v) @@ -78,7 +65,7 @@ void CodeMarkerItem::setRect(Vec2F& v) /** * @brief draws colored shapes at heads in image to indicate detection status * - * differnet calculations of position depending on whether function is called out of findCodeMarker() Function + * different calculations of position depending on whether function is called out of findCodeMarker() Function * only (== recoMethod 6) or if findCodeMarker() Function is called out of findMulticolorMarker() Function (== recoMethod 5). * In the first case the offset is added automatically via 'offset' and 'v'. * In the second case the offset from cropRect to ROI has to be added manually. diff --git a/src/codeMarkerWidget.cpp b/src/codeMarkerWidget.cpp index 602e5dc304f84fc00d0e669529c02e53f53c54b2..f30db3c1b7fa425863831af4266aafa6df58ae49 100644 --- a/src/codeMarkerWidget.cpp +++ b/src/codeMarkerWidget.cpp @@ -63,7 +63,7 @@ CodeMarkerWidget::CodeMarkerWidget(QWidget *parent) // <PARAM CLOSE_RADIUS="0" CLOSE_USED="0" OPEN_RADIUS="0" OPEN_USED="0" MIN_AREA="0" MAX_AREA="0" MAX_RATIO="0.0"/> //</COLOR_MARKER> -// store data in xml node +/// store data in xml node void CodeMarkerWidget::setXml(QDomElement &elem) { QDomElement subElem; @@ -98,7 +98,7 @@ void CodeMarkerWidget::setXml(QDomElement &elem) } -// read data from xml node +/// read data from xml node void CodeMarkerWidget::getXml(QDomElement &elem) { QDomElement subElem; diff --git a/src/colorMarkerItem.cpp b/src/colorMarkerItem.cpp index 4b8f9add257ca4b642f66ecd874204afa903d24f..3e692a0cadc8b9bcf74e1d2f6edcb663f242aee2 100644 --- a/src/colorMarkerItem.cpp +++ b/src/colorMarkerItem.cpp @@ -37,35 +37,22 @@ ColorMarkerItem::ColorMarkerItem(QWidget *wParent, QGraphicsItem * parent) { mMainWindow = (class Petrack*) wParent; mImage = NULL; -// mMask = NULL; - //setAcceptsHoverEvents(true); - - // setEnabled(false); // all mouse events connot access this item, but it will be seen - // einzig move koennte interessant sein, um grid zu verschieben?! -// setAcceptsHoverEvents(true); } -// // bounding box wird durch linke obere ecke und breite/hoehe angegeben -// // wenn an den rand gescrollt wurde im view, dann wird durch das dynamische anpassen -// // bei trans und scale zwar zuerst alles neu gezeichnet durch update, -// // aber beim verkleinern des scrollbereichs nur der teil von tracker neu gezeichnet + +/** + * @brief Bounding box of drawn to area. + * + * This bounding box is used to determine if this Item needs to be redrawn or not. + * See the official Qt Docs for QGraphicsItem + * + * @return (updated) bounding rect of this item + */ QRectF ColorMarkerItem::boundingRect() const { if (mMainWindow->getImage()) return QRectF(-mMainWindow->getImageBorderSize(), -mMainWindow->getImageBorderSize(), mMainWindow->getImage()->width(), mMainWindow->getImage()->height()); -// return QRectF(-mMainWindow->getImageBorderSize(), -mMainWindow->getImageBorderSize(), mImage->width(), mImage->height()); else return QRectF(0, 0, 0, 0); -// // bounding box wird in lokalen koordinaten angegeben!!! (+-10 wegen zahl "1") -// if (mControlWidget->getCalibCoordShow()) -// return QRectF(-110., -110., 220., 220.); -// else ; - -// return QRectF(0., 0., 0., 0.); - -// // sicher ware diese boundingbox, da alles -// // return QRectF(xMin, yMin, xMax-xMin, yMax-yMin); -// // eigentlich muesste folgende Zeile reichen, aber beim ranzoomen verschwindet dann koord.sys. -// // return QRectF(mControlWidget->getCalibCoordTransX()/10.-scale, mControlWidget->getCalibCoordTransY()/10.-scale, 2*scale, 2*scale); } void ColorMarkerItem::setRect(Vec2F& v) @@ -73,6 +60,15 @@ void ColorMarkerItem::setRect(Vec2F& v) mUlc = v; // upper left corner to draw } +/** + * @brief Paints color thresholding mask + * + * Paints a mask over the image which imitates the thresholding + * via thresholdHSV(). The mask is set by using it in the thresholding. + * It is accessed via createMask. + * + * @param painter + */ void ColorMarkerItem::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/) { if (!mMask.empty()) @@ -112,20 +108,17 @@ void ColorMarkerItem::paint(QPainter *painter, const QStyleOptionGraphicsItem */ } } -// only pointer is set, no copy of data +/// be aware of data sharing between cv::Mat's void ColorMarkerItem::setMask(Mat &mask) { mMask = mask; } -// original width w and height h must be given +/// original width w and height h must be given Mat ColorMarkerItem::createMask(int w, int h) { if (w>0 && h>0 && (mMask.empty() || (!mMask.empty() && (w != mMask.cols || h != mMask.rows)))) { -// cvReleaseImage(&mMask); -// mMask = cvCreateImage(cvSize(w, h), 8, 1); - mMask.create(h,w,CV_8UC1); } return mMask; diff --git a/src/colorMarkerWidget.cpp b/src/colorMarkerWidget.cpp index b24cf870d159669497ed0c7cf193f16ddbbd2419..7afad3eef7f584ce5c6dde2fd53cc9e8f9da729e 100644 --- a/src/colorMarkerWidget.cpp +++ b/src/colorMarkerWidget.cpp @@ -52,7 +52,7 @@ ColorMarkerWidget::ColorMarkerWidget(QWidget *parent) // <PARAM CLOSE_RADIUS="0" CLOSE_USED="0" OPEN_RADIUS="0" OPEN_USED="0" MIN_AREA="0" MAX_AREA="0" MAX_RATIO="0.0"/> //</COLOR_MARKER> -// store data in xml node +/// store data in xml node void ColorMarkerWidget::setXml(QDomElement &elem) { QDomElement subElem; @@ -87,7 +87,7 @@ void ColorMarkerWidget::setXml(QDomElement &elem) elem.appendChild(subElem); } -// read data from xml node +/// read data from xml node void ColorMarkerWidget::getXml(QDomElement &elem) { QDomElement subElem; diff --git a/src/colorPlot.cpp b/src/colorPlot.cpp index 67ad557c20ffe97f3ea11d4e167367cea70bf16d..d270af3fd874477d9fb9afd15a62bf4588f2e43e 100644 --- a/src/colorPlot.cpp +++ b/src/colorPlot.cpp @@ -80,39 +80,39 @@ public: // { // return QwtDoubleRect(0., 0., 200., 200.); // } - + /** + * @brief Draws the mImage at the right position in correct size. + * @param p + * @param mx + * @param my + */ void draw(QPainter* p, const QwtScaleMap& mx, const QwtScaleMap& my, const QRectF& /*r*/) const { -// debout << "---" <<endl; -// debout << r.x() << " " << r.y() << " " << r.width() << " " << r.height()<<endl; -// debout << "x:" <<endl; -// debout << mx.p1() << " "<< mx.p2() << " " << mx.s1() << " "<< mx.s2() << " "<<endl; -// debout << "y:" <<endl; -// debout << my.p1() << " "<< my.p2() << " " << my.s1() << " "<< my.s2() << " "<<endl; - p->save(); p->scale(mx.p2()/(mx.s2() - mx.s1()), my.p1()/(my.s2() - my.s1()));// -// p->scale((mx.p2() - mx.p1())/(mx.s2() - mx.s1()), (my.p1() - my.p2())/(my.s2() - my.s1()));// p->translate(-mx.s1(), my.s2()-((ColorPlot *) plot())->yMax()); - //mx.p1()-mx.s1(), my.s2()+my.p2()-((ColorPlot *) plot())->yMax() p->drawImage(0, 0, *mImage); p->restore(); } - // fuer x==y werden restliche komponenten gemaess z gewertet und das min in beide dimensionen als wert genommen + /** + * @brief Generates the color background or the color plot + * + * If x == y, the minimal values for both are used and the other two + * dimenions get set with the value of z. + * + * @param model + * @param x First dimension (dimension for x-values) RGB or HSV (e.g. Hue, Value, Red) + * @param y Second dimension (dimension for y-values) RGB or HSV (e.g. Hue, Value, Red) + * @param z Value for third dimension (if x == y for 2nd and 3rd) + */ void generateImage(int model, int x, int y, int z) { -// debout << "generate image" <<endl; - -// if (!mControlWidget) -// return; - QColor col; int i, j; - if (model == 0) // HSV //mControlWidget->recoColorModel->currentIndex() + if (model == 0) // HSV { - // mControlWidget->recoColorX->currentIndex() for (i = 0; i < (x==0?360:256); ++i) for (j = 0; j < (y==0?360:256); ++j) { @@ -161,48 +161,15 @@ TrackerPlotItem::TrackerPlotItem() mTracker = NULL; } +/** + * @brief Draws a circle in the colorplot for every color associated with a trackperson. + * + * @param p + * @param mapX + * @param mapY + */ void TrackerPlotItem::draw(QPainter* p, const QwtScaleMap& mapX, const QwtScaleMap& mapY, const QRectF& /*re*/) const { -// // alt: ohne betrachtung des z-wertes: -// QRectF rect; -// double sx = mapX.p2()/(mapX.s2() - mapX.s1()); -// double sy = mapY.p1()/(mapY.s2() - mapY.s1()); -// double yMax = ((ColorPlot *) plot())->yMax(); -// double circleSize = ((ColorPlot *) plot())->symbolSize(); -// int i; - -// p->save(); -// p->scale(sx, sy); -// p->translate(-mapX.s1(), mapY.s2()-yMax); - -// rect.setWidth(circleSize/sx); -// rect.setHeight(circleSize/sy); -// sx = circleSize/(2.*sx); -// sy = circleSize/(2.*sy); -// if (mTracker) -// { -// for (i = 0; i < mTracker->size(); ++i) -// { -// if ((*mTracker)[i].color().isValid()) // insbesondere von hand eingefuegte trackpoint/persons haben keine farbe -// { -// QPoint point = ((ColorPlot *) plot())->getPos((*mTracker)[i].color()); -// rect.moveLeft(point.x()-sx); -// rect.moveTop(point.y()-sy); - -// p->setBrush(QBrush((*mTracker)[i].color())); -// if (((ColorPlot *) plot())->isGrey((*mTracker)[i].color())) -// p->setPen(Qt::red); -// else -// p->setPen(mPen); - -// p->drawEllipse(rect); -// } -// } -// } -// p->restore(); - - - QRectF rect; double sx = mapX.p2()/(mapX.s2() - mapX.s1()); double sy = mapY.p1()/(mapY.s2() - mapY.s1()); @@ -346,11 +313,11 @@ RectPlotItem::RectPlotItem() { } -// auch wenn punkt auf linie liegt, wird er als drinnen gezaehlt!!!! -// es wird einfach der erste treffer in map-list genommen - unterscheidung zwischen farbe und graustufe -// wird keine farbige map fuer farbige col gefunden, wird in grauen map der erste treffer genommen und -// andersherum: wird fuer graue col keine graue map gefunden, wird erste farbige map zurueckgegeben -// und hoehe zurueckgegeben +/// auch wenn punkt auf linie liegt, wird er als drinnen gezaehlt!!!! +/// es wird einfach der erste treffer in map-list genommen - unterscheidung zwischen farbe und graustufe +/// wird keine farbige map fuer farbige col gefunden, wird in grauen map der erste treffer genommen und +/// andersherum: wird fuer graue col keine graue map gefunden, wird erste farbige map zurueckgegeben +/// und hoehe zurueckgegeben double RectPlotItem::map(const QColor &col) const //const TrackPerson &tp RectMap ... double x, double y { double yMax = ((ColorPlot *) plot())->yMax(); @@ -506,6 +473,15 @@ RectMap RectPlotItem::getMap(int index) const return RectMap(); } +/** + * @brief Draws rectangles representing the color maps into the color plot. + * + * The currently active/selected map is drawn green, the rest red. + * + * @param p + * @param mapX + * @param mapY + */ void RectPlotItem::draw(QPainter* p, const QwtScaleMap& mapX, const QwtScaleMap& mapY, const QRectF& /*re*/) const { QRectF rect; @@ -615,6 +591,10 @@ public: //widgetWheelEvent ( QWheelEvent * e ) + /** + * @brief Allows movement in the zoomed in color plot via dragging with a pressed down middle mouse button. + * @param e + */ void widgetMouseMoveEvent(QMouseEvent *e) override { static int lastX = -1; @@ -716,6 +696,16 @@ public: { } + /** + * @brief Marks the point in color plot with the color under the cursor in the image. + * + * This function draws a little x at the place in the colorplot corresponding + * to the color the image/video frame has under the cursor of the user. + * + * @param p + * @param mapX + * @param mapY + */ void draw(QPainter* p, const QwtScaleMap& mapX, const QwtScaleMap& mapY, const QRectF& /*re*/) const { double sx = mapX.p2()/(mapX.s2() - mapX.s1()); diff --git a/src/coordItem.cpp b/src/coordItem.cpp index 0a284c544912b8520f6f5e8338e5c07db15f0ba8..ab31bc7375b604d268612cc1b551d32b7cc117cf 100644 --- a/src/coordItem.cpp +++ b/src/coordItem.cpp @@ -53,10 +53,15 @@ CoordItem::CoordItem(QWidget *wParent,/* QGraphicsScene * scene,*/ QGraphicsItem //setAcceptsHoverEvents(true); } -// bounding box wird durch linke obere ecke und breite/hoehe angegeben -// wenn an den rand gescrollt wurde im view, dann wird durch das dynamische anpassen -// bei trans und scale zwar zuerst alles neu gezeichnet durch update, -// aber beim verkleinern des scrollbereichs nur der teil von coord neu gezeichnet + +/** + * @brief Bounding box of drawn to area. + * + * This bounding box is used to determine if this Item needs to be redrawn or not. + * See the official Qt Docs for QGraphicsItem + * + * @return (updated) bounding rect of this item + */ QRectF CoordItem::boundingRect() const { /* double sc = mControlWidget->getCalibCoordScale()/10; diff --git a/src/ellipse.cpp b/src/ellipse.cpp index f3660ca66664dca403bb6bb1bb39b986ce698b88..093a977856e6a7e365226b284e53587053e8b380 100644 --- a/src/ellipse.cpp +++ b/src/ellipse.cpp @@ -74,7 +74,8 @@ double MyEllipse::area() const { return PI*mR1*mR2; } -// only estimation, because of complex elliptical integral + +/// only estimation, because of complex elliptical integral double MyEllipse::outline() const { return PI*(1.5*(mR1+mR2) - sqrt(mR1*mR2)); @@ -83,7 +84,8 @@ double MyEllipse::outline() const //return PI*sqrt(2.*(mR1*mR1+mR2*mR2)); //return PI*(mR1+mR2); } -// is point p inside or on the ellipse + +/// is point p inside or on the ellipse bool MyEllipse::isInside(const Vec2F& p) const { // for a point to be inside the ellipse the sum of the diff --git a/src/extrCalibration.cpp b/src/extrCalibration.cpp index 239c1ce1f56d0a4f82b862f4cb699075a7c02150..7df2f6a3f79f9940cb3664af6ed3821b27949df4 100644 --- a/src/extrCalibration.cpp +++ b/src/extrCalibration.cpp @@ -97,6 +97,29 @@ bool ExtrCalibration::openExtrCalibFile(){ return false; } + +/** + * @brief Loads the extrinsic calibration from mExtrCalibFile + * + * This methods reads an extrinsic calibration in one of two formats: + * First: 3D coordinates followed by corresponding 2D coordinates + * + * x y z px py + * + * Second: Just 3D coordinates + * + * x y z + * + * It is possible to optionally start the file with the number of lines: + * + * 2 + * x1 y1 z1 + * x2 y2 z2 + * + * This is just going to be ignored. Comments start with "#". + * + * @return + */ bool ExtrCalibration::loadExtrCalibFile(){ bool all_ok = true; @@ -127,14 +150,8 @@ bool ExtrCalibration::loadExtrCalibFile(){ with_3D_data = false, end_loop = false; - while( 1 ) + while( !in.atEnd() ) { - // Falls Datei am Ende Schleife beenden - if( in.atEnd() ) - { - break; - } - // Neue Zeile einlesen line = in.readLine(); ++line_counter; @@ -255,6 +272,14 @@ bool ExtrCalibration::loadExtrCalibFile(){ calibExtrParams(); return all_ok; } + +/** + * @brief Uses manually set TrackPoints as 2D points for extrinsic calibration + * + * @pre loaded at least 4 3D-points + * + * @return true if calibration did take place + */ bool ExtrCalibration::fetch2DPoints() { bool all_ok = true; @@ -291,6 +316,18 @@ bool ExtrCalibration::fetch2DPoints() } return all_ok; } + +/** + * @brief Saves points used for extrinsic calibration + * + * Saves the points used for extrinsic calibration in the format: + * + * n + * x y z px py + * + * With n as number of points, x,y,z as 3D coordianted and px,py as 2D coordinates. + * @return + */ bool ExtrCalibration::saveExtrCalibPoints() { bool all_okay = false; @@ -364,6 +401,9 @@ bool ExtrCalibration::isSetExtrCalib(){ return true;//isSetExtrCalib; } +/** + * @brief Extrinsic calibration with help of cv::solvePnP + */ void ExtrCalibration::calibExtrParams() { @@ -538,6 +578,17 @@ void ExtrCalibration::calibExtrParams() } +/** + * @brief Calculates the reprojection Error + * + * This method calculates following errors and their variance: + * <ul> + * <li>2D Point to 3D Point against 3D Point - using calibration points</li> + * <li>3D to 2D to 3D against 2D to 3D - using default height for calib. points</li> + * <li>3D to 2D against 2D - using calib. points</li> + * </ul> + * @return + */ bool ExtrCalibration::calcReprojectionError() { ////// @@ -553,38 +604,38 @@ bool ExtrCalibration::calcReprojectionError() bool debug = false; for(int i=0; i< num_points; i++) { - Point2f p2 = get2DList().at(i); + Point2f p2d = get2DList().at(i); Point3f p3d = get3DList().at(i); p3d.x -= mControlWidget->getCalibCoord3DTransX(); p3d.y -= mControlWidget->getCalibCoord3DTransY(); p3d.z -= mControlWidget->getCalibCoord3DTransZ(); - Point2f p3 = getImagePoint(p3d); + Point2f p3dTo2d = getImagePoint(p3d); // Error measurements metric (cm) //debout << "Point-Height: " << endl; - Point3f p2d = get3DPoint(Point2f(p2.x/*+bS*/,p2.y/*+bS*/),p3d.z); + Point3f p2dTo3d = get3DPoint(p2d,p3d.z); //debout << p2d.x << " " << p2d.y << " " << p2d.z << endl; //debout << p3d.x << " " <<p3d.y << " " <<p3d.z << endl; //debout << "Default-Height: " << endl; - Point3f p2d_mapDefaultHeight = get3DPoint(p2,mControlWidget->mapDefaultHeight->value()); // mStatusPosRealHeight->value()); ? + Point3f p2dTo3dMapDefaultHeight = get3DPoint(p2d,mControlWidget->mapDefaultHeight->value()); //debout << p2d_mapDefaultHeight.x << " " << p2d_mapDefaultHeight.y << " " << p2d_mapDefaultHeight.z << endl; - Point3f p3d_mapDefaultHeight = get3DPoint(Point2f(p3.x,p3.y)/*getImagePoint(p2d_mapDefaultHeight)*/,mControlWidget->mapDefaultHeight->value()); + Point3f p3dTo2dTo3dMapDefaultHeight = get3DPoint(p3dTo2d,mControlWidget->mapDefaultHeight->value()); //debout << p3d_mapDefaultHeight.x << " " << p3d_mapDefaultHeight.y << " " << p3d_mapDefaultHeight.z << endl; - val = sqrt(pow(p3d.x-p2d.x,2) + pow(p3d.y-p2d.y,2)); + val = sqrt(pow(p3d.x - p2dTo3d.x,2) + pow(p3d.y - p2dTo3d.y,2)); if ( val > max_pH ) max_pH = val; sum_pH += val; if( debug ) debout << "Error point[" << i << "]: " << val << endl; - val = sqrt(pow(p3d_mapDefaultHeight.x-p2d_mapDefaultHeight.x,2) + pow(p3d_mapDefaultHeight.y-p2d_mapDefaultHeight.y,2)); + val = sqrt(pow(p3dTo2dTo3dMapDefaultHeight.x - p2dTo3dMapDefaultHeight.x,2) + pow(p3dTo2dTo3dMapDefaultHeight.y-p2dTo3dMapDefaultHeight.y,2)); if ( val > max_dH ) max_dH = val; sum_dH += val; if( debug ) debout << "Error point[" << i << "]: " << val << endl; // Error measurements pixel - val = sqrt(pow(p3.x-p2.x,2) + pow(p3.y-p2.y,2)); + val = sqrt(pow(p3dTo2d.x - p2d.x,2) + pow(p3dTo2d.y - p2d.y,2)); // Maximum if ( val > max_px ) max_px = val; sum_px += val; @@ -593,33 +644,33 @@ bool ExtrCalibration::calcReprojectionError() } for(int i=0; i< num_points; i++) { - Point2f p2 = get2DList().at(i); + Point2f p2d = get2DList().at(i); Point3f p3d = get3DList().at(i); p3d.x -= mControlWidget->getCalibCoord3DTransX(); p3d.y -= mControlWidget->getCalibCoord3DTransY(); p3d.z -= mControlWidget->getCalibCoord3DTransZ(); - Point2f p3 = getImagePoint(p3d); + Point2f p3d_to_2d = getImagePoint(p3d); // Error measurements metric (cm) //debout << "Point-Height: " << endl; - Point3f p2d = get3DPoint(Point2f(p2.x/*+bS*/,p2.y/*+bS*/),p3d.z); + Point3f p2d_to_3d = get3DPoint(p2d,p3d.z); //debout << p2d.x << " " << p2d.y << " " << p2d.z << endl; //debout << p3d.x << " " <<p3d.y << " " <<p3d.z << endl; //debout << "Default-Height: " << endl; - Point3f p2d_mapDefaultHeight = get3DPoint(p2,mControlWidget->mapDefaultHeight->value()); // mStatusPosRealHeight->value()); ? + Point3f p2d_to_3d_mapDefaultHeight = get3DPoint(p2d,mControlWidget->mapDefaultHeight->value()); // mStatusPosRealHeight->value()); ? //debout << p2d_mapDefaultHeight.x << " " << p2d_mapDefaultHeight.y << " " << p2d_mapDefaultHeight.z << endl; - Point3f p3d_mapDefaultHeight = get3DPoint(Point2f(p3.x,p3.y)/*getImagePoint(p2d_mapDefaultHeight)*/,mControlWidget->mapDefaultHeight->value()); + Point3f p3d_to2d_to3d_mapDefaultHeight = get3DPoint(p3d_to_2d,mControlWidget->mapDefaultHeight->value()); //debout << p3d_mapDefaultHeight.x << " " << p3d_mapDefaultHeight.y << " " << p3d_mapDefaultHeight.z << endl; - val = pow(sqrt(pow(p3d.x-p2d.x,2) + pow(p3d.y-p2d.y,2))-(sum_pH/num_points),2); + val = pow(sqrt(pow(p3d.x-p2d_to_3d.x,2) + pow(p3d.y-p2d_to_3d.y,2))-(sum_pH/num_points),2); var_pH += val; - val = pow(sqrt(pow(p3d_mapDefaultHeight.x-p2d_mapDefaultHeight.x,2) + pow(p3d_mapDefaultHeight.y-p2d_mapDefaultHeight.y,2))-(sum_dH/num_points),2); + val = pow(sqrt(pow(p3d_to2d_to3d_mapDefaultHeight.x-p2d_to_3d_mapDefaultHeight.x,2) + pow(p3d_to2d_to3d_mapDefaultHeight.y-p2d_to_3d_mapDefaultHeight.y,2))-(sum_dH/num_points),2); var_dH += val; - val = pow(sqrt(pow(p3.x-p2.x,2) + pow(p3.y-p2.y,2))-(sum_px/num_points),2); + val = pow(sqrt(pow(p3d_to_2d.x-p2d.x,2) + pow(p3d_to_2d.y-p2d.y,2))-(sum_px/num_points),2); var_px += val; } @@ -663,7 +714,16 @@ bool ExtrCalibration::calcReprojectionError() return reprojectionError[0] > MAX_AV_ERROR ? false : true; // Falls pixel fehler im schnitt > 20 ist das Ergebnis nicht akzeptabel } - +/** + * @brief Projects the 3D point to the image plane + * + * Projection is done by multiplying with the external camera matrix + * composed out of rotation and translation aquired in ExtrCalibration::calibExtrParams(). + * After that, the internal camera matrix is applied. + * + * @param p3d 3D point to transform + * @return calculated 2D projection of p3d + */ Point2f ExtrCalibration::getImagePoint(Point3f p3d) { bool debug = false; @@ -768,19 +828,15 @@ Point2f ExtrCalibration::getImagePoint(Point3f p3d) } return point2D; } -/** - * Methode get3DPoint - * Wandelt einen 2D-Punkt in einen 3D Punkt um - * Dazu muss der 2D-Pixelpunkt sowie der Abstand - * des 2D-Punktes zur xy-Ebene angegeben werden (i.d.R. die Hoehe/Personengroesse) - * - * Input: p2d = 2D Pixelpunkt (Uebergabe ohne Border) - * h = Abstand des Punktes zur xy-Ebene - * - * Output: Point3f resultPoint gibt den berechneten 3D-Punkt zurueck - * - */ + +/** + * @brief Tranforms a 2D point into a 3D point with given height. + * + * @param p2d 2D pixel point (without border) + * @param h height i.e. distance to xy-plane + * @return calculated 3D point + */ Point3f ExtrCalibration::get3DPoint(Point2f p2d, double h) { bool debug = false; diff --git a/src/filter.cpp b/src/filter.cpp index cc29511801483e578ff8020694c41647f7e06ed6..ea3d683da4ea30cb89f31ec96ff3b53067ae174d 100644 --- a/src/filter.cpp +++ b/src/filter.cpp @@ -100,12 +100,17 @@ Filter::Filter() // mResStored = false; } -// was pure virtuell function must be implemented -// and has to return, if any parameter is changed -// so that the filter would return another result -//---------- -// now this function has also to be called -// from a child function which looks for changing parameters +/** + * @brief Indicates if any of the parameters of the filter have changed + * + * was pure virtuell function must be implemented + * and has to return, if any parameter is changed + * so that the filter would return another result + * now this function has also to be called + * from a child function which looks for changing parameters + * + * @return true, if a parameter changed + */ bool Filter::changed() { return mChg; @@ -120,14 +125,16 @@ void Filter::setChanged(bool b) } /** - * @brief Applies filter and sets changed to false + * @brief Applies the filter to img and sets changed on false. * - * Applies the filter and after that sets changed to false - * The filter is only applied, when it is enabled, else - * the img just gets returned without filtering. + * The filter is applied, iff it is enabled. Else the image + * is returned without any modifications. Depending on the + * Filter::getOnCopy() result, the image is copied before the filter + * is applied. * - * @param img Image to apply filter to - * @return filtered image + * The result is cached and can be accessed through Filter::getLastResult(). + * @param img image to be transformed + * @return if enabled the transformed image else just img without changes (still gets cached) */ Mat Filter::apply(Mat &img) { diff --git a/src/gridItem.cpp b/src/gridItem.cpp index b23f59b75b4a310a0e05abcd5c5600bfded97fb2..ef3a0d506281f1fdcdca594308c64eafc4056f3b 100644 --- a/src/gridItem.cpp +++ b/src/gridItem.cpp @@ -39,6 +39,15 @@ GridItem::GridItem(QWidget *wParent, QGraphicsItem * parent) //setEnabled(false); // all mouse events connot access this item, but it will be seen // einzig move koennte interessant sein, um grid zu verschieben?! } + +/** + * @brief Bounding box of drawn to area. + * + * This bounding box is used to determine if this Item needs to be redrawn or not. + * See the official Qt Docs for QGraphicsItem + * + * @return (updated) bounding rect of this item + */ QRectF GridItem::boundingRect() const { // -mMainWindow->getImageBorderSize(), -mMainWindow->getImageBorderSize() TUTS NICHT !!!!! diff --git a/src/helper.cpp b/src/helper.cpp index e1ac4c3c17d41db1b96b815a04850a135e3e64ba..b20c4d5e6b21c7d5013508d2bdb9526a3edd002b 100644 --- a/src/helper.cpp +++ b/src/helper.cpp @@ -99,7 +99,7 @@ void showImg(QLabel *l, IplImage *i) #endif /** -@brief get roi: copys roi to rect by setting values of roi to correct values inside rect +@brief get roi: copies roi to rect by setting values of roi to correct values inside rect no copy of data, only new header which allows to access rect rect wird veraendert, roi nicht diff --git a/src/imageItem.cpp b/src/imageItem.cpp index b7712d4856c8c7ea480bd94d324ba282205728a2..01abc731d0b77b706fc0a17741e7d80cf97abf32 100644 --- a/src/imageItem.cpp +++ b/src/imageItem.cpp @@ -38,6 +38,15 @@ ImageItem::ImageItem(QWidget *wParent, QGraphicsItem * parent) setAcceptHoverEvents(true); // setAcceptDrops(true); } + +/** + * @brief Bounding box of drawn to area. + * + * This bounding box is used to determine if this Item needs to be redrawn or not. + * See the official Qt Docs for QGraphicsItem + * + * @return (updated) bounding rect of this item + */ QRectF ImageItem::boundingRect() const { if (mImage) @@ -172,13 +181,12 @@ double ImageItem::getAngleToGround(float px, float py, float height){ } QPointF ImageItem::getPosImage(QPointF pos, float height) -//QPointF ImageItem::getPosImage(QPointF pos) { bool debug = false; cv::Point2f p2d; if( mImage ) { - if( mControlWidget->getCalibCoordDimension() == 0 ) + if( mControlWidget->getCalibCoordDimension() == 0 ) // Tab coordinate system is on 3D { p2d = mMainWindow->getExtrCalibration()->getImagePoint(cv::Point3f(pos.x(),pos.y(),height)); pos.setX(p2d.x); @@ -320,7 +328,11 @@ void ImageItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { QGraphicsItem::mouseMoveEvent(event); } -// event, of moving mouse + +/** + * @brief Updates the mousePosOnImage in Petrack + * @param event + */ void ImageItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) { // // real coordinate diff --git a/src/multiColorMarkerItem.cpp b/src/multiColorMarkerItem.cpp index 807ae5d168d4aa4573c222c28f619fb9b4ef4ad1..0db477568d2cd4d2579f90fc7498be3efb960020 100644 --- a/src/multiColorMarkerItem.cpp +++ b/src/multiColorMarkerItem.cpp @@ -44,10 +44,15 @@ MultiColorMarkerItem::MultiColorMarkerItem(QWidget *wParent, QGraphicsItem * par // einzig move koennte interessant sein, um grid zu verschieben?! // setAcceptsHoverEvents(true); } -// // bounding box wird durch linke obere ecke und breite/hoehe angegeben -// // wenn an den rand gescrollt wurde im view, dann wird durch das dynamische anpassen -// // bei trans und scale zwar zuerst alles neu gezeichnet durch update, -// // aber beim verkleinern des scrollbereichs nur der teil von tracker neu gezeichnet + +/** + * @brief Bounding box of drawn to area. + * + * This bounding box is used to determine if this Item needs to be redrawn or not. + * See the official Qt Docs for QGraphicsItem + * + * @return (updated) bounding rect of this item + */ QRectF MultiColorMarkerItem::boundingRect() const { if (mMainWindow->getImage()) diff --git a/src/petrack.cpp b/src/petrack.cpp index e2501445a5dd7ac360f047727315558b4b80d3c6..6476fb4fa5afde78c4a8fed7ab1b654c1b1cff12 100644 --- a/src/petrack.cpp +++ b/src/petrack.cpp @@ -347,6 +347,15 @@ void Petrack::dragEnterEvent(QDragEnterEvent *event) if (event->mimeData()->hasUrls()) event->acceptProposedAction(); } + +/** + * @brief Accepts dropped .pet, .trc and media files + * + * Opens the project for a .pet. Imports the trajectories for a .trc + * and tries to open the sequence for any other kind of file. + * + * @param event + */ void Petrack::dropEvent(QDropEvent *event) { if (event->mimeData()->hasUrls()) @@ -404,6 +413,12 @@ void Petrack::updateSceneRect() mScene->setSceneRect(-bS, -bS, iW, iH); } +/** + * @brief Loads the content of a .pet file into petrack + * + * @param doc the DOM of the .pet file + * @param openSeq true, if sequence given in doc should be opened + */ void Petrack::openXml(QDomDocument &doc, bool openSeq) { @@ -716,13 +731,13 @@ void Petrack::saveXml(QDomDocument &doc) root.appendChild(elem); } -// rueckgabewert zeigt an, ob gesichert werden konnte +/// rueckgabewert zeigt an, ob gesichert werden konnte bool Petrack::saveSameProject() { return saveProject(mProFileName); } -// rueckgabewert zeigt an, ob gesichert werden konnte +/// rueckgabewert zeigt an, ob gesichert werden konnte bool Petrack::saveProject(QString fileName) // default fileName="" { // if no destination file or folder is given @@ -803,7 +818,11 @@ void Petrack::writeXmlElement(QXmlStreamWriter& xmlStream, QDomElement element) xmlStream.writeEndElement(); } -void Petrack::openCameraLiveStream(int camID) +/** + * @brief Opens camera livestream from cam with camID + * @param camID id of camera to use (defaults to 0) + */ +void Petrack::openCameraLiveStream(int camID /* =-1*/) { if (camID == -1) { @@ -930,9 +949,18 @@ void Petrack::saveViewSequence() { saveSequence(false, true); } -// kann die geladene einzelbildsequnz oder video in video oder einzelbildsequenz speichern -// saveSequ zeigt an, ob einzelbildsequenz oder video gespeichert werden soll, -// wenn dest nicht angegeben ist, ansonsten wird dateiendung von dest als hinweis auf format genommen + + +/** + * @brief Saves current sequence as avi-file or image sequence + * + * Saves the loaded image sequence or video from current frame on till the end. + * One can save the sequence as is or one can save the view shown in PeTrack. + * + * @param saveVideo true, if wanting to save a video. Ignored when dest isn't empty + * @param saveView true, if sequence should be saved as shown in PeTrack (with trajectories etc.) + * @param dest destination file; if empty, the user chooses via a dialog + */ void Petrack::saveSequence(bool saveVideo, bool saveView, QString dest) // default saveView= false, dest="" { static QString lastDir; @@ -1264,6 +1292,11 @@ void Petrack::saveSequence(bool saveVideo, bool saveView, QString dest) // defau } } +/** + * @brief Saves the current View, including visualizations, in a file (.g. pdf) + * + * @param dest name of the saved file; if empty, a dialogue for the user opens + */ void Petrack::saveView(QString dest) //default = "" { static QString lastFile; @@ -1627,6 +1660,10 @@ void Petrack::setCamera() #endif } +/** + * @brief Helper function to create Actions for the menu bar + * @see Petrack::createMenus() + */ void Petrack::createActions() { mOpenSeqAct = new QAction(tr("&Open Sequence"), this); @@ -1801,6 +1838,10 @@ void Petrack::createActions() connect(mOnlineHelpAct, SIGNAL(triggered()), this, SLOT(onlineHelp())); } +/** + * @brief Helper function building menues out of QActions + * @see Petrack::createActions() + */ void Petrack::createMenus() { mFileMenu = new QMenu(tr("&File"), this); @@ -1870,6 +1911,9 @@ void Petrack::createMenus() mCameraMenu->setEnabled(false); } +/** + * @brief Helper function to create status bar at the bottom of the window + */ void Petrack::createStatusBar() { QFont f("Courier", 12, QFont::Bold); //Times Helvetica, Normal @@ -2212,7 +2256,7 @@ void Petrack::setShowFPS(double fps) * * This method calculates the FPS by remembering how long * it has been since it was called last time. If skipped is - * true, it doesn't directly updat the FPS since 2 + * true, it doesn't directly update the FPS since 2 * skipped frames have essentially a time delay of 0 between * them, which would make calculations wonky. * @@ -2254,6 +2298,7 @@ void Petrack::setStatusPosReal() // pos in cm if (mImageItem) setStatusPosReal(mImageItem->getPosReal(mMousePosOnImage, getStatusPosRealHeight())); } + void Petrack::setStatusPosReal(const QPointF &pos) // pos in cm { if (mStatusLabelPosReal) @@ -2265,10 +2310,12 @@ void Petrack::setStatusPosReal(const QPointF &pos) // pos in cm mStatusLabelPosReal->setText(labelText); } } + void Petrack::setStatusPos(const QPoint &pos) // pos in pixel { mStatusLabelPos->setText(QString("%1x%2").arg(pos.x(), 4).arg(pos.y(), 4)); } + void Petrack::setStatusColor(const QRgb &col) { QString s("#%1%2%3"); // static moeglich? @@ -2290,6 +2337,7 @@ void Petrack::setStatusColor(const QRgb &col) //debout << "QColor: " << color << " height: " << mControlWidget->getColorPlot()->map(color) << endl; } + void Petrack::setStatusColor() { QPointF pos = getMousePosOnImage(); @@ -2307,6 +2355,14 @@ double Petrack::getStatusPosRealHeight() return 0.; } +/** + * @brief Reads (and applies) settings form platform-independent persistent storage + * + * The saved size and position of the application window get reconstructed. As well as + * the options about antialiasing and the usage of OpenGL. + * mSeqFileName and mProFileName get set, so the "Open Project" and "Open Sequence" + * dialogues start at correct folder. The old project/sequence is NOT actually loaded. + */ void Petrack::readSettings() { QSettings settings("Forschungszentrum Juelich GmbH", "PeTrack by Maik Boltes, Daniel Salden"); @@ -2325,6 +2381,10 @@ void Petrack::readSettings() opengl(); } +/** + * @brief Writes persistent setting. + * @see Petrack::readSettings + */ void Petrack::writeSettings() { QSettings settings("Forschungszentrum Juelich GmbH", "PeTrack by Maik Boltes, Daniel Salden"); @@ -2375,6 +2435,13 @@ void Petrack::closeEvent(QCloseEvent *event) } +/** + * @brief Sets the mMousePosOnImage member variable and displayed pixel/real coordinates + * + * Gets called from ImageItem::hoverMoveEvent() and enables an easy access + * to the mouse position. + * @param pos Position of mouse cursor in image pixel coordinates + */ void Petrack::setMousePosOnImage(QPointF pos) { if (mImage) @@ -2430,7 +2497,7 @@ void Petrack::mousePressEvent(QMouseEvent *event) } } -// update control widget, if image size changed (especially because of changing border) +/// update control widget, if image size changed (especially because of changing border) void Petrack::updateControlImage(Mat &img) { @@ -3393,6 +3460,17 @@ void Petrack::playAll() mPlayerWidget->skipToFrame(memPos); } +/** + * @brief Activates tracking and reco; calcs through the video (in both ways) + * + * This method activates tracking and reco and plays the whole video (from current + * frame on) till the end. Then, if mAutoBackTrack is set, it jumps back to the + * largest first frame, i.e. the last time a new person was added/recognized, and + * tracks backwards till the beginning of the video. + * + * The old settings for tracking and reco will be restored. No interaction with the + * main window is possible for the time of tracking. + */ void Petrack::trackAll() { int memPos = mPlayerWidget->getPos(); @@ -3869,62 +3947,31 @@ void Petrack::updateSequence() } -//// calculate background for backgroud subtraction -//// WIRD NICHT MEHR BENOETIGT, DA HINTERGRUNDMODELL IM BETRIEB AKTUALISIERT WIRD!!! -//void Petrack::calcBackground() -//{ -// int memPos = mPlayerWidget->getPos(); -// if (memPos != -1) // video loaded -// { -// int progVal = 0; -// int from = mControlWidget->filterBgFrom->value(); // from - frame where background begins -// int num = mControlWidget->filterBgNum->value(); // num - frame number for averaging because of stabilization - -// if (from < mAnimation->getNumFrames()) -// { -// QProgressDialog progress("Calculating background...", "Abort calculation", 0, num, this); -// progress.setWindowModality(Qt::WindowModal); // blocks main window -// mPlayerWidget->skipToFrame(from); - -// cvNamedWindow("BG", 1); -// cvNamedWindow("FG", 1); -// CvBGStatModel* bg_model = cvCreateGaussianBGModel(getIplImageFiltered()); -// //CvBGStatModel* bg_model = cvCreateFGDStatModel(getIplImageFiltered()); - -// while ((++progVal < num) && (mPlayerWidget->frameForward())) -// { -// cvUpdateBGStatModel(getIplImageFiltered(), bg_model); -// cvShowImage("BG", bg_model->background); -// cvShowImage("FG", bg_model->foreground); - -// progress.setValue(progVal); -// qApp->processEvents(); -// if (progress.wasCanceled()) -// break; -// } - -// cvReleaseBGStatModel(&bg_model); - -// mPlayerWidget->skipToFrame(memPos); // ruecksprung zur urspruenglichen Position -// } -// else -// { -// QMessageBox::critical(this, tr("PeTrack"), tr("from has to be smaller than %1.").arg(mAnimation->getNumFrames())); -// return; -// } -// } -//} - -// gibt cm pro pixel zurueck -// wert wir nur neu bestimmt, wenn auch kopfgroesse berechnet wird +/** + * @brief Gets cm per pixel. Only recalculates when calculating head size. + * @return cm per pixel + */ double Petrack::getCmPerPixel() { return mCmPerPixel; } + // die Groesse des kreises des durchschnittlichen Kopfdurchmessers, der ganzen kopf umfasst in Pixel // annahmen: 21cm avg kopflaenge, mapDefaultheight genommen statt: 173cm avg koerpergroesse mann / frau mit Schuhen (180cm waere nur Mann) // hS ==-1 als default besagt, dass mHeadSize neu berechnet statt gesetzt werden soll // WENN HEADSIZE NEU BERECHNET WIRD WIRD AUTOMATISCH AUCH CMPERPIXEL MITBERECHNET +/** + * @brief Sets the size of the circle of the average head circumference in pixel. + * + * Assumption for default calculation: <br> + * 21cm avg head length <br> + * default height of person accoring to mapDefaultHeigt <br> + * + * Default case recalculates mCmPerPixel + * + * @see Petrack::getCmPerPixel + * @param hS new headsize or -1, for calculating default + */ void Petrack::setHeadSize(double hS) { if (hS == -1) diff --git a/src/player.cpp b/src/player.cpp index dbf47b8760a00b6ebabd1c460d51d2129f8a6782..8206b2918e75a4fa586a26e8ae2a391987d24ec6 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -470,6 +470,14 @@ void Player::togglePlayPause() } } +/** + * @brief Toggles recording and saving of recording + * + * If already recording, the method stops the recording and saves it to + * a user-given file. If recording hasn't started, this method starts it. + * + * Actual recording happens in Player::updateImage() + */ void Player::recStream() { if (mAnimation->isCameraLiveStream() || mAnimation->isVideo() || mAnimation->isImageSequence() || mAnimation->isStereoVideo()) @@ -587,6 +595,9 @@ bool Player::skipToFrame() // [0..mAnimation->getNumFrames()-1] return skipToFrame(mFrameNum->text().toInt()); } +/** + * @brief Properly updates FrameInNum and FrameOutNum + */ void Player::update() { if (true || !mMainWindow->isLoading()) diff --git a/src/recognition.cpp b/src/recognition.cpp index 0fbb7a84249a3e8d83a603074f04c68a853c641f..2b93f03ed2a947b4bf2bed7eaef6a1084135cb0e 100644 --- a/src/recognition.cpp +++ b/src/recognition.cpp @@ -1095,9 +1095,9 @@ void findColorMarker(Mat &img, QList<TrackPoint> *crossList, Control *controlWid } /** - * @brief uses openCV libraries to detect Aruco CodeMarkers + * @brief uses OpenCV libraries to detect Aruco CodeMarkers * @param img - * @param crossList + * @param crossList[out] list of detected TrackPoints * @param controlWidget */ void findCodeMarker(Mat &img, QList<TrackPoint> *crossList, Control *controlWidget, Vec2F offsetCropRect2Roi) @@ -1676,9 +1676,16 @@ imShow("img2", tmpAusgabe2); } - -// returns list of mid point of black crosses on white ground in region of interest roi -// in image iplImg +/** + * @brief Detects position of markers from user-chosen type + * + * @param img + * @param roi Region of interest for recognition + * @param crossList[out] detected TrackPoints + * @param controlWidget + * @param borderSize + * @param bgFilter + */ void getMarkerPos(Mat &img, QRect &roi, QList<TrackPoint> *crossList, Control *controlWidget, int borderSize, BackgroundFilter *bgFilter) { int markerBrightness = controlWidget->markerBrightness->value(); diff --git a/src/stereoItem.cpp b/src/stereoItem.cpp index c8d5f48d75c95e8d291ad109f02407318e33f641..ac28e42be874e42b5be6e71d72afbd722e0c4aa6 100644 --- a/src/stereoItem.cpp +++ b/src/stereoItem.cpp @@ -44,10 +44,14 @@ StereoItem::StereoItem(QWidget *wParent, QGraphicsItem * parent) } -// // bounding box wird durch linke obere ecke und breite/hoehe angegeben -// // wenn an den rand gescrollt wurde im view, dann wird durch das dynamische anpassen -// // bei trans und scale zwar zuerst alles neu gezeichnet durch update, -// // aber beim verkleinern des scrollbereichs nur der teil von tracker neu gezeichnet +/** + * @brief Bounding box of drawn to area. + * + * This bounding box is used to determine if this Item needs to be redrawn or not. + * See the official Qt Docs for QGraphicsItem + * + * @return (updated) bounding rect of this item + */ QRectF StereoItem::boundingRect() const { if (mMainWindow->getImage()) diff --git a/src/tracker.cpp b/src/tracker.cpp index 7807a33313b7e2f73d74a05c696aaadbe63f4b34..4296c78802d050f19f9094e18470562e6473ebc6 100644 --- a/src/tracker.cpp +++ b/src/tracker.cpp @@ -40,7 +40,11 @@ using namespace std; #define MIN_WIN_SIZE 3. - +/** + * @brief Transforms OpenCV error in tracking (L1-Norm) to quality + * @param error error reported by cv::calcOpticalFlowPyrLK + * @return quality according to error + */ inline float errorToQual(float error) { return 80.F - error/20.F; @@ -334,6 +338,30 @@ double TrackPerson::getNearestZ(int i, int *extrapolated) // rueckgabe zeigt an, ob neuer p eingefuegt wurde oder nicht, falls qualitaet schlechter // persNr ist index in uebergeordneter liste zur sinnvollen warnungs-ausgabe +/** + * @brief Inserts point + * + * If the point would be appended or prepended, it is inserted + * and the points at the frames between the current one and the + * last one with a frame get linearly interpolated. If the point + * being appended/prepended is further away than the speed + * (between the last two points) would reasonably allow, the point + * is either not inserted or extrapolated. + * + * If the new point would replace an old point, it is only added + * if it has a better quality. + * + * Multicolor-Blackdot and Multicolor-Aruco markers which get + * recognized by color are shifted by the difference between + * dot/code-point and color-point to avoid stuttering of the + * trajectory. + * + * @param frame + * @param p + * @param persNr + * @param extrapolate + * @return true if point was added + */ bool TrackPerson::insertAtFrame(int frame, const TrackPoint &p, int persNr, bool extrapolate) { // if (frame == mLastFrame+1) //included in following lines @@ -536,8 +564,12 @@ const TrackPoint& TrackPerson::trackPointAt(int frame) const // & macht bei else // } //void draw(IplImage *img) const; -// gibt -1 zurueck, wenn frame oder naechster frame nicht existiert -// entfernung ist absolut +/** + * @brief Absolute distance to next frame + * + * @param frame + * @return absolute distance or -1, if frame doen't exist + */ double TrackPerson::distanceToNextFrame(int frame) const { if (frame >= mFirstFrame && frame+1 <= mLastFrame) @@ -641,7 +673,7 @@ void Tracker::resize(Size size) // // -getImgBorderSize() nutzen } -// split trajectorie pers before frame frame +/// split trajectorie pers before frame frame void Tracker::splitPerson(int pers, int frame) { int j; @@ -662,9 +694,14 @@ void Tracker::splitPerson(int pers, int frame) } } -// split trajectorie before frame frame -// onlyVisible == -1 : immer alles betrachten, ansonsten nur person onlyVisible -// gibt true zurueck, wenn trajektorie gesplttet werden konnte +/** + * @brief Split trajectory at point p before given frame + * + * @param p point where to split trajectory (helpful if onlyVisible isn't set) + * @param frame frame at which to split the trajectory + * @param onlyVisible set of people for whom to do it (empty means everyone) + * @return true if a trajectory was split + */ bool Tracker::splitPersonAt(const Vec2F& p, int frame, QSet<int> onlyVisible) { int i; @@ -679,10 +716,13 @@ bool Tracker::splitPersonAt(const Vec2F& p, int frame, QSet<int> onlyVisible) return false; } -// gibt true zurueck, wenn punkt geloescht werden konnte -// direction zeigt an, ob bis zum aktuellen (-1), ab dem aktuellen (1) oder ganzer trackpath (0) -// onlyVisible == -1 : immer alles betrachten, ansonsten nur person onlyVisible -// loescht trackpoint nur einer trajektorie +/** + * @brief Deletes points of pers + * @param pers TrackPerson whose points should be deleted + * @param direction notes if previous (-1), following(1) or whole(0) trajectory should be deleted + * @param frame + * @return true, if deletion occured + */ bool Tracker::delPointOf(int pers, int direction, int frame) { int j; @@ -709,6 +749,14 @@ bool Tracker::delPointOf(int pers, int direction, int frame) // direction zeigt an, ob bis zum aktuellen (-1), ab dem aktuellen (1) oder ganzer trackpath (0) // onlyVisible == -1 : immer alles betrachten, ansonsten nur person onlyVisible // loescht trackpoint nur einer trajektorie +/** + * @brief Deletes points of a SINGLE person in onlyVisible + * @param p point which need to be on the person (helpful if onlyVisible is not properly set) + * @param direction notes if previous (-1), following(1) or whole(0) trajectory should be deleted + * @param frame + * @param onlyVisible set of people whose points could be deleted; empty means everyone + * @return true if deletion occured + */ bool Tracker::delPoint(const Vec2F& p, int direction, int frame, QSet<int> onlyVisible) { int i; @@ -722,8 +770,11 @@ bool Tracker::delPoint(const Vec2F& p, int direction, int frame, QSet<int> onlyV return false; } -// direction zeigt an, ob bis zum aktuellen (-1), ab dem aktuellen (1) oder ganzer trackpath (0) -// loescht trackpoints aller trajektorien +/** + * @brief Deletes trackpoints of all trajectories + * @param direction notes if previous (-1), following(1) or whole(0) trajectory should be deleted + * @param frame + */ void Tracker::delPointAll(int direction, int frame) { int i, j; @@ -1243,6 +1294,7 @@ int Tracker::smallestLastFrame() /** * @brief Tracker::calcPrevFeaturePoints calculates all featurePoints(Persons) from the "previous" frame + * * @param prevFrame Number of previous frame (can be both, larger or smaller; forward or backwards) * @param rect ROI * @param frame current frame number @@ -1665,6 +1717,7 @@ void Tracker::trackFeaturePointsLK(int level, bool adaptive) /** * @brief Tries to track colorPoint when featurePoint has high error + * * @param level Pyramidlevel to track with * @param numOfPeopleToTrack * @param errorScale Factor for highest tolerable tracking error @@ -1706,6 +1759,17 @@ void Tracker::refineViaColorPointLK(int level, float errorScale) } } +/** + * @brief Counts consecutive TrackPoints in background and deletes trajectories with too many + * + * If a TrackPoint is inside the recognition ROI and in the background + * a counter is incremented. Once this counter hits a user defined value + * and if the user has enabled deletion of trajectories, the trajectory is + * marked for deletion. + * + * @param trjToDel[out] trajectories marked for deletion + * @param bgFilter[in] backgroundFilter, which determines if a point is in the bg + */ void Tracker::useBackgroundFilter(QList<int>& trjToDel, BackgroundFilter *bgFilter){ int x, y; static int margin=10; // rand am bild, ab dem trajectorie in den hintergrund laufen darf @@ -1852,6 +1916,23 @@ void Tracker::recalcHeight(float altitude) } } +/** + * @brief Performs different tests to check the plausibility of trajectories. + * + * This method can check for + * <ul><li>shortness (less than 10 points)</li> + * <li>start and endpoint (both should be outside the reco ROI + * with exceptions for the beginning and end of the video)</li> + * <li>Fast variations of speed (4 frame interval)</li> + * <li>TrackPoints are too close together</li></ul> + * + * @param pers[in] list of persons (ID) to check + * @param frame[out] list of frames at which "problems" occured + * @param testEqual[in] true if warning for very close points are wished + * @param testVelocity[in] true if warning for fast speed variations is whished + * @param testInside[in] true if warning for start and endpoint in reco ROI is wished + * @param testLength[in] true if warning for very short trajectories is wished + */ void Tracker::checkPlausibility(QList<int> &pers, QList<int> &frame, bool testEqual, bool testVelocity, bool testInside, bool testLength) { @@ -2052,8 +2133,11 @@ void Tracker::resetPos() (*this)[i][j].setSp(-1., -1., -1.); } -// gibt groessenverteilung der personen auf stdout aus -// rueckgabewert false wenn keine hoeheninformationen in tracker datensatz vorliegt +/** + * @brief Prints height distribution to stdout + * + * @return false if no height information is available, else true + */ bool Tracker::printHeightDistribution() { debout << endl; @@ -2096,10 +2180,21 @@ bool Tracker::printHeightDistribution() return true; } +/** + * @brief Deletes TrackPersons with over 80% solely tracked points + * + * DOESN'T WORK WITH COLOR MARKERS because they have a quality under + * 100 (quality threshold of this method could be changed) + * + * Only trajectories having a point at the given frame are purged. + * Trajectories with less than 10 points are not purged. + * + * @param frame frame at which all trajectories should be purged + */ void Tracker::purge(int frame) { int i, j; - float count; // anzahl der trackpoints, an denen die person nicht gefunden wurde + float count; ///< number of trackpoints without recognition for (i = 0; i < size(); ++i) { diff --git a/src/trackerItem.cpp b/src/trackerItem.cpp index 4ad31fca12577ad18d0bfc388ed644a0bd86a087..9aeb6f759b387076ce324736b06efcddf008cda4 100644 --- a/src/trackerItem.cpp +++ b/src/trackerItem.cpp @@ -48,10 +48,15 @@ TrackerItem::TrackerItem(QWidget *wParent, Tracker *tracker, QGraphicsItem * par // einzig move koennte interessant sein, um grid zu verschieben?! // setAcceptsHoverEvents(true); } -// // bounding box wird durch linke obere ecke und breite/hoehe angegeben -// // wenn an den rand gescrollt wurde im view, dann wird durch das dynamische anpassen -// // bei trans und scale zwar zuerst alles neu gezeichnet durch update, -// // aber beim verkleinern des scrollbereichs nur der teil von tracker neu gezeichnet + +/** + * @brief Bounding box of drawn to area. + * + * This bounding box is used to determine if this Item needs to be redrawn or not. + * See the official Qt Docs for QGraphicsItem + * + * @return (updated) bounding rect of this item + */ QRectF TrackerItem::boundingRect() const { if (mMainWindow->getImage())