OpenCV C ++ - Как я могу заменить значение каждого пикселя средним значением градаций серого в окрестности 3x3? - PullRequest
0 голосов
/ 07 апреля 2020

Я новичок в OpenCV (в C ++) и обработке изображений. Я хочу, чтобы изображение в градациях серого заменяло значение каждого пикселя, вычисляя среднее значение градаций серого в окрестности 3x3.

Прежде всего, я открываю изображение

Mat img = imread(samples::findFile(argv[1]), IMREAD_GRAYSCALE);

// Example of image
[4 3 9 1,
 2 9 8 0,
 3 5 2 1,
 7 5 8 3]

. чтобы получить среднее значение ближайших пикселей 3x3 углов (верхний левый, верхний правый, нижний левый и нижний правый), я делаю отступ изображения: постоянная граница 1x1x1x1

Mat imgPadding;
copyMakeBorder(img, imgPadding, 1,1,1,1, BORDER_CONSTANT, Scalar(0));

// Padding example
[0 0 0 0 0 0,
 0 4 3 9 1 0,
 0 2 9 8 0 0,
 0 3 5 2 1 0,
 0 7 5 8 3 0,
 0 0 0 0 0 0]

Теперь у меня есть есть некоторые проблемы с выходным изображением. Я пытался по-разному, но никоим образом не приводит меня к решению. Я попробовал это, используя функцию mean () , чтобы получить среднее значение в градациях серого i, j-й матрицы 3x3, полученной с помощью метода Rect () . For l oop начинается с первого пикселя без отступов и заканчивается последним пикселем без отступов.

Mat imgAvg = Mat::zeros(img.rows, img.cols, img.type());
// initialization of the output Mat object with same input size and type

for (int i = 1; i < imgAvg.rows; i++)
    for (int j = 1; j < imgAvg.cols; j++) 
        imgAvg.at<Scalar>(Point(j - 1, i - 1)) = mean(imgPadding(Rect(j - 1, i - 1, 3, 3)));

, но я получил эту ошибку времени выполнения

main: malloc.c:2379: sysmalloc: Assertion `(old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0)' failed.

Я пытался также случайно уменьшил диапазон

for (int i = 1; i < imgAvg.rows - 35; i++)
    for (int j = 1; j < imgAvg.cols - 35; j++) 
        imgAvg.at<Scalar>(Point(j - 1, i - 1)) = mean(imgPadding(Rect(j - 1, i - 1, 3, 3)));

, и я получил этот странный вывод: снимок экрана

Заранее спасибо!

РЕДАКТИРОВАТЬ: Спасибо всем за ответы, я еще не знал функцию blur(). Таким образом, я импортирую изображение и просто вызываю функцию размытия

Mat img = imread(samples::findFile(argv[1]), IMREAD_GRAYSCALE);
Mat imgAvg = Mat::zeros(img.rows, img.cols, img.type());

blur(img, imgAvg, Size(3, 3));

Но так как я все еще новичок, и я думаю, что назначенное мне упражнение было написать код "ручной работы", Я пробовал также это рабочее решение

for (int i = 1; i <= imgAvg.rows; i++)
    for (int j = 1; j <= imgAvg.cols; j++) 
        imgAvg.at<uint8_t>(Point(j - 1, i - 1)) = mean(imgPadding(Rect(j - 1, i - 1, 3, 3)))[0];

Результат алгоритма (одинаковый для обоих решений)

Ответы [ 2 ]

0 голосов
/ 08 апреля 2020

То, что вы хотите сделать, называется «коробочной фильтрацией» при обработке изображений. В OpenCV вы делаете:

cv::blur(src_img, 
         dest_img, // same shape and type as src, cannot be src
         cv::Size(3, 3))  // use a kernel of size 3x3           

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

0 голосов
/ 08 апреля 2020

Просто примените сглаживающий фильтр к изображению - функция blur в модуле imgproc должна выполнить sh то, что вам нужно. Хороший пример приведен в документации: https://docs.opencv.org/3.4/dc/dd3/tutorial_gausian_median_blur_bilateral_filter.html

В этом случае вам нужны следующие аргументы: изображение (img), изображение назначения (dst) и размер ядра (ksize), который в данном случае равен 3:

src = ...
Mat dst = Mat::zeros( src.size(), src.type() )
blur( src, dst, Size( 3, 3 ))

Сглаживание вручную не будет производительным и более подвержено ошибкам.

Удачи!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...