1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                           License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14 // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
15 // Third party copyrights are property of their respective owners.
16 //
17 // Redistribution and use in source and binary forms, with or without modification,
18 // are permitted provided that the following conditions are met:
19 //
20 //   * Redistribution's of source code must retain the above copyright notice,
21 //     this list of conditions and the following disclaimer.
22 //
23 //   * Redistribution's in binary form must reproduce the above copyright notice,
24 //     this list of conditions and the following disclaimer in the documentation
25 //     and/or other materials provided with the distribution.
26 //
27 //   * The name of the copyright holders may not be used to endorse or promote products
28 //     derived from this software without specific prior written permission.
29 //
30 // This software is provided by the copyright holders and contributors "as is" and
31 // any express or implied warranties, including, but not limited to, the implied
32 // warranties of merchantability and fitness for a particular purpose are disclaimed.
33 // In no event shall the Intel Corporation or contributors be liable for any direct,
34 // indirect, incidental, special, exemplary, or consequential damages
35 // (including, but not limited to, procurement of substitute goods or services;
36 // loss of use, data, or profits; or business interruption) however caused
37 // and on any theory of liability, whether in contract, strict liability,
38 // or tort (including negligence or otherwise) arising in any way out of
39 // the use of this software, even if advised of the possibility of such damage.
40 //
41 //M*/
42 //################################################################################
43 //
44 //                    Created by Nuno Moutinho
45 //
46 //################################################################################
47 
48 #include "precomp.hpp"
49 
50 namespace cv
51 {
52     namespace plot
53     {
54         using namespace std;
55 
56         class Plot2dImpl CV_FINAL : public Plot2d
57         {
58             public:
59 
Plot2dImpl(InputArray plotData)60             Plot2dImpl(InputArray plotData)
61             {
62                 Mat _plotData = plotData.getMat();
63                 //if the matrix is not Nx1 or 1xN
64                 if(_plotData.cols > 1 && _plotData.rows > 1)
65                     CV_Error(Error::StsBadArg, "ERROR: Plot data must be a 1xN or Nx1 matrix.\n");
66 
67                 CV_Assert(_plotData.type() == CV_64F);
68 
69                 //in case we have a row matrix than needs to be transposed
70                 if(_plotData.cols > _plotData.rows)
71                 {
72                     _plotData = _plotData.t();
73                 }
74 
75                 plotDataY=_plotData;
76                 plotDataX = plotDataY*0;
77                 for (int i=0; i<plotDataY.rows; i++)
78                 {
79                     plotDataX.at<double>(i,0) = i;
80                 }
81 
82                 //calling the main constructor
83                 plotHelper(plotDataX, plotDataY);
84 
85             }
86 
Plot2dImpl(InputArray plotDataX_,InputArray plotDataY_)87             Plot2dImpl(InputArray plotDataX_, InputArray plotDataY_)
88             {
89                 Mat _plotDataX = plotDataX_.getMat();
90                 Mat _plotDataY = plotDataY_.getMat();
91                 //f the matrix is not Nx1 or 1xN
92                 if((_plotDataX.cols > 1 && _plotDataX.rows > 1) || (_plotDataY.cols > 1 && _plotDataY.rows > 1))
93                     CV_Error(Error::StsBadArg, "ERROR: Plot data must be a 1xN or Nx1 matrix.\n");
94 
95                 CV_Assert(_plotDataX.type() == CV_64F && _plotDataY.type() == CV_64F);
96 
97                 //in case we have a row matrix than needs to be transposed
98                 if(_plotDataX.cols > _plotDataX.rows)
99                 {
100                     _plotDataX = _plotDataX.t();
101                 }
102                 if(_plotDataY.cols > _plotDataY.rows)
103                 {
104                     _plotDataY = _plotDataY.t();
105                 }
106 
107                 plotHelper(_plotDataX, _plotDataY);
108             }
109 
110             //set functions
setMinX(double _plotMinX)111             void setMinX(double _plotMinX) CV_OVERRIDE
112             {
113                 plotMinX = _plotMinX;
114                 plotMinX_plusZero = _plotMinX;
115             }
setMaxX(double _plotMaxX)116             void setMaxX(double _plotMaxX) CV_OVERRIDE
117             {
118                 plotMaxX = _plotMaxX;
119                 plotMaxX_plusZero = _plotMaxX;
120             }
setMinY(double _plotMinY)121             void setMinY(double _plotMinY) CV_OVERRIDE
122             {
123                 plotMinY = _plotMinY;
124                 plotMinY_plusZero = _plotMinY;
125             }
setMaxY(double _plotMaxY)126             void setMaxY(double _plotMaxY) CV_OVERRIDE
127             {
128                 plotMaxY = _plotMaxY;
129                 plotMaxY_plusZero = _plotMaxY;
130             }
setPlotLineWidth(int _plotLineWidth)131             void setPlotLineWidth(int _plotLineWidth) CV_OVERRIDE
132             {
133                 plotLineWidth = _plotLineWidth;
134             }
setInvertOrientation(bool _invertOrientation)135             void setInvertOrientation(bool _invertOrientation) CV_OVERRIDE
136             {
137                 invertOrientation = _invertOrientation;
138             }
setNeedPlotLine(bool _needPlotLine)139             void setNeedPlotLine(bool _needPlotLine) CV_OVERRIDE
140             {
141                 needPlotLine = _needPlotLine;
142             }
setPlotLineColor(Scalar _plotLineColor)143             void setPlotLineColor(Scalar _plotLineColor) CV_OVERRIDE
144             {
145                 plotLineColor=_plotLineColor;
146             }
setPlotBackgroundColor(Scalar _plotBackgroundColor)147             void setPlotBackgroundColor(Scalar _plotBackgroundColor) CV_OVERRIDE
148             {
149                 plotBackgroundColor=_plotBackgroundColor;
150             }
setPlotAxisColor(Scalar _plotAxisColor)151             void setPlotAxisColor(Scalar _plotAxisColor) CV_OVERRIDE
152             {
153                 plotAxisColor=_plotAxisColor;
154             }
setPlotGridColor(Scalar _plotGridColor)155             void setPlotGridColor(Scalar _plotGridColor) CV_OVERRIDE
156             {
157                 plotGridColor=_plotGridColor;
158             }
setPlotTextColor(Scalar _plotTextColor)159             void setPlotTextColor(Scalar _plotTextColor) CV_OVERRIDE
160             {
161                 plotTextColor=_plotTextColor;
162             }
setPlotSize(int _plotSizeWidth,int _plotSizeHeight)163             void setPlotSize(int _plotSizeWidth, int _plotSizeHeight) CV_OVERRIDE
164             {
165                 if(_plotSizeWidth > 400)
166                     plotSizeWidth = _plotSizeWidth;
167                 else
168                     plotSizeWidth = 400;
169 
170                 if(_plotSizeHeight > 300)
171                     plotSizeHeight = _plotSizeHeight;
172                 else
173                     plotSizeHeight = 300;
174             }
setShowGrid(bool _needShowGrid)175             void setShowGrid(bool _needShowGrid) CV_OVERRIDE
176             {
177                 needShowGrid = _needShowGrid;
178             }
setShowText(bool _needShowText)179             void setShowText(bool _needShowText) CV_OVERRIDE
180             {
181                 needShowText = _needShowText;
182             }
setGridLinesNumber(int _gridLinesNumber)183             void setGridLinesNumber(int _gridLinesNumber) CV_OVERRIDE
184             {
185                 if(_gridLinesNumber <= 0)
186                     _gridLinesNumber = 1;
187                 gridLinesNumber = _gridLinesNumber;
188             }
setPointIdxToPrint(int _cursorPos)189             void setPointIdxToPrint(int _cursorPos) CV_OVERRIDE
190             {
191                 if(_cursorPos >= plotDataX.rows || _cursorPos < 0)
192                     _cursorPos = plotDataX.rows - 1;
193                 cursorPos = _cursorPos;
194             }
195             //render the plotResult to a Mat
render(OutputArray _plotResult)196             void render(OutputArray _plotResult) CV_OVERRIDE
197             {
198                 //create the plot result
199                 _plotResult.create(plotSizeHeight, plotSizeWidth, CV_8UC3);
200                 plotResult = _plotResult.getMat();
201                 plotResult.setTo(plotBackgroundColor);
202 
203                 int NumVecElements = plotDataX.rows;
204 
205                 Mat InterpXdata = linearInterpolation(plotMinX, plotMaxX, 0, plotSizeWidth, plotDataX);
206                 Mat InterpYdata = invertOrientation ?
207                                   linearInterpolation(plotMaxY, plotMinY, 0, plotSizeHeight, plotDataY) :
208                                   linearInterpolation(plotMinY, plotMaxY, 0, plotSizeHeight, plotDataY);
209 
210                 //Find the zeros in image coordinates
211                 Mat InterpXdataFindZero = linearInterpolation(plotMinX_plusZero, plotMaxX_plusZero, 0, plotSizeWidth, plotDataX_plusZero);
212                 Mat InterpYdataFindZero = invertOrientation ?
213                                           linearInterpolation(plotMaxY_plusZero, plotMinY_plusZero, 0, plotSizeHeight, plotDataY_plusZero) :
214                                           linearInterpolation(plotMinY_plusZero, plotMaxY_plusZero, 0, plotSizeHeight, plotDataY_plusZero);
215 
216                 int ImageXzero = (int)InterpXdataFindZero.at<double>(NumVecElements,0);
217                 int ImageYzero = (int)InterpYdataFindZero.at<double>(NumVecElements,0);
218 
219                 double CurrentX = plotDataX.at<double>(cursorPos,0);
220                 double CurrentY = plotDataY.at<double>(cursorPos,0);
221 
222                 drawAxis(ImageXzero,ImageYzero, CurrentX, CurrentY, plotAxisColor, plotGridColor);
223 
224                 if(needPlotLine)
225                 {
226                     //Draw the plot by connecting lines between the points
227                     Point p1;
228                     p1.x = (int)InterpXdata.at<double>(0,0);
229                     p1.y = (int)InterpYdata.at<double>(0,0);
230 
231                     for (int r=1; r<InterpXdata.rows; r++)
232                     {
233                         Point p2;
234                         p2.x = (int)InterpXdata.at<double>(r,0);
235                         p2.y = (int)InterpYdata.at<double>(r,0);
236 
237                         line(plotResult, p1, p2, plotLineColor, plotLineWidth, 8, 0);
238 
239                         p1 = p2;
240                     }
241                 }
242                 else
243                 {
244                     for (int r=0; r<InterpXdata.rows; r++)
245                     {
246                         Point p;
247                         p.x = (int)InterpXdata.at<double>(r,0);
248                         p.y = (int)InterpYdata.at<double>(r,0);
249 
250                         circle(plotResult, p, 1, plotLineColor, plotLineWidth, 8, 0);
251                     }
252                 }
253             }
254 
255             protected:
256 
257             Mat plotDataX;
258             Mat plotDataY;
259             Mat plotDataX_plusZero;
260             Mat plotDataY_plusZero;
261             const char * plotName;
262 
263             //dimensions and limits of the plot
264             int plotSizeWidth;
265             int plotSizeHeight;
266             double plotMinX;
267             double plotMaxX;
268             double plotMinY;
269             double plotMaxY;
270             double plotMinX_plusZero;
271             double plotMaxX_plusZero;
272             double plotMinY_plusZero;
273             double plotMaxY_plusZero;
274             int plotLineWidth;
275             bool invertOrientation;
276             bool needShowGrid;
277             bool needShowText;
278             int gridLinesNumber;
279             int cursorPos;
280 
281             //colors of each plot element
282             Scalar plotLineColor;
283             Scalar plotBackgroundColor;
284             Scalar plotAxisColor;
285             Scalar plotGridColor;
286             Scalar plotTextColor;
287 
288             //the final plot result
289             Mat plotResult;
290 
291             //flag which enables/disables connection of plotted points by lines
292             bool needPlotLine;
293 
plotHelper(Mat _plotDataX,Mat _plotDataY)294             void plotHelper(Mat _plotDataX, Mat _plotDataY)
295             {
296                 plotDataX=_plotDataX;
297                 plotDataY=_plotDataY;
298 
299                 int NumVecElements = plotDataX.rows;
300 
301                 plotDataX_plusZero = Mat::zeros(NumVecElements+1,1,CV_64F);
302                 plotDataY_plusZero = Mat::zeros(NumVecElements+1,1,CV_64F);
303 
304                 for(int i=0; i<NumVecElements; i++){
305                     plotDataX_plusZero.at<double>(i,0) = plotDataX.at<double>(i,0);
306                     plotDataY_plusZero.at<double>(i,0) = plotDataY.at<double>(i,0);
307                 }
308 
309                 double MinX;
310                 double MaxX;
311                 double MinY;
312                 double MaxY;
313                 double MinX_plusZero;
314                 double MaxX_plusZero;
315                 double MinY_plusZero;
316                 double MaxY_plusZero;
317 
318                 needPlotLine = true;
319                 invertOrientation = false;
320 
321                 //Obtain the minimum and maximum values of Xdata
322                 minMaxLoc(plotDataX,&MinX,&MaxX);
323 
324                 //Obtain the minimum and maximum values of Ydata
325                 minMaxLoc(plotDataY,&MinY,&MaxY);
326 
327                 //Obtain the minimum and maximum values of Xdata plus zero
328                 minMaxLoc(plotDataX_plusZero,&MinX_plusZero,&MaxX_plusZero);
329 
330                 //Obtain the minimum and maximum values of Ydata plus zero
331                 minMaxLoc(plotDataY_plusZero,&MinY_plusZero,&MaxY_plusZero);
332 
333                 //setting the min and max values for each axis
334                 plotMinX = MinX;
335                 plotMaxX = MaxX;
336                 plotMinY = MinY;
337                 plotMaxY = MaxY;
338                 plotMinX_plusZero = MinX_plusZero;
339                 plotMaxX_plusZero = MaxX_plusZero;
340                 plotMinY_plusZero = MinY_plusZero;
341                 plotMaxY_plusZero = MaxY_plusZero;
342 
343                 //setting the default size of a plot figure
344                 setPlotSize(600, 400);
345 
346                 //setting the default plot line size
347                 setPlotLineWidth(1);
348 
349                 //setting default colors for the different elements of the plot
350                 setPlotAxisColor(Scalar(0, 0, 255));
351                 setPlotGridColor(Scalar(255, 255, 255));
352                 setPlotBackgroundColor(Scalar(0, 0, 0));
353                 setPlotLineColor(Scalar(0, 255, 255));
354                 setPlotTextColor(Scalar(255, 255, 255));
355                 setShowGrid(true);
356                 setShowText(true);
357                 setGridLinesNumber(10);
358                 setPointIdxToPrint(-1);
359             }
360 
drawAxis(int ImageXzero,int ImageYzero,double CurrentX,double CurrentY,Scalar axisColor,Scalar gridColor)361             void drawAxis(int ImageXzero, int ImageYzero, double CurrentX, double CurrentY, Scalar axisColor, Scalar gridColor)
362             {
363                 if(needShowText)
364                 {
365                     drawValuesAsText(0, ImageXzero, ImageYzero, 10, 20);
366                     drawValuesAsText(0, ImageXzero, ImageYzero, -20, 20);
367                     drawValuesAsText(0, ImageXzero, ImageYzero, 10, -10);
368                     drawValuesAsText(0, ImageXzero, ImageYzero, -20, -10);
369                     drawValuesAsText((format("X_%d = ", cursorPos) + "%g").c_str(), CurrentX, 0, 0, 40, 20);
370                     drawValuesAsText((format("Y_%d = ", cursorPos) + "%g").c_str(), CurrentY, 0, 20, 40, 20);
371                 }
372 
373                 //Horizontal X axis and equispaced horizontal lines
374                 int LineSpace = cvRound(plotSizeHeight / (float)gridLinesNumber);
375                 int TraceSize = 5;
376                 drawLine(0, plotSizeWidth, ImageYzero, ImageYzero, axisColor);
377 
378                if(needShowGrid)
379                for(int i=-plotSizeHeight; i<plotSizeHeight; i=i+LineSpace){
380 
381                     if(i!=0){
382                         int Trace=0;
383                         while(Trace<plotSizeWidth){
384                             drawLine(Trace, Trace+TraceSize, ImageYzero+i, ImageYzero+i, gridColor);
385                             Trace = Trace+2*TraceSize;
386                         }
387                     }
388                 }
389 
390                 //Vertical Y axis
391                 drawLine(ImageXzero, ImageXzero, 0, plotSizeHeight, axisColor);
392                 LineSpace = cvRound(LineSpace * (float)plotSizeWidth / plotSizeHeight );
393 
394                 if(needShowGrid)
395                 for(int i=-plotSizeWidth; i<plotSizeWidth; i=i+LineSpace){
396 
397                     if(i!=0){
398                         int Trace=0;
399                         while(Trace<plotSizeHeight){
400                             drawLine(ImageXzero+i, ImageXzero+i, Trace, Trace+TraceSize, gridColor);
401                             Trace = Trace+2*TraceSize;
402                         }
403                     }
404                 }
405             }
406 
linearInterpolation(double Xa,double Xb,double Ya,double Yb,Mat Xdata)407             Mat linearInterpolation(double Xa, double Xb, double Ya, double Yb, Mat Xdata){
408 
409                 Mat Ydata = Xdata*0;
410 
411                 for (int i=0; i<Xdata.rows; i++){
412 
413                     double X = Xdata.at<double>(i,0);
414                     Ydata.at<double>(i,0) = int(Ya + (Yb-Ya)*(X-Xa)/(Xb-Xa));
415 
416                     if(Ydata.at<double>(i,0)<0)
417                         Ydata.at<double>(i,0)=0;
418                 }
419 
420                 return Ydata;
421             }
422 
drawValuesAsText(double Value,int Xloc,int Yloc,int XMargin,int YMargin)423             void drawValuesAsText(double Value, int Xloc, int Yloc, int XMargin, int YMargin){
424 
425                 char AxisX_Min_Text[20];
426                 double TextSize = 1;
427 
428                 sprintf(AxisX_Min_Text, "%g", Value);
429                 Point AxisX_Min_Loc;
430                 AxisX_Min_Loc.x = Xloc+XMargin;
431                 AxisX_Min_Loc.y = Yloc+YMargin;
432 
433                 putText(plotResult,AxisX_Min_Text, AxisX_Min_Loc, FONT_HERSHEY_COMPLEX_SMALL, TextSize, plotTextColor, 1, 8);
434             }
435 
drawValuesAsText(const char * Text,double Value,int Xloc,int Yloc,int XMargin,int YMargin)436             void drawValuesAsText(const char *Text, double Value, int Xloc, int Yloc, int XMargin, int YMargin){
437 
438                 char AxisX_Min_Text[20];
439                 int TextSize = 1;
440 
441                 sprintf(AxisX_Min_Text, Text, Value);
442                 Point AxisX_Min_Loc;
443                 AxisX_Min_Loc.x = Xloc+XMargin;
444                 AxisX_Min_Loc.y = Yloc+YMargin;
445 
446                 putText(plotResult,AxisX_Min_Text, AxisX_Min_Loc, FONT_HERSHEY_COMPLEX_SMALL, TextSize, plotTextColor, 1, 8);
447             }
448 
449 
drawLine(int Xstart,int Xend,int Ystart,int Yend,Scalar lineColor)450             void drawLine(int Xstart, int Xend, int Ystart, int Yend, Scalar lineColor){
451 
452                 Point Axis_start;
453                 Point Axis_end;
454                 Axis_start.x = Xstart;
455                 Axis_start.y = Ystart;
456                 Axis_end.x = Xend;
457                 Axis_end.y = Yend;
458 
459                 line(plotResult, Axis_start, Axis_end, lineColor, plotLineWidth, 8, 0);
460             }
461         };
462 
create(InputArray _plotData)463         Ptr<Plot2d> Plot2d::create(InputArray _plotData)
464         {
465             return Ptr<Plot2dImpl> (new Plot2dImpl (_plotData));
466         }
467 
create(InputArray _plotDataX,InputArray _plotDataY)468         Ptr<Plot2d> Plot2d::create(InputArray _plotDataX, InputArray _plotDataY)
469         {
470             return Ptr<Plot2dImpl> (new Plot2dImpl (_plotDataX, _plotDataY));
471         }
472     }
473 }
474