我想要用渐变色填充圆圈,就像我在底部显示的那样.我想不出简单的方法,怎么做.我可以制作更多的圆圈,但过渡是可见的.
cv::circle(img, center, circle_radius * 1.5, cv::Scalar(1.0, 1.0, 0.3), CV_FILLED);
cv::circle(img, center, circle_radius * 1.2, cv::Scalar(1.0, 1.0, 0.6), CV_FILLED);
cv::circle(img, center, circle_radius, cv::Scalar(1.0, 1.0, 1.0), CV_FILLED);
Run Code Online (Sandbox Code Playgroud)
您需要做的就是创建一个函数,该函数接收中心点和新点,计算距离,并返回该点的灰度值.或者,您可以返回距离,存储该点的距离,然后随后缩放整个事物cv::normalize().
所以,假设你有(50, 50)一个(100, 100)像图像中心点.这是你想要做的伪代码:
function euclideanDistance(center, point) # returns a float
return sqrt( (center.x - point.x)^2 + (center.y - point.y)^2 )
center = (50, 50)
rows = 100
cols = 100
gradient = new Mat(rows, cols) # should be of type float
for row < rows:
for col < cols:
point = (col, row)
gradient[row, col] = euclideanDistance(center, point)
normalize(gradient, 0, 255, NORM_MINMAX, uint8)
gradient = 255 - gradient
Run Code Online (Sandbox Code Playgroud)
请注意这里的步骤:
uint8,但你做到了)现在,对于您的确切示例图像,圆形中存在渐变,而此方法仅将整个图像创建为渐变.在您的情况下,如果您想要一个特定的半径,只需修改计算欧几里德距离的函数,如果它超出一定距离,则将其设置为0(圆心的值,最终将翻转为白色) :
function euclideanDistance(center, point, radius) # returns a float
distance = sqrt( (center.x - point.x)^2 + (center.y - point.y)^2 )
if distance > radius:
return 0
else
return distance
Run Code Online (Sandbox Code Playgroud)
以上是实际的C++代码:
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <cmath>
float euclidean_distance(cv::Point center, cv::Point point, int radius){
float distance = std::sqrt(
std::pow(center.x - point.x, 2) + std::pow(center.y - point.y, 2));
if (distance > radius) return 0;
return distance;
}
int main(){
int h = 400;
int w = 400;
int radius = 100;
cv::Mat gradient = cv::Mat::zeros(h, w, CV_32F);
cv::Point center(150, 200);
cv::Point point;
for(int row=0; row<h; ++row){
for(int col=0; col<w; ++col){
point.x = col;
point.y = row;
gradient.at<float>(row, col) = euclidean_distance(center, point, radius);
}
}
cv::normalize(gradient, gradient, 0, 255, cv::NORM_MINMAX, CV_8U);
cv::bitwise_not(gradient, gradient);
cv::imshow("gradient", gradient);
cv::waitKey();
}
Run Code Online (Sandbox Code Playgroud)
一个完全不同的方法(虽然做同样的事情)将是使用distanceTransform().此函数将从白色斑点中心到最近的黑色值的距离映射到灰度值,就像我们上面所做的那样.这段代码更简洁,做同样的事情.但是,它可以处理任意形状,而不仅仅是圆形,所以这很酷.
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
int main(){
int h = 400;
int w = 400;
int radius = 100;
cv::Point center(150, 200);
cv::Mat gradient = cv::Mat::zeros(h, w, CV_8U);
cv::rectangle(gradient, cv::Point(115, 100), cv::Point(270, 350), cv::Scalar(255), -1, 8 );
cv::Mat gradient_padding;
cv::bitwise_not(gradient, gradient_padding);
cv::distanceTransform(gradient, gradient, CV_DIST_L2, CV_DIST_MASK_PRECISE);
cv::normalize(gradient, gradient, 0, 255, cv::NORM_MINMAX, CV_8U);
cv::bitwise_or(gradient, gradient_padding, gradient);
cv::imshow("gradient-distxform.png", gradient);
cv::waitKey();
}
Run Code Online (Sandbox Code Playgroud)
你必须绘制很多圆圈.每个圆的颜色取决于距中心的距离.这是一个简单的例子:
void printGradient(cv::Mat &_input,const cv::Point &_center, const double radius)
{
cv::circle(_input, _center, radius, cv::Scalar(0, 0, 0), -1);
for(double i=1; i<radius; i=i++)
{
const int color = 255-int(i/radius * 255); //or some another color calculation
cv::circle(_input,_center,i,cv::Scalar(color, color, color),2);
}
}
Run Code Online (Sandbox Code Playgroud)
结果: