You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
wheeldetect/3part/Cyclops/3rd/cvplot/cvplot.cpp

526 lines
10 KiB
C++

// Matlab style plot functions for OpenCV by Changbo (zoccob@gmail).
#include "cvplot.h"
namespace CvPlot
{
// use anonymous namespace to hide global variables.
namespace
{
const CvScalar CV_BLACK = CV_RGB(0, 0, 0);
const CvScalar CV_WHITE = CV_RGB(255, 255, 255);
const CvScalar CV_GREY = CV_RGB(150, 150, 150);
PlotManager pm;
}
Series::Series(void)
{
data = NULL;
label = "";
Clear();
}
Series::Series(const Series& s):count(s.count), label(s.label), auto_color(s.auto_color), color(s.color)
{
data = new float[count];
memcpy(data, s.data, count * sizeof(float));
}
Series::~Series(void)
{
Clear();
}
void Series::Clear(void)
{
if (data != NULL)
delete [] data;
data = NULL;
count = 0;
color = CV_BLACK;
auto_color = true;
label = "";
}
void Series::SetData(int n, float *p)
{
Clear();
count = n;
data = p;
}
void Series::SetColor(int R, int G, int B, bool auto_color)
{
R = R > 0 ? R : 0;
G = G > 0 ? G : 0;
B = B > 0 ? B : 0;
color = CV_RGB(R, G, B);
SetColor(color, auto_color);
}
void Series::SetColor(CvScalar color, bool auto_color)
{
this->color = color;
this->auto_color = auto_color;
}
Figure::Figure(const string name)
: output(NULL)
{
figure_name = name;
custom_range_y = false;
custom_range_x = false;
background_color = CV_WHITE;
axis_color = CV_BLACK;
text_color = CV_BLACK;
figure_size = cvSize(600, 200);
border_size = 30;
plots.reserve(10);
}
Figure::~Figure(void)
{
}
string Figure::GetFigureName(void)
{
return figure_name;
}
Series* Figure::Add(const Series &s)
{
plots.push_back(s);
return &(plots.back());
}
void Figure::Clear()
{
plots.clear();
}
void Figure::Initialize()
{
color_index = 0;
// size of the figure
if (figure_size.width <= border_size * 2 + 100)
figure_size.width = border_size * 2 + 100;
if (figure_size.height <= border_size * 2 + 200)
figure_size.height = border_size * 2 + 200;
y_max = FLT_MIN;
y_min = FLT_MAX;
x_max = 0;
x_min = 0;
// find maximum/minimum of axes
for (vector<Series>::iterator iter = plots.begin();
iter != plots.end();
iter++)
{
float *p = iter->data;
for (int i=0; i < iter->count; i++)
{
float v = p[i];
if (v < y_min)
y_min = v;
if (v > y_max)
y_max = v;
}
if (x_max < iter->count)
x_max = iter->count;
}
// calculate zoom scale
// set to 2 if y range is too small
float y_range = y_max - y_min;
float eps = 1e-9f;
if (y_range <= eps)
{
y_range = 1;
y_min = y_max / 2;
y_max = y_max * 3 / 2;
}
x_scale = 1.0f;
if (x_max - x_min > 1)
x_scale = (float)(figure_size.width - border_size * 2) / (x_max - x_min);
y_scale = (float)(figure_size.height - border_size * 2) / y_range;
}
CvScalar Figure::GetAutoColor()
{
// change color for each curve.
CvScalar col;
switch (color_index)
{
case 1:
col = CV_RGB(60,60,255); // light-blue
break;
case 2:
col = CV_RGB(60,255,60); // light-green
break;
case 3:
col = CV_RGB(255,60,40); // light-red
break;
case 4:
col = CV_RGB(0,210,210); // blue-green
break;
case 5:
col = CV_RGB(180,210,0); // red-green
break;
case 6:
col = CV_RGB(210,0,180); // red-blue
break;
case 7:
col = CV_RGB(0,0,185); // dark-blue
break;
case 8:
col = CV_RGB(0,185,0); // dark-green
break;
case 9:
col = CV_RGB(185,0,0); // dark-red
break;
default:
col = CV_RGB(200,200,200); // grey
color_index = 0;
}
color_index++;
return col;
}
void Figure::DrawAxis(IplImage *output)
{
int bs = border_size;
int h = figure_size.height;
int w = figure_size.width;
// size of graph
int gh = h - bs * 2;
int gw = w - bs * 2;
// draw the horizontal and vertical axis
// let x, y axies cross at zero if possible.
float y_ref = y_min;
if ((y_max > 0) && (y_min <= 0))
y_ref = 0;
int x_axis_pos = h - bs - cvRound((y_ref - y_min) * y_scale);
cvLine(output, cvPoint(bs, x_axis_pos),
cvPoint(w - bs, x_axis_pos),
axis_color);
cvLine(output, cvPoint(bs, h - bs),
cvPoint(bs, h - bs - gh),
axis_color);
// Write the scale of the y axis
CvFont font;
cvInitFont(&font,CV_FONT_HERSHEY_PLAIN,0.55,0.7, 0,1,CV_AA);
int chw = 6, chh = 10;
char text[16];
// y max
if ((y_max - y_ref) > 0.05 * (y_max - y_min))
{
snprintf(text, sizeof(text)-1, "%.1f", y_max);
cvPutText(output, text, cvPoint(bs / 5, bs - chh / 2), &font, text_color);
}
// y min
if ((y_ref - y_min) > 0.05 * (y_max - y_min))
{
snprintf(text, sizeof(text)-1, "%.1f", y_min);
cvPutText(output, text, cvPoint(bs / 5, h - bs + chh), &font, text_color);
}
// x axis
snprintf(text, sizeof(text)-1, "%.1f", y_ref);
cvPutText(output, text, cvPoint(bs / 5, x_axis_pos + chh / 2), &font, text_color);
// Write the scale of the x axis
snprintf(text, sizeof(text)-1, "%.0f", x_max );
cvPutText(output, text, cvPoint(w - bs - strlen(text) * chw, x_axis_pos + chh),
&font, text_color);
// x min
snprintf(text, sizeof(text)-1, "%.0f", x_min );
cvPutText(output, text, cvPoint(bs, x_axis_pos + chh),
&font, text_color);
}
void Figure::DrawPlots(IplImage *output)
{
int bs = border_size;
int h = figure_size.height;
int w = figure_size.width;
// draw the curves
for (vector<Series>::iterator iter = plots.begin();
iter != plots.end();
iter++)
{
float *p = iter->data;
// automatically change curve color
if (iter->auto_color == true)
iter->SetColor(GetAutoColor());
CvPoint prev_point;
for (int i=0; i<iter->count; i++)
{
int y = cvRound(( p[i] - y_min) * y_scale);
int x = cvRound(( i - x_min) * x_scale);
CvPoint next_point = cvPoint(bs + x, h - (bs + y));
cvCircle(output, next_point, 1, iter->color, 1);
// draw a line between two points
if (i >= 1)
cvLine(output, prev_point, next_point, iter->color, 1, CV_AA);
prev_point = next_point;
}
}
}
void Figure::DrawLabels(IplImage *output, int posx, int posy)
{
CvFont font;
cvInitFont(&font,CV_FONT_HERSHEY_PLAIN,0.55,1.0, 0,1,CV_AA);
// character size
int chw = 6, chh = 8;
for (vector<Series>::iterator iter = plots.begin();
iter != plots.end();
iter++)
{
string lbl = iter->label;
// draw label if one is available
if (lbl.length() > 0)
{
cvLine(output, cvPoint(posx, posy - chh / 2), cvPoint(posx + 15, posy - chh / 2),
iter->color, 2, CV_AA);
cvPutText(output, lbl.c_str(), cvPoint(posx + 20, posy),
&font, iter->color);
posy += int(chh * 1.5);
}
}
}
// whole process of draw a figure.
void Figure::Show()
{
Initialize();
if (output)
{
if (output->width != figure_size.width ||
output->height != figure_size.height)
{
cvReleaseImage(&output);
output = NULL;
}
}
if (!output)
{
output = cvCreateImage(figure_size, IPL_DEPTH_8U, 3);
}
cvSet(output, background_color, 0);
DrawAxis(output);
DrawPlots(output);
DrawLabels(output, figure_size.width - 100, 10);
cvShowImage(figure_name.c_str(), output);
cvWaitKey(1);
}
IplImage * Figure::getOutput() const
{
if (output)
{
IplImage* pRet = cvCloneImage(output);
return pRet;
}
else
{
return NULL;
}
}
bool PlotManager::HasFigure(string wnd)
{
return false;
}
// search a named window, return null if not found.
Figure* PlotManager::FindFigure(string wnd)
{
for(vector<Figure>::iterator iter = figure_list.begin();
iter != figure_list.end();
iter++)
{
if (iter->GetFigureName() == wnd)
return &(*iter);
}
return NULL;
}
// plot a new curve, if a figure of the specified figure name already exists,
// the curve will be plot on that figure; if not, a new figure will be created.
void PlotManager::Plot(const string figure_name, const float *p, int count, int step,
int R, int G, int B)
{
if (count < 1)
return;
if (step <= 0)
step = 1;
// copy data and create a series format.
float *data_copy = new float[count];
for (int i = 0; i < count; i++)
*(data_copy + i) = *(p + step * i);
Series s;
s.SetData(count, data_copy);
if ((R > 0) || (G > 0) || (B > 0))
s.SetColor(R, G, B, false);
// search the named window and create one if none was found
active_figure = FindFigure(figure_name);
if ( active_figure == NULL)
{
Figure new_figure(figure_name);
figure_list.push_back(new_figure);
active_figure = FindFigure(figure_name);
if (active_figure == NULL)
exit(-1);
}
active_series = active_figure->Add(s);
active_figure->Show();
}
// add a label to the most recently added curve
void PlotManager::Label(string lbl)
{
if((active_series!=NULL) && (active_figure != NULL))
{
active_series->label = lbl;
active_figure->Show();
}
}
// delete all plots on a specified figure
void clear(const string figure_name)
{
Figure *fig = pm.FindFigure(figure_name);
if (fig != NULL)
{
fig->Clear();
}
}
// add a label to the most recently added curve
// static method
void label(string lbl)
{
pm.Label(lbl);
}
// plot a new curve, if a figure of the specified figure name already exists,
// the curve will be plot on that figure; if not, a new figure will be created.
// static method
template<typename T>
void plot(const string figure_name, const T* p, int count, int step /*= 1*/, int R /*= -1*/, int G /*= -1*/, int B /*= -1*/)
{
if (step <= 0)
step = 1;
float *data_copy = new float[count * step];
float *dst = data_copy;
const T *src = p;
for (int i = 0; i < count * step; i++)
{
*dst = (float)(*src);
dst++;
src++;
}
pm.Plot(figure_name, data_copy, count, step, R, G, B);
delete[] data_copy;
}
template
void plot(const string figure_name, const unsigned char* p, int count, int step,
int R, int G, int B);
template
void plot(const string figure_name, const int* p, int count, int step,
int R, int G, int B);
template
void plot(const string figure_name, const short* p, int count, int step,
int R, int G, int B);
template
void plot(const string figure_name, const float* p, int count, int step,
int R, int G, int B);
IplImage* getPlotImage(const string figure_name)
{
Figure* pFigure = pm.FindFigure(figure_name);
if (!pFigure)
{
return NULL;
}
IplImage* pImage = pFigure->getOutput();
return pImage;
}
bool savePlotImage(const string figure_name, const string file_name)
{
IplImage* pImage = getPlotImage(figure_name);
if (pImage)
{
cvSaveImage(file_name.data(), pImage);
return true;
}
else
{
return false;
}
}
};