使用抗锯齿时,箭头尖端的像素丢失

时间:2017-02-27 11:44:31

标签: 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 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;
}

绘制了一个箭头,但在顶端缺少一些像素:

Arrow with missing tip pixels

更准确地说,两列像素未正确着色(缩放):

enter image description here

如果我禁用抗锯齿,即,如果我使用

arrowedLine(image, from, to, Vec3b(0, 0, 0), 1, LINE_8, 0, 0.1);
而不是(注意LINE_8而不是LINE_AA),像素在那里,虽然没有抗锯齿:

enter image description here

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

增加X坐标,例如至640或641)使问题更严重,即更多的箭头像素消失,而尖端仍然缺少近两个完整的像素列。

扩展和裁剪图像可以解决相邻的像素问题,但在我原来的用例中,问题出现了,我无法放大图像,即它的大小必须保持不变。

1 个答案:

答案 0 :(得分:2)

经过快速审核后,我发现OpenCV draws AA lines using a Gaussian filter合同最终图片。

正如我在评论中建议的那样,您可以为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));

另一种选择可能是在图像中绘制两倍大的箭头,并使用良好的平滑滤镜将其缩小。

显然,只有在图像上没有任何先前数据时,最后两个选项才有效。如果是这样,那么使用透明图像进行时间绘制并在最后覆盖它。