C++ 使用抗锯齿时箭头尖端缺少像素

C++ 使用抗锯齿时箭头尖端缺少像素,c++,opencv,line,antialiasing,C++,Opencv,Line,Antialiasing,我正在尝试使用OpenCV 3.2绘制箭头: #include <opencv2/core.hpp> #include <opencv2/imgproc.hpp> #include <opencv2/highgui.hpp> using namespace cv; int main() { Mat image(480, 640, CV_8UC3, Scalar(255, 255, 255)); //White background Point fr

我正在尝试使用OpenCV 3.2绘制箭头:

#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>

using namespace cv;

int main()
{
  Mat image(480, 640, CV_8UC3, Scalar(255, 255, 255)); //White background
  Point from(320, 240); //Middle
  Point to(639, 240); //Right border
  arrowedLine(image, from, to, Vec3b(0, 0, 0), 1, LINE_AA, 0, 0.1);
  imshow("Arrow", image);
  waitKey(0);
  return 0;
}
取而代之的是(注意线_8而不是线_AA),像素在那里,尽管没有抗锯齿:

我知道抗锯齿可能依赖于相邻像素,但奇怪的是,像素根本没有在边界处绘制,而不是在没有抗锯齿的情况下绘制。这个问题有解决办法吗

增加X坐标(例如,增加到640或641)会使问题变得更糟,即更多箭头像素消失,而尖端仍然缺少几乎两个完整的像素列


扩展和裁剪图像可以解决相邻像素的问题,但在我最初的使用案例中,当问题出现时,我无法放大图像,即图像大小必须保持不变。

快速查看后,我发现OpenCV收缩了最终图像

正如我在评论中所建议的那样,您可以为AA模式实现自己的函数(如果AA被禁用,您可以调用原来的函数),手动扩展点(请参见下面的代码以了解想法)

其他选项可能是在使用AA时增加线宽

您也可以模拟OpenCV的AA效果,但会出现在最终图像上(如果有许多箭头,则速度可能较慢,但会有所帮助)。我不是OpenCV专家,因此我将编写一个通用方案:

// Filter radius, the higher the stronger
const int kRadius = 3;

// Image is extended to fit pixels that are not going to be blurred
Mat blurred(480 + kRadius * 2, 640 + kRadius * 2, CV_8UC3, Scalar(255, 255, 255));

// Points moved a according to filter radius (need testing, but the idea is that)
Point from(320, 240 + kRadius);
Point to(639 + kRadius * 2, 240 + kRadius);

// Extended non-AA arrow
arrowedLine(blurred, ..., LINE_8, ...);

// Simulate AA
GaussianBlur(blurred, blurred, Size(kRadius, kRadius), ...);

// Crop image (be careful, it doesn't copy data)
Mat image = blurred(Rect(kRadius, kRadius, 640, 480));
另一种选择可能是在图像中绘制两倍大的箭头,并使用良好的平滑过滤器将其缩小


显然,只有在图像上没有任何以前的数据时,最后两个选项才起作用。如果是这样,则使用透明图像进行临时绘制,并将其覆盖在末尾。

可以在末尾获得“之前”和“之后”的平均值borders@huseyintugrulbuyukisik:你的意思是我画带AA和不带AA的箭头,并在两个受影响的列中取平均值吗?我的意思是只画边框,不完整image@huseyintugrulbuyukisik例如我不明白。你能举个例子吗?从0,0点到0,x点,从0点到y点,x感谢你的想法和努力,但这需要重新分配原始图像,即在内存中有效地移动它,对吗?如果你手动执行模糊传递
BORDER\u REPLICATE
到GaussianBlur应该会得到更好的结果。使用此标志,它将选择最后一列中线条的颜色。哦,我不知道该选项,太好了@那真是太好了。我想没有机会让
drawArrow
也这样做?对我来说,这似乎是一个bug,因为它目前在图片的边界上运行。
// Filter radius, the higher the stronger
const int kRadius = 3;

// Image is extended to fit pixels that are not going to be blurred
Mat blurred(480 + kRadius * 2, 640 + kRadius * 2, CV_8UC3, Scalar(255, 255, 255));

// Points moved a according to filter radius (need testing, but the idea is that)
Point from(320, 240 + kRadius);
Point to(639 + kRadius * 2, 240 + kRadius);

// Extended non-AA arrow
arrowedLine(blurred, ..., LINE_8, ...);

// Simulate AA
GaussianBlur(blurred, blurred, Size(kRadius, kRadius), ...);

// Crop image (be careful, it doesn't copy data)
Mat image = blurred(Rect(kRadius, kRadius, 640, 480));