Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

How to draw gradient?

How can I draw gradient like this?

image description

How to draw gradient?

How can I draw gradient like this?

image description

I want to draw gradient of circle.

First idea, I could create a white line and empty image I. Then to go through loop with angle from 0 to 89, in every iteration do I++; and angle++; rotate this line with fixed origin at x=radius, y=0; This would create one image of gradient. Then I need to copy the image 3 times in a loop rotating it +90° in every iteration.

Now I ask what functions to use to copy the pixels from the original line to the image using rotation and how to do the same with an image. It's basically the same difference is only in image dimensions. That line is radius,0 and image dimensions are radius*2,radius,2

How to draw gradient?

How can I draw gradient like this?

image description

I want to draw gradient of circle.

First idea, I could create a white line and empty image I. Then to go through loop with angle from 0 to 89, in every iteration do I++; and angle++; rotate this line with fixed origin at x=radius, y=0; This would create one image of gradient. Then I need to copy the image 3 times in a loop rotating it +90° in every iteration.

Now I ask what functions to use to copy the pixels from the original line to the image using rotation and how to do the same with an image. It's basically the same difference is only in image dimensions. That line is radius,0 and image dimensions are radius*2,radius,2

What I tried after Lorena pointed me to try linearPolar:

int radius = 4;
int side = 2*radius;
int size = 1 + 2*side;
Mat I = Mat::zeros(size, size, CV_8UC1);
Point center; 
center.x = 2*radius+1 -1; center.y = 2*radius+1 -1;
int sigma = radius%2==0 ? radius+1 : radius;
cv::Size kernelSize = CvSize(sigma, sigma);

Mat L = Mat::zeros(1, center.x, CV_8UC1);
I = Mat::zeros(size, size, CV_8UC1);
Point a,b;

L = Mat::zeros(center.x, 1, CV_8UC1);
a.x=0; a.y = 0; b.x=0; b.y = radius-1;
line( L, a, b, cv::Scalar( 255, 255, 255 ), 1, 8 );
cv::GaussianBlur( L, L, kernelSize, sigma );

imshow("blured line",L);
waitKey(0);
cv::Size dsize= cv::Size(radius*10, radius*10);

resize(L, I, dsize );
Point2f  fcenter; 
fcenter.x = (float) radius/16 ;
fcenter.y = (float) radius/16 ;
cv::linearPolar(I, I, fcenter, radius, INTER_LINEAR );
imshow("linearPolar",I);
waitKey(0);

The resulting image contains some gradient which is horizontal instead circular.

How to draw gradient?

How can I draw gradient like this?

image description

I want to draw gradient of circle.

First idea, I could create a white line and empty image I. Then to go through loop with angle from 0 to 89, in every iteration do I++; and angle++; rotate this line with fixed origin at x=radius, y=0; This would create one image of gradient. Then I need to copy the image 3 times in a loop rotating it +90° in every iteration.

Now I ask what functions to use to copy the pixels from the original line to the image using rotation and how to do the same with an image. It's basically the same difference is only in image dimensions. That line is radius,0 and image dimensions are radius*2,radius,2

What I tried after Lorena pointed me to try linearPolar:

int radius = 4;
int side = 2*radius;
int size = 1 + 2*side;
Mat I = Mat::zeros(size, size, CV_8UC1);
Point center; 
center.x = 2*radius+1 -1; center.y = 2*radius+1 -1;
int sigma = radius%2==0 ? radius+1 : radius;
cv::Size kernelSize = CvSize(sigma, sigma);

Mat L = Mat::zeros(1, center.x, CV_8UC1);
I = Mat::zeros(size, size, CV_8UC1);
Point a,b;

L = Mat::zeros(center.x, 1, CV_8UC1);
a.x=0; a.y = 0; b.x=0; b.y = radius-1;
line( L, a, b, cv::Scalar( 255, 255, 255 ), 1, 8 );
cv::GaussianBlur( L, L, kernelSize, sigma );

imshow("blured line",L);
waitKey(0);
cv::Size dsize= cv::Size(radius*10, radius*10);

resize(L, I, dsize );
Point2f  fcenter; 
fcenter.x = (float) radius/16 ;
fcenter.y = (float) radius/16 ;
cv::linearPolar(I, I, fcenter, radius, INTER_LINEAR );
imshow("linearPolar",I);
waitKey(0);

The resulting image contains some gradient which is horizontal instead circular.

Edit: New code (radius 25) - same problem:

// Mat::zeros( 5, 5, CV_8UC3 );
int radius = 25;
int side = 2*radius;
int size = 1 + 2*side;
Mat I = Mat::zeros(size, size, CV_8UC1);
Point center; 
center.x = 2*radius+1 -1; center.y = 2*radius+1 -1;
/*
circle( I,
    center,
    radius,
    cv::Scalar( 255, 255, 255 ),
    -1, // when thickness is negative, filled circle is drawn
    8 );
imshow("circle",I);
waitKey(0);*/
int sigma = radius%2==0 ? radius+1 : radius;
cv::Size kernelSize = CvSize(sigma, sigma);
/*
cv::GaussianBlur( I, I, kernelSize, sigma );
imshow("blured circle",I);
waitKey(0);*/

/** ANGLE GRADIENT **/
Mat L = Mat::zeros(1, center.x, CV_8UC1);
I = Mat::zeros(size, size, CV_8UC1);

Point a,b; 
/*
a.x=0; a.y = 0; b.x=radius; b.y = 0;
int c = 255;
line( I, a, b, cv::Scalar( c ), 1, 8 );
*/

/** ANGLE GRADIENT **/
L = Mat::zeros(center.x, 1, CV_8UC1);
a.x=0; a.y = 0; b.x=0; b.y = radius-1;
line( L, a, b, cv::Scalar( 255, 255, 255 ), 1, 8 );
cv::GaussianBlur( L, L, kernelSize, sigma );

imshow("blured line",L);
waitKey(0);
cv::Size dsize= cv::Size(size, size);

resize(L, I, dsize );
Point2f  fcenter; 
fcenter.x = (float) radius ;
fcenter.y = (float) radius ;
cv::linearPolar(I, I, fcenter, size, INTER_LINEAR );
imshow("linearPolar",I);
waitKey(0);

How to draw gradient?

How can I draw gradient like this?

image description

I want to draw gradient of circle.

First idea, I could create a white line and empty image I. Then to go through loop with angle from 0 to 89, in every iteration do I++; and angle++; rotate this line with fixed origin at x=radius, y=0; This would create one image of gradient. Then I need to copy the image 3 times in a loop rotating it +90° in every iteration.

Now I ask what functions to use to copy the pixels from the original line to the image using rotation and how to do the same with an image. It's basically the same difference is only in image dimensions. That line is radius,0 and image dimensions are radius*2,radius,2

What I tried after Lorena pointed me to try linearPolar:

int radius = 4;
int side = 2*radius;
int size = 1 + 2*side;
Mat I = Mat::zeros(size, size, CV_8UC1);
Point center; 
center.x = 2*radius+1 -1; center.y = 2*radius+1 -1;
int sigma = radius%2==0 ? radius+1 : radius;
cv::Size kernelSize = CvSize(sigma, sigma);

Mat L = Mat::zeros(1, center.x, CV_8UC1);
I = Mat::zeros(size, size, CV_8UC1);
Point a,b;

L = Mat::zeros(center.x, 1, CV_8UC1);
a.x=0; a.y = 0; b.x=0; b.y = radius-1;
line( L, a, b, cv::Scalar( 255, 255, 255 ), 1, 8 );
cv::GaussianBlur( L, L, kernelSize, sigma );

imshow("blured line",L);
waitKey(0);
cv::Size dsize= cv::Size(radius*10, radius*10);

resize(L, I, dsize );
Point2f  fcenter; 
fcenter.x = (float) radius/16 ;
fcenter.y = (float) radius/16 ;
cv::linearPolar(I, I, fcenter, radius, INTER_LINEAR );
imshow("linearPolar",I);
waitKey(0);

The resulting image contains some gradient which is horizontal instead circular.

Edit: New code (radius 25) - same problem:

// Mat::zeros( 5, 5, CV_8UC3 );
int radius = 25;
int side = 2*radius;
int size = 1 + 2*side;
Mat I = Mat::zeros(size, size, CV_8UC1);
Point center; 
center.x = 2*radius+1 -1; center.y = 2*radius+1 -1;
/*
circle( I,
    center,
    radius,
    cv::Scalar( 255, 255, 255 ),
    -1, // when thickness is negative, filled circle is drawn
    8 );
imshow("circle",I);
waitKey(0);*/
int sigma = radius%2==0 ? radius+1 : radius;
cv::Size kernelSize = CvSize(sigma, sigma);
/*
cv::GaussianBlur( I, I, kernelSize, sigma );
imshow("blured circle",I);
waitKey(0);*/

/** ANGLE GRADIENT **/
Mat L = Mat::zeros(1, center.x, CV_8UC1);
I = Mat::zeros(size, size, CV_8UC1);

Point a,b; 
/*
a.x=0; a.y = 0; b.x=radius; b.y = 0;
int c = 255;
line( I, a, b, cv::Scalar( c ), 1, 8 );
*/

/** ANGLE GRADIENT **/
L = Mat::zeros(center.x, 1, CV_8UC1);
a.x=0; a.y = 0; b.x=0; b.y = radius-1;
line( L, a, b, cv::Scalar( 255, 255, 255 ), 1, 8 );
cv::GaussianBlur( L, L, kernelSize, sigma );

imshow("blured line",L);
waitKey(0);
cv::Size dsize= cv::Size(size, size);

resize(L, I, dsize );
Point2f  fcenter; 
fcenter.x = (float) radius ;
fcenter.y = (float) radius ;
cv::linearPolar(I, I, fcenter, size, INTER_LINEAR );
imshow("linearPolar",I);
waitKey(0);

Edit: Another try as a reaction on answer is to try small image.

int radius = 25;
int side = 2*radius;
int size = 1 + 2*side;
Mat I = Mat::zeros(size, size, CV_8UC1);

Point center; 
center.x = 2*radius+1 -1; center.y = 2*radius+1 -1;

// This will have only small steps
int cStep = static_cast<int> ( std::ceil( (double) (255 / I.rows ) ) );
// Here I had problems, it would be better use integer divisions
float d =  cStep + (float) (255 % I.rows) /100 ;
d =  static_cast<float>( ((int)(d * 10 + .5) / 10.0) );
float m =  static_cast<float>( ((int)(d * 1 + .5) / 1.0) );
m = m-d; // remains after division by float value
m = 1/m;  // 1/remains
int n = static_cast<int>(m);
int c = -cStep;
float res;

I = Mat::zeros(size, size, CV_8UC1);

int f;
for (int r = 0; r < I.rows; r++)
    {
        c += cStep;
        I.row(r).setTo(c); 
        res = d*(r+1);
        if ( r % n == 0 )
            c++; // it will finish at 250 not 255, the last loop is not applied
    }
imshow("Polar Gradient", I);
waitKey(0);
cv::linearPolar(I, I, 
    cv::Point(I.cols/2, I.rows/2), 
    side+1, 
    INTER_CUBIC | WARP_FILL_OUTLIERS | WARP_INVERSE_MAP);
imshow("Polar Gradient", I);
waitKey(0);

How to draw gradient?

How can I draw gradient like this?

image description

I want to draw gradient of circle.

First idea, I could create a white line and empty image I. Then to go through loop with angle from 0 to 89, in every iteration do I++; and angle++; rotate this line with fixed origin at x=radius, y=0; This would create one image of gradient. Then I need to copy the image 3 times in a loop rotating it +90° in every iteration.

Now I ask what functions to use to copy the pixels from the original line to the image using rotation and how to do the same with an image. It's basically the same difference is only in image dimensions. That line is radius,0 and image dimensions are radius*2,radius,2

What I tried after Lorena pointed me to try linearPolar:

int radius = 4;
int side = 2*radius;
int size = 1 + 2*side;
Mat I = Mat::zeros(size, size, CV_8UC1);
Point center; 
center.x = 2*radius+1 -1; center.y = 2*radius+1 -1;
int sigma = radius%2==0 ? radius+1 : radius;
cv::Size kernelSize = CvSize(sigma, sigma);

Mat L = Mat::zeros(1, center.x, CV_8UC1);
I = Mat::zeros(size, size, CV_8UC1);
Point a,b;

L = Mat::zeros(center.x, 1, CV_8UC1);
a.x=0; a.y = 0; b.x=0; b.y = radius-1;
line( L, a, b, cv::Scalar( 255, 255, 255 ), 1, 8 );
cv::GaussianBlur( L, L, kernelSize, sigma );

imshow("blured line",L);
waitKey(0);
cv::Size dsize= cv::Size(radius*10, radius*10);

resize(L, I, dsize );
Point2f  fcenter; 
fcenter.x = (float) radius/16 ;
fcenter.y = (float) radius/16 ;
cv::linearPolar(I, I, fcenter, radius, INTER_LINEAR );
imshow("linearPolar",I);
waitKey(0);

The resulting image contains some gradient which is horizontal instead circular.

Edit: New code (radius 25) - same problem:

// Mat::zeros( 5, 5, CV_8UC3 );
int radius = 25;
int side = 2*radius;
int size = 1 + 2*side;
Mat I = Mat::zeros(size, size, CV_8UC1);
Point center; 
center.x = 2*radius+1 -1; center.y = 2*radius+1 -1;
/*
circle( I,
    center,
    radius,
    cv::Scalar( 255, 255, 255 ),
    -1, // when thickness is negative, filled circle is drawn
    8 );
imshow("circle",I);
waitKey(0);*/
int sigma = radius%2==0 ? radius+1 : radius;
cv::Size kernelSize = CvSize(sigma, sigma);
/*
cv::GaussianBlur( I, I, kernelSize, sigma );
imshow("blured circle",I);
waitKey(0);*/

/** ANGLE GRADIENT **/
Mat L = Mat::zeros(1, center.x, CV_8UC1);
I = Mat::zeros(size, size, CV_8UC1);

Point a,b; 
/*
a.x=0; a.y = 0; b.x=radius; b.y = 0;
int c = 255;
line( I, a, b, cv::Scalar( c ), 1, 8 );
*/

/** ANGLE GRADIENT **/
L = Mat::zeros(center.x, 1, CV_8UC1);
a.x=0; a.y = 0; b.x=0; b.y = radius-1;
line( L, a, b, cv::Scalar( 255, 255, 255 ), 1, 8 );
cv::GaussianBlur( L, L, kernelSize, sigma );

imshow("blured line",L);
waitKey(0);
cv::Size dsize= cv::Size(size, size);

resize(L, I, dsize );
Point2f  fcenter; 
fcenter.x = (float) radius ;
fcenter.y = (float) radius ;
cv::linearPolar(I, I, fcenter, size, INTER_LINEAR );
imshow("linearPolar",I);
waitKey(0);

Edit: Another try as a reaction on answer is to try small image.

int radius = 25;
int side = 2*radius;
int size = 1 + 2*side;
Mat I = Mat::zeros(size, size, CV_8UC1);

Point center; 
center.x = 2*radius+1 -1; center.y = 2*radius+1 -1;

// This will have only small steps
int cStep = static_cast<int> ( std::ceil( (double) (255 / I.rows ) ) );
// Here I had problems, it would be better use integer divisions
float d =  cStep + (float) (255 % I.rows) /100 ;
d =  static_cast<float>( ((int)(d * 10 + .5) / 10.0) );
float m =  static_cast<float>( ((int)(d * 1 + .5) / 1.0) );
m = m-d; // remains after division by float value
m = 1/m;  // 1/remains
int n = static_cast<int>(m);
int c = -cStep;
float res;

I = Mat::zeros(size, size, CV_8UC1);

int f;
for (int r = 0; r < I.rows; r++)
    {
        c += cStep;
        I.row(r).setTo(c); 
        res = d*(r+1);
        if ( r % n == 0 )
            c++; // it will finish at 250 not 255, the last loop is not applied
    }
imshow("Polar Gradient", I);
waitKey(0);
cv::linearPolar(I, I, 
    cv::Point(I.cols/2, I.rows/2), 
    side+1, 
    INTER_CUBIC | WARP_FILL_OUTLIERS | WARP_INVERSE_MAP);
imshow("Polar Gradient", I);
waitKey(0);