Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/156.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ [OpenCv][C+;+;]创建类似于Photoshop的平滑、喷枪式笔刷笔划?_C++_Opencv_Graphics_Drawing_Photoshop - Fatal编程技术网

C++ [OpenCv][C+;+;]创建类似于Photoshop的平滑、喷枪式笔刷笔划?

C++ [OpenCv][C+;+;]创建类似于Photoshop的平滑、喷枪式笔刷笔划?,c++,opencv,graphics,drawing,photoshop,C++,Opencv,Graphics,Drawing,Photoshop,我有一个直径为200px,硬度为0的圆形笔刷(笔刷是一个圆形渐变)。每个电刷之间的间距为电刷直径的25%。然而,当我比较我的程序绘制的笔划和Photoshop绘制的笔划时,所有设置都相等。。。 很明显,photoshop的更流畅!我不能减少间距,因为这会导致边缘变得更硬 如何使我的笔划像photoshop一样? 这是我的程序中的相关代码 //defining a circle Mat alphaBrush(2*outerRadius,2*outerRadius,CV_32FC1); float

我有一个直径为200px,硬度为0的圆形笔刷(笔刷是一个圆形渐变)。每个电刷之间的间距为电刷直径的25%。然而,当我比较我的程序绘制的笔划和Photoshop绘制的笔划时,所有设置都相等。。。 很明显,photoshop的更流畅!我不能减少间距,因为这会导致边缘变得更硬

如何使我的笔划像photoshop一样? 这是我的程序中的相关代码

//defining a circle
Mat alphaBrush(2*outerRadius,2*outerRadius,CV_32FC1);
float floatInnerRadius = outerRadius * hardness;
for(int i = 0; i < alphaBrush.rows; i++ ){
    for(int j=0; j<alphaBrush.cols; j++ ){
        int x = outerRadius - i;
        int y = outerRadius - j;
        float radius=hypot((float) x, (float) y );
        auto& pixel = alphaBrush.at<float>(i,j);
        if(radius>outerRadius){ pixel=0.0; continue;}      // transparent
        if(radius<floatInnerRadius){ pixel=1.0; continue;}      // solid
        pixel=1-((radius-floatInnerRadius)/(outerRadius-floatInnerRadius));  // partial
    }
}

/*
(...irrelevant stuff)
*/

//drawing the brush onto the canvas
for (int j = 0; j < inMatROI.rows; j++) {
            Vec3b *thisBgRow = inMatROI.ptr<Vec3b>(j);
            float *thisAlphaRow = brushROI.ptr<float>(j);
            for (int i = 0; i < inMatROI.cols; i++) {
                for (int c = 0; c < 3; c++) {
                    thisBgRow[i][c] = saturate_cast<uchar>((brightness * thisAlphaRow[i]) + ((1.0 - thisAlphaRow[i]) * thisBgRow[i][c]));
                }
            }
        }
//定义圆
Mat alphaBrush(2*outerRadius,2*outerRadius,CV_32FC1);
浮动内半径=外半径*硬度;
对于(int i=0;i如果(半径这是一种方法,画一条实线,然后计算每个像素到该线的距离。
正如您所看到的,存在一些瑕疵,可能主要是因为cv::distanceTransform中只有近似的距离值。如果您精确计算距离(可能是双精度),您应该会得到非常平滑的结果

intmain()
{
cv::Mat canvas=cv::Mat(768768,cv_8UC3,cv::Scalar::all(255));
cv::Mat canvasMask=cv::Mat::Zero(canvas.size(),cv_8UC1);
//确保笔划的大小始终大于等于2,否则cv::line方式将不起作用。。。
std::矢量冲程采样;
冲程采样。推回(cv::点(250100));
冲程采样。推回(cv::点(250200));
冲程采样。推回(cv::点(600300));
冲程采样。推回(cv::点(600400));
冲程采样。推回(cv::点(250500));
冲程采样。推回(cv::点(250650));
对于(int i=0;i外表面){百分比=0.0;}//透明
其他的
if(半径0)
{
//在这里,如果您愿意,您可以使用画布蒙版,而不是直接在画布上绘制
cv::Vec3b canvasColor=canvas.at(y,x);
cv::Vec3b cColor=cv::Vec3b(strokeColor[0],strokeColor[1],strokeColor[2]);
画布(y,x)=百分比*cColor+(1-百分比)*画布颜色;
}
}
cv::imshow(“out”,画布);
cv::imwrite(“C:/StackOverflow/Output/stroke.png”,canvas);
cv::waitKey(0);
}

你能提供一个最小的完整工作代码吗?我的算法非常标准-我有一系列的点,我在每个点之间画一条线,并且每隔x步沿连接线画一个画笔,其中x是直径乘以间距(200*.25=50px)。您在上面看到的两位代码是我生成画笔和绘制画笔的地方。imo笔划的循环采样不能很好地做到这一点。计算笔划,然后使用到笔划的实际距离计算梯度(例如距离变换或最近邻搜索).因此,在绘制点集之间的线之后,详细计算到线像素的距离(不是子采样),并根据该距离设置渐变颜色。你知道如何消除“褶皱”吗在内角?我认为这些应该是距离变换产生的伪影,它是针对速度而不是精度进行优化的。但没有测试它。我希望实现这一点,但不幸的是,这只有在我们提前完成整条线的情况下才行得通。你需要某种“临时层”或者至少是工作中的当前行作为某种工作集。
int main()
{
    cv::Mat canvas = cv::Mat(768, 768, CV_8UC3, cv::Scalar::all(255));

    cv::Mat canvasMask = cv::Mat::zeros(canvas.size(), CV_8UC1);

    // make sure the stroke has always a size of >= 2, otherwise will be cv::line way not work...
    std::vector<cv::Point> strokeSampling;
    strokeSampling.push_back(cv::Point(250, 100));

    strokeSampling.push_back(cv::Point(250, 200));
    strokeSampling.push_back(cv::Point(600, 300));
    strokeSampling.push_back(cv::Point(600, 400));
    strokeSampling.push_back(cv::Point(250, 500));

    strokeSampling.push_back(cv::Point(250, 650));

    for (int i = 0; i < strokeSampling.size() - 1; ++i)
        cv::line(canvasMask, strokeSampling[i], strokeSampling[i + 1], cv::Scalar::all(255));

    // computing a distance map:
    cv::Mat tmp1 = 255 - canvasMask;
    cv::Mat distMap;
    cv::distanceTransform(tmp1, distMap, CV_DIST_L2, CV_DIST_MASK_PRECISE);

    float outerRadius = 50;
    float innerRadius = 10;
    cv::Scalar strokeColor = cv::Scalar::all(0);

    for (int y = 0; y < distMap.rows; ++y)
        for (int x = 0; x < distMap.cols; ++x)
        {
            float percentage = 0.0f;
            float radius = distMap.at<float>(y, x);

            if (radius>outerRadius){ percentage = 0.0; }      // transparent
            else
            if (radius<innerRadius){ percentage = 1.0; }      // solid
            else
            {
                percentage = 1 - ((radius - innerRadius) / (outerRadius - innerRadius));  // partial
            }

            if (percentage > 0)
            {
                // here you could use the canvasMask if you like to, instead of directly drawing on the canvas
                cv::Vec3b canvasColor = canvas.at<cv::Vec3b>(y, x);
                cv::Vec3b cColor = cv::Vec3b(strokeColor[0], strokeColor[1], strokeColor[2]);
                canvas.at<cv::Vec3b>(y, x) = percentage*cColor + (1 - percentage) * canvasColor;
            }
        }

    cv::imshow("out", canvas);
    cv::imwrite("C:/StackOverflow/Output/stroke.png", canvas);
    cv::waitKey(0);

}