缓冲区颜色绘制函数
opencv里面对每次绘制产生一个大小为4的缓冲数组,通过循环赋值将颜色赋值到数组里面
void scalarToRawData_(const Scalar& s, T * const buf, const int cn, const int unroll_to)
{
int i = 0;
for(; i < cn; i++)
buf[i] = saturate_cast<T>(s.val[i]);
for(; i < unroll_to; i++)
buf[i] = buf[i-cn];
}
circle函数
1.用法:主要需要我们传入的参数有,目标矩阵,圆心,半径,颜色,厚度(该参数默认为-1),line_type(该参数是指绘图时线的产生方法,默认为8连通线算法)
/*************************************************************/
2.函数的实现思路主要就是
通过mat类获取矩阵信息----将颜色值导入缓冲区数组----判断画圆的厚度是否大于1来实现不同的绘制
void circle( InputOutputArray _img, Point center, int radius,
const Scalar& color, int thickness, int line_type, int shift )
{
CV_INSTRUMENT_REGION();
Mat img = _img.getMat();
if( line_type == CV_AA && img.depth() != CV_8U )
line_type = 8;
CV_Assert( radius >= 0 && thickness <= MAX_THICKNESS &&
0 <= shift && shift <= XY_SHIFT );
double buf[4];
scalarToRawData(color, buf, img.type(), 0);
if( thickness > 1 || line_type != LINE_8 || shift > 0 )
{
Point2l _center(center);
int64 _radius(radius);
_center.x <<= XY_SHIFT - shift;
_center.y <<= XY_SHIFT - shift;
_radius <<= XY_SHIFT - shift;
EllipseEx( img, _center, Size2l(_radius, _radius),
0, 0, 360, buf, thickness, line_type );
}
else
Circle( img, center, radius, buf, thickness < 0 );
}
2.Circle函数
上来就是获取mat类的指针,通过该指针获取每个像素位置的信息
然后通过inside变量判断该圆形是否有超出图片的范围,不超则设置为1
注意这里的radius(半径变量)通过跟踪发现,主要是用于实现函数的求导即dx
绘制部分:
通过导数和指针的配合,找到圆的下一个绘制点,调用绘制函数为其赋值
Circle( Mat& img, Point center, int radius, const void* color, int fill )
{
Size size = img.size();
size_t step = img.step;
int pix_size = (int)img.elemSize();
uchar* ptr = img.ptr();
int err = 0, dx = radius, dy = 0, plus = 1, minus = (radius << 1) - 1;
int inside = center.x >= radius && center.x < size.width - radius &&
center.y >= radius && center.y < size.height - radius;
#define ICV_PUT_POINT( ptr, x ) \
memcpy( ptr + (x)*pix_size, color, pix_size );
while( dx >= dy )
{
int mask;
int y11 = center.y - dy, y12 = center.y + dy, y21 = center.y - dx, y22 = center.y + dx;
int x11 = center.x - dx, x12 = center.x + dx, x21 = center.x - dy, x22 = center.x + dy;
if( inside )
{
uchar *tptr0 = ptr + y11 * step;
uchar *tptr1 = ptr + y12 * step;
if( !fill )
{
ICV_PUT_POINT( tptr0, x11 );
ICV_PUT_POINT( tptr1, x11 );
ICV_PUT_POINT( tptr0, x12 );
ICV_PUT_POINT( tptr1, x12 );
}
else
{
ICV_HLINE( tptr0, x11, x12, color, pix_size );
ICV_HLINE( tptr1, x11, x12, color, pix_size );
}
tptr0 = ptr + y21 * step;
tptr1 = ptr + y22 * step;
if( !fill )
{
ICV_PUT_POINT( tptr0, x21 );
ICV_PUT_POINT( tptr1, x21 );
ICV_PUT_POINT( tptr0, x22 );
ICV_PUT_POINT( tptr1, x22 );
}
else
{
ICV_HLINE( tptr0, x21, x22, color, pix_size );
ICV_HLINE( tptr1, x21, x22, color, pix_size );
}
}
else if( x11 < size.width && x12 >= 0 && y21 < size.height && y22 >= 0 )
{
if( fill )
{
x11 = std::max( x11, 0 );
x12 = MIN( x12, size.width - 1 );
}
if( (unsigned)y11 < (unsigned)size.height )
{
uchar *tptr = ptr + y11 * step;
if( !fill )
{
if( x11 >= 0 )
ICV_PUT_POINT( tptr, x11 );
if( x12 < size.width )
ICV_PUT_POINT( tptr, x12 );
}
else
ICV_HLINE( tptr, x11, x12, color, pix_size );
}
if( (unsigned)y12 < (unsigned)size.height )
{
uchar *tptr = ptr + y12 * step;
if( !fill )
{
if( x11 >= 0 )
ICV_PUT_POINT( tptr, x11 );
if( x12 < size.width )
ICV_PUT_POINT( tptr, x12 );
}
else
ICV_HLINE( tptr, x11, x12, color, pix_size );
}
if( x21 < size.width && x22 >= 0 )
{
if( fill )
{
x21 = std::max( x21, 0 );
x22 = MIN( x22, size.width - 1 );
}
if( (unsigned)y21 < (unsigned)size.height )
{
uchar *tptr = ptr + y21 * step;
if( !fill )
{
if( x21 >= 0 )
ICV_PUT_POINT( tptr, x21 );
if( x22 < size.width )
ICV_PUT_POINT( tptr, x22 );
}
else
ICV_HLINE( tptr, x21, x22, color, pix_size );
}
if( (unsigned)y22 < (unsigned)size.height )
{
uchar *tptr = ptr + y22 * step;
if( !fill )
{
if( x21 >= 0 )
ICV_PUT_POINT( tptr, x21 );
if( x22 < size.width )
ICV_PUT_POINT( tptr, x22 );
}
else
ICV_HLINE( tptr, x21, x22, color, pix_size );
}
}
}
dy++;
err += plus;
plus += 2;
mask = (err <= 0) - 1;
err -= minus & mask;
dx += mask;
minus -= mask & 2;
}
#undef ICV_PUT_POINT
}