C++ 用渐变填充圆

C++ 用渐变填充圆,c++,opencv,C++,Opencv,我想用渐变色填充圆形,就像我在底部显示的一样。我想不出简单的方法,怎么做。 我可以做更多的圆,但过渡是可见的 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, cir

我想用渐变色填充圆形,就像我在底部显示的一样。我想不出简单的方法,怎么做。 我可以做更多的圆,但过渡是可见的

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);

您只需创建一个函数,该函数接收一个中心点和一个新点,计算距离,并返回该点的灰度值。或者,您可以返回距离,在该点存储距离,然后稍后使用
cv::normalize()
缩放整个对象

假设在
(100100)
图像中,中心点为
(50,50)
。以下是您想要执行的操作的伪代码:

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

<>这里是实际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();

}

你必须画许多圆圈。每个圆的颜色取决于距中心的距离。下面是一些简单的例子:

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);
   }  
}
void printGradient(cv::Mat&_input,常数cv::Point&_center,常数双半径)
{
cv::圆(_输入,_中心,半径,cv::标量(0,0,0),-1);

对于(double i=1;i另一种尚未提及的方法是预计算圆梯度图像(使用上述方法之一,如接受的解决方案),并使用仿射扭曲和线性插值创建其他此类圆(不同大小)。如果翘曲和插值得到优化,并且可能通过硬件加速,则速度会更快。 结果可能比完美还要糟糕


我曾经用它为内窥镜成像的每一帧创建一个单独的渐晕遮罩圈。比“手动”计算距离要快.

大概您可以将亮度/灰度值设置为与中心距离的函数?@EdChum是的。取决于与中心的距离。是的,@EdChum说只需创建一个函数,计算与中心的距离,然后根据该距离为其赋值。但是我需要创建更多的圆?不,您不需要。我你认为画许多圆圈的解决方案会更容易理解吗implement@KamilSzelag我不确定我是否同意,但你的方法也很好。不同的是,你的方法将离散每个像素最接近的半径的灰度值,我的方法将为每个单独的距离指定唯一的值。换句话说,你的gradient图像将有
半径
不同的灰度VAL,我的将有不同距离的灰度VAL。可能会对大半径产生影响。我想知道哪个更快?每个像素的唯一值等于更好的质量,是的。我想知道光栅图像上是否有明显的变化。我认为,您的方法更快@ NejcGalof当然,我添加了C++代码。为了将来的引用,如果你尝试实现一个解决方案,编辑你原来的问题来添加代码。这样我就可以给出一个简单的提示来解决你的问题,或者复制/粘贴你的代码,而不是从头开始写。这不是什么大不了的事,但是对于未来……@NejcGalof我添加了另一个完全不同的方法来实现这一点,它使用OpenCV的
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();

}
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);
   }  
}