I want to draw an open polygon with say 50 sides. Now I am looking for a way to have each side a different color, depending on an index, eg:
polygon_coordinates = [ [5, 10], [7, 9], [8, 11], [11, 20] ]
color_index = [100, 75, 200]
I am looking for something like
import cv2
for i in range (0, len(polygon_coordinates)-1):
cv2.polylines([polygon_coordinates[i],polygon_coordinates[i+1]], color=[color_index[i], color_index[i], color_index[i]])
Is there a way for that, ideally without a loop? Thanks for the help
This is probably not the answer you are looking for:)
Short answer is not really. You cannot do that in cv2. I also checked about 5 or 6 other libraries and it is the same for them as well (I am sure you have done that too).
Not all is lost though. I have a strong feeling that the polylines in cv2 is implemented by using the line function. From my rusty cpp years, here is what I gathered when I delved into the source code for OpenCV for linux and mac (https://github.com/Itseez/opencv/archive/3.0.0.zip):
In opencv-3.0.0/modules/imgproc/src/drawing.cpp
polylines call PolyLine to do the drawing at the end of the code block
void polylines( Mat& img, const Point* const* pts, const int* npts, int ncontours, bool isClosed,
const Scalar& color, int thickness, int line_type, int shift )
{
if( line_type == CV_AA && img.depth() != CV_8U )
line_type = 8;
CV_Assert( pts && npts && ncontours >= 0 &&
0 <= thickness && thickness <= MAX_THICKNESS &&
0 <= shift && shift <= XY_SHIFT );
double buf[4];
scalarToRawData( color, buf, img.type(), 0 );
for( int i = 0; i < ncontours; i++ )
PolyLine( img, pts[i], npts[i], isClosed, buf, thickness, line_type, shift );
}
PolyLine calls ThickLine to draw segments by looping.
PolyLine( Mat& img, const Point* v, int count, bool is_closed,
const void* color, int thickness,
int line_type, int shift )
{
if( !v || count <= 0 )
return;
int i = is_closed ? count - 1 : 0;
int flags = 2 + !is_closed;
Point p0;
CV_Assert( 0 <= shift && shift <= XY_SHIFT && thickness >= 0 );
p0 = v[i];
for( i = !is_closed; i < count; i++ )
{
Point p = v[i];
ThickLine( img, p0, p, color, thickness, line_type, flags, shift );
p0 = p;
flags = 2;
}
}
ThickLine in turn invokes various Line functions to do its implementations, truncated here because it is a long function but just look at what it does when drawing lines of thickness of 1 or less, it calls the Line function
ThickLine( Mat& img, Point p0, Point p1, const void* color,
int thickness, int line_type, int flags, int shift )
{
static const double INV_XY_ONE = 1./XY_ONE;
p0.x <<= XY_SHIFT - shift;
p0.y <<= XY_SHIFT - shift;
p1.x <<= XY_SHIFT - shift;
p1.y <<= XY_SHIFT - shift;
if( thickness <= 1 )
{
if( line_type < CV_AA )
{
if( line_type == 1 || line_type == 4 || shift == 0 )
{
p0.x = (p0.x + (XY_ONE>>1)) >> XY_SHIFT;
p0.y = (p0.y + (XY_ONE>>1)) >> XY_SHIFT;
p1.x = (p1.x + (XY_ONE>>1)) >> XY_SHIFT;
p1.y = (p1.y + (XY_ONE>>1)) >> XY_SHIFT;
Line( img, p0, p1, color, line_type );
}
else
Line2( img, p0, p1, color );
}
else
LineAA( img, p0, p1, color );
}
...
And finally Line (and its variations like Line2 etc) just plot points:
Line( Mat& img, Point pt1, Point pt2,
const void* _color, int connectivity = 8 )
{
if( connectivity == 0 )
connectivity = 8;
else if( connectivity == 1 )
connectivity = 4;
LineIterator iterator(img, pt1, pt2, connectivity, true);
int i, count = iterator.count;
int pix_size = (int)img.elemSize();
const uchar* color = (const uchar*)_color;
for( i = 0; i < count; i++, ++iterator )
{
uchar* ptr = *iterator;
if( pix_size == 1 )
ptr[0] = color[0];
else if( pix_size == 3 )
{
ptr[0] = color[0];
ptr[1] = color[1];
ptr[2] = color[2];
}
else
memcpy( *iterator, color, pix_size );
}
}
That means that there shouldn't be too much of a performance hit for calling lines over polylines because the C++ code is doing more or less the same thing: iterate over a line drawing function.
If you want to test this, you can probably draw a single colored polygon with a number of sides close to what you need to use in your application by calling polylines and line and timing them. Here is a very quick and dirty example of how you can time stuff in Python from Learning Python 5th Edition page 630:
import time
def timer(func, *args):
start = time.clock()
for i in range(1000):
func(*args)
return time.clock() - start
I am sure you can find much better tools than this to test though:)
One last thought: If I am wrong and there is a noticeable performance difference between two methods, you can always optimize your code afterwards for more speed. There are tons of tools to speed up Python tools. You can start by looking at PyPy.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With