При прохождении теста 1 в нем оказались вопросы, который во-первых в 1 лекции не рассматривались, во-вторых, оказалось, что вопрос был рассмаотрен в самостоятельно работе №2. Это значит, что их нужно выполнить перед прохождением теста? или это ошибка? |
Сравнение производительности некоторых алгоритмов в библиотеках OpenCV и IPP
2.5. Реализация операций с использованием функционала библиотеки OpenCV
Первые три задачи из выбранных нами средствами OpenCV решаются очень просто. Рассмотрим их подробнее.
2.5.1. Функция медианной фильтрации
Медианная фильтрация в библиотеке OpenCV реализуется с помощью функции medianBlur(). Ее подробное описание может быть найдено в лабораторной работе "Базовые операции обработки изображений" настоящего курса. Здесь же лишь отметим, что в экспериментах мы будем использовать размер ядра, равный 3, но предусмотрим возможность его изменения.
double median_opencv(const Mat &srcImg, Mat &dstImg, const int kSize = 3); double median_opencv(const Mat &srcImg, Mat &dstImg, const int kSize) { clock_t start, finish; start = clock(); medianBlur(srcImg, dstImg, kSize); finish = clock(); return double(finish - start) / CLOCKS_PER_SEC; }
2.5.2. Функция вычисления эрозии
Эрозия изображения выполняется в OpenCV с помощью функции erode(). Используем простейший вариант ее вызова с тремя параметрами, при котором применяется квадратный шаблон .
double erode_opencv(const Mat &srcImg, Mat &dstImg) { clock_t start, finish; start = clock(); Mat element = Mat(); erode(srcImg, dstImg, element); finish = clock(); return double(finish - start) / CLOCKS_PER_SEC; }
2.5.3. Функция вычисления дилатации
Полностью аналогично обстоит дело с функцией дилатации.
double dilate_opencv(const Mat &srcImg, Mat &dstImg) { clock_t start, finish; start = clock(); Mat element = Mat(); dilate(srcImg, dstImg, element); finish = clock(); return double(finish - start) / CLOCKS_PER_SEC; }
За описанием функций erode() и dilate() также отсылаем к лабораторной работе "Базовые операции обработки изображений".
2.5.4. Функция вычисления гистограммы
Для вычисления гистограммы используем часть кода, приведенного в соответствующем разделе лабораторной работы "Базовые операции обработки изображений". Будем строить гистограмму по каждому каналу цветного изображения, предварительно расщепляя его по каналам с помощью функции split().
double hist_opencv(const Mat &srcImg, Mat &dstImg) { Mat bgrChannels[3], bHist, gHist, rHist; // количество бинов гистограммы int kBins = 256; // интервал изменения значений бинов float range[] = {0.0f, 256.0f}; const float* histRange = { range }; // равномерное распределение интервала по бинам bool uniform = true; // запрет очищения перед вычислением гистограммы bool accumulate = false; clock_t start, finish; start = clock(); split(srcImg, bgrChannels); // вычисление гистограммы для каждого канала calcHist(&bgrChannels[0], 1, 0, Mat(), bHist, 1, &kBins, &histRange, uniform, accumulate); calcHist(&bgrChannels[1], 1, 0, Mat(), gHist, 1, &kBins, &histRange, uniform, accumulate); calcHist(&bgrChannels[2], 1, 0, Mat(), rHist, 1, &kBins, &histRange, uniform, accumulate); finish = clock(); return double(finish - start) / CLOCKS_PER_SEC; }
2.6. Реализация операций с использованием функционала библиотеки Intel IPP
2.6.1. Функция медианной фильтрации
Медианная фильтрация в IPP выполняется при помощи одной из функций вида ippiFilterMedian_<mod>. В случае цветного изображения mod – 3uC3R. Кроме того, в документации к IPP указано, что если мы хотим применить фильтр с шаблоном размера msk, необходимо расширить матрицу изображения на msk / 2 пикселов с каждой стороны. Для расширения используем функцию ippiCopyReplicateBorder_8u_C3R(). Наконец, после получения "расширенного" отфильтрованного изображения, необходимо выполнить обратную операцию – выделить изображение исходного размера. Это можно сделать, просто скопировав внутреннюю часть расширенной матрицы пикселей с помощью функции ippiCopy_8u_C3R().
Получим следующий код.
double median_ipp(const Mat &srcImg, Mat &dstImg, const int msk = 3); double median_ipp(const Mat &srcImg, Mat &dstImg, const int msk) { const int borderSize = msk / 2; IppiSize mskSize = { msk , msk }; IppiPoint anchor = { msk / 2, msk / 2 }; Mat ippSrcImg, ippDstImg; Size ippImgSize; IppiSize ippSrcSize, ippDstSize; Ipp8u *pSrcData, *pDstData; clock_t start, finish; ippImgSize.width = srcImg.size().width + 2 * borderSize; ippImgSize.height = srcImg.size().height + 2 * borderSize; ippSrcImg.create(ippImgSize, srcImg.type()); ippDstImg.create(ippImgSize, srcImg.type()); pSrcData = (Ipp8u *)ippSrcImg.data; pDstData = (Ipp8u *)ippDstImg.data; start = clock(); ippSrcSize.width = srcImg.size().width; ippSrcSize.height = srcImg.size().height; ippDstSize.width = srcImg.size().width + 2 * borderSize; ippDstSize.height = srcImg.size().height + 2 * borderSize; ippiCopyReplicateBorder_8u_C3R(srcImg.data, srcImg.step1(), ippSrcSize, pSrcData, srcImg.step1() + 3 * 2 * borderSize, ippDstSize, borderSize, borderSize); ippiFilterMedian_8u_C3R(pSrcData + ippImgSize.width * 3 * borderSize + 3 * borderSize, srcImg.step1() + 3 * 2 * borderSize, pDstData + ippImgSize.width * 3 * borderSize + 3 * borderSize, srcImg.step1() + 3 * 2 * borderSize, ippSrcSize, mskSize, anchor); finish = clock(); dstImg.create(srcImg.size(), srcImg.type()); pSrcData = pDstData; pDstData = (Ipp8u *)dstImg.data; ippiCopy_8u_C3R(pSrcData + ippImgSize.width * 3 * borderSize + 3 * borderSize, srcImg.step1() + 3 * 2 * borderSize, pDstData, dstImg.step1(), ippSrcSize); ippSrcImg.release(); ippDstImg.release(); return double(finish - start) / CLOCKS_PER_SEC; }
Отметим, что для построения "расширенной" матрицы изображения мы использовали функции OpenCV для работы c типом Mat.
ippImgSize.width = srcImg.size().width + 2 * borderSize; ippImgSize.height = srcImg.size().height + 2 * borderSize; ippSrcImg.create(ippImgSize, srcImg.type()); ippDstImg.create(ippImgSize, srcImg.type()); pSrcData = (Ipp8u *)ippSrcImg.data; pDstData = (Ipp8u *)ippDstImg.data;
Конечно, то же самое можно проделать только средствами IPP. Внести соответствующие изменения предлагаем читателю самостоятельно.
Также отметим, что, как и в OpenCV-версии, здесь мы предусмотрели возможность задания ядра произвольного размера, но в экспериментах далее будем использовать значение msk по умолчанию.