Пиксели на кончике стрелки отсутствуют при использовании сглаживания

Я пытаюсь нарисовать стрелку с 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;
}

Стрелка нарисована, но на кончике отсутствуют некоторые пиксели:

Стрелка с отсутствующими кончиками пикселей

Чтобы быть более точным, два столбца пикселей не окрашены правильно (увеличено):

введите описание изображения здесь

Если я отключу сглаживание, т.е. если я использую

arrowedLine(image, from, to, Vec3b(0, 0, 0), 1, LINE_8, 0, 0.1);

вместо этого (обратите внимание на LINE_8 вместо LINE_AA), пиксели есть, хотя и без сглаживания:

введите описание изображения здесь

Мне известно, что сглаживание может основываться на соседних пикселях, но кажется странным, что пиксели вообще не рисуются на границах, а не рисуются без сглаживания. Есть ли решение этой проблемы?

Увеличение координаты X, например, 640 или 641) усугубляет проблему, т. е. исчезает больше пикселей со стрелками, в то время как на острие по-прежнему не хватает почти двух полных столбцов пикселей.

Расширение и обрезка изображения решит проблему соседних пикселей, но в моем исходном сценарии использования, где возникла проблема, я не могу увеличить свое изображение, то есть его размер должен оставаться постоянным.

2

Решение

После быстрого обзора я обнаружил, что OpenCV рисует линии АА с использованием фильтра Гаусса, который контракты окончательное изображение.

Как я предлагал в комментариях, вы можете реализовать свою собственную функцию для режима AA (вы можете вызвать оригинальную функцию, если AA отключен), расширяя точки вручную (см. Код ниже, чтобы иметь представление).

Другим вариантом может быть увеличение ширины линии при использовании AA.

Вы также можете имитировать эффект АА OpenCV, но на конечном изображении (может быть медленнее, но полезно, если у вас много стрелок). Я не эксперт по 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));

Другой вариант — нарисовать стрелку на изображении в два раза больше и уменьшить ее с помощью хорошего сглаживающего фильтра.

Очевидно, что последние два варианта будут работать, только если у вас нет предыдущих данных на изображении. Если это так, то используйте прозрачное изображение для временного рисования и наложите его в конце.

2

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector