|
При прохождении теста 1 в нем оказались вопросы, который во-первых в 1 лекции не рассматривались, во-вторых, оказалось, что вопрос был рассмаотрен в самостоятельно работе №2. Это значит, что их нужно выполнить перед прохождением теста? или это ошибка? |
Сборка и установка Intel® Integrated Performance Primitives. Использование библиотеки в среде Microsoft® Visual Studio
5.6. Реализация поиска прямых с использованием функций библиотеки Intel® Integrated Performance Primitives
Последовательно рассмотрим шаги реализации функции hough_ipp. Параметры функции в точности соответствуют тем, что были приведены при описании реализации hough _opencv.
Аналогично в начале функции объявим ряд рабочих переменных.
int hough_ipp(const Mat &srcImg,
vector<Point> &points1, vector<Point> &points2)
{
Ipp32f low = 50.0f, high = 100.0f;
int minNumPoints = 35, maxLineCount = 40, lineCount,
bufSize;
Ipp8u* pGraySrc, *pBinSrc, *buffer;
IppiSize pGraySize;
IppStatus error;
Поскольку детектор ребер Канни работает с полутоновым изображением, то далее исходное изображение конвертируется в оттенки серого посредством вызова функции ippiRGBToGray_8u_C3C1R. Рассмотрим подробнее входные параметры данной функции:
- srcImg.data – указатель на область памяти, содержащую исходное цветное изображение в формате RGB, которое предварительно было выровнено.
- srcImg.step1() – шаг, с которым необходимо выполнять проход от начала массива цветов исходного изображения, чтобы обратиться к элементу следующей строки.
- grayImg.data – указатель на область памяти для сохранения результата конвертирования.
- grayImg.step1() – шаг, с которым необходимо выполнять проход от начала массива интенсивностей пикселей выходного изображения, чтобы обратиться к элементу следующей строки.
- pGraySize – реальные размеры результирующего полутонового изображения.
// создать полутоновое изображение
Mat grayImg(srcImg.size(), CV_8UC1);
// заполнить размер IppiSize для изображения
// в оттенках серого
pGraySize.width = srcImg.size().width;
pGraySize.height = srcImg.size().height;
// преобразовать исходное изображение в оттенки серого
error = ippiRGBToGray_8u_C3C1R(srcImg.data,
srcImg.step1(), grayImg.data,
grayImg.step1(), pGraySize);
// проверить результат выполнения
// операции преобразования
if (error != ippStsNoErr)
{
printf("ERROR!!! ippiRGBToGray_8u_C3C1R(...)\n\n");
return 1;
}
На данном этапе необходимо применить детектор ребер Канни, предварительно вычислив значения вертикального и горизонтального оператора Собеля. Рассмотрим последовательность вызовов функций. Первоначально следует создать матрицу для хранения бинарного изображения, описывающего ребра.
// преобразовать указатель
pGraySrc = (Ipp8u *)grayImg.data;
// создать бинарное изображение
Mat binImg(srcImg.size(), CV_8UC1);
Затем следует определить размеры вспомогательных буферов, которые будут использоваться при вычислении значений горизонтального и вертикального оператора Собеля. Для этого необходимо вызвать функции ippiFilterSobel<type>GetBufferSize_8u16s_C1R (<type> принимает значения Vert или Horiz). Обе функции принимают на вход три параметра: размер матрицы значений оператора Собеля (vertSobelSize, horzSobelSize), размер маски оператора Собеля (ippMskSize3x3), выходной размер вспомогательного буфера (vertSize, horzSize).
// вычислить значения горизонтального и вертикального
// оператора Собеля
int vertSize, horzSize, vertSobelStep, horzSobelStep;
IppiSize vertSobelSize, horzSobelSize;
vertSobelSize.width = srcImg.size().width;
vertSobelSize.height = srcImg.size().height;
horzSobelSize.width = srcImg.size().width;
horzSobelSize.height = srcImg.size().height;
Ipp16s *horzSobel, *vertSobel;
ippiFilterSobelVertGetBufferSize_8u16s_C1R(
vertSobelSize, ippMskSize3x3, &vertSize);
ippiFilterSobelHorizGetBufferSize_8u16s_C1R(
horzSobelSize, ippMskSize3x3, &horzSize);
if (vertSize < horzSize)
{
vertSize = horzSize;
}
Аналогично необходимо вычислить размер вспомогательного буфера для детектора Канни посредством вызова функции ippiCannyGetSize, которой на вход передается реальный размер изображения и переменная для записи результирующего размера.
ippiCannyGetSize(pGraySize, &vertSize);
На данном этапе требуется выделить память для значений вертикального и горизонтального оператора Собеля с использованием функции ippiMalloc_16s_C1. Функция принимает в качестве входных параметров ширину и высоту изображения, возвращает указатель на выделенную область памяти и шаг прохода от одной строки к другой.
horzSobel = ippiMalloc_16s_C1(srcImg.size().width,
srcImg.size().height, &horzSobelStep);
vertSobel = ippiMalloc_16s_C1(srcImg.size().width,
srcImg.size().height, &vertSobelStep);
Теперь необходимо выделить память для вспомогательного буфера, который будет использоваться для детектора Канни, посредством вызова функции ippsMalloc_8u.
buffer = ippsMalloc_8u(vertSize);
К настоящему моменту выполнены все подготовительные операции, осталось вычислить значения горизонтального и вертикального оператора Собеля. Соответствующие функции выделены полужирным начертанием. Набор параметров этих функций аналогичен:
- pGraySrc – исходное полутоновое изображение.
- grayImg.step1() – шаг по строке исходного изображения.
- vertSobel / horzSobel – указатель на область памяти, в которую будет записан результат применения оператора Собеля.
- vertSobelStep / horzSobelStep – шаг по строке значений оператора Собеля.
- vertSobelSize / horzSobelSize – размер результирующей матрицы.
- ippMskSize3x3 – размер шаблона оператора Собеля.
- Способ формирования границы для вычисления граничных значений оператора.
- ippBorderConst – граница постоянного размера.
- ippBorderRepl – граница, полученная в результате копирования краевых пикселей.
- ippBorderWrap – граница получена в результате сворачивания изображения в тор.
- ippBorderMirror – зеркальное отображение краевых пикселей.
- ippBorderMirrorR – зеркальные отображение краевых пикселей с копированием.
- 0 – значение интенсивности на границе в случае, если предыдущий параметр равен ippBorderConst.
- buffer – указатель на вспомогательный буфер.
error = ippiFilterSobelVertBorder_8u16s_C1R(pGraySrc,
grayImg.step1(),
vertSobel, vertSobelStep,
vertSobelSize, ippMskSize3x3,
ippBorderRepl, 0, buffer);
if (error != ippStsNoErr)
{
printf("ERROR!!!\n\n");
return 1;
}
error = ippiFilterSobelHorizBorder_8u16s_C1R(pGraySrc,
grayImg.step1(),
horzSobel, horzSobelStep,
horzSobelSize, ippMskSize3x3,
ippBorderRepl, 0, buffer);
if (error != ippStsNoErr)
{
printf("ERROR!!! \n\n");
return 1;
}
Далее необходимо выполнить поиск ребер с помощью детектора Канни, реализованного в библиотеке Intel® IPP. Для этого необходимо вызвать функцию ippiCanny_16s8u_C1R. Функция имеет следующие входные параметры:
- Матрицы значений вертикального (vertSobel) и горизонтального оператора Собеля (horzSobel).
- Шаги по строкам для соответствующих матриц (horzSobelStep, vertSobelStep).
- Указатель на область памяти binImg.data, в которую необходимо записать результирующую матрицу ребер.
- Шаг по строке в результирующей матрице binImg.step1().
- pGraySize – размер матрицы ребер.
- Два пороговых значения (low, high) – параметры детектора Канни.
- Указатель на вспомогательный буфер buffer.
// определить ребра с помощью детектора Канни
error = ippiCanny_16s8u_C1R(horzSobel, horzSobelStep,
vertSobel, vertSobelStep, binImg.data,
binImg.step1(), pGraySize, low, high,
buffer);
if (error != ippStsNoErr)
{
printf("ERROR!!! ippiCanny_16s8u_C1R\n\n");
return 1;
}
// освободить память из-под вспомогательных буферов
ippsFree(buffer);
ippiFree(horzSobel);
ippiFree(vertSobel);
namedWindow("Canny (IPP)");
imshow("Canny (IPP)", binImg);
Осталось применить преобразование Хафа, предварительно подготовив необходимый набор параметров. Первоначально требуется определить размер рабочего буфера памяти посредством вызова функции ippiHoughLineGetSize_8u_C1R. Данная функция вычисляет размер буфера bufSize на основании размера исходного изображения pGraySize, значения параметра дискретизации delta полярной системы и заданного максимального количества прямых линий, которые будут детектироваться. Далее следует выделить вспомогательный буфер pBuffer и создать массив lines для хранения продетектированных прямых линий. Теперь можно выполнить преобразование Хафа посредством вызова функции ippiHoughLine_8u32f_C1R.Функция принимает на вход следующий набор параметров:
- pBinSrc – указатель на область памяти, где хранится бинарное изображение ребер.
- binImg.step1() – шаг по строке в бинарном изображении ребер.
- pGraySize – реальный размер результирующей матрицы.
- delta – параметры дискретизации сетки.
- minNumPoints – минимальное количество точек, лежащих на прямой линии.
- lines – указатель на массив линий.
- maxLineCount – максимальное количество линий, которые будет найдено в результате применения преобразования Хафа.
- lineCount – реальное количество продетектированных линий.
- pBuffer – указатель на рабочий буфер памяти.
// преобразовать указатель
pBinSrc = (Ipp8u *)binImg.data;
// установить параметры для преобразования Хафа
IppPointPolar delta;
delta.rho = 1;
delta.theta = 1.0f * ((float)CV_PI) / 180.0f;
IppPointPolar *lines;
Ipp8u *pBuffer;
// вычислить размер вспомогательного буфера
error = ippiHoughLineGetSize_8u_C1R(pGraySize, delta,
maxLineCount, &bufSize);
if (error != ippStsNoErr)
{
printf("ERROR!!!\n\n");
return 1;
}
// выделить память под вспомогательный буфер
// и массив линий
pBuffer = ippsMalloc_8u(bufSize);
lines = (IppPointPolar *)malloc(sizeof(IppPointPolar) *
maxLineCount);
// выполнить преобразование Хафа
error = ippiHoughLine_8u32f_C1R(pBinSrc,
binImg.step1(), pGraySize, delta,
minNumPoints, lines, maxLineCount,
&lineCount, pBuffer);
// проверить результат выполнения операции
// преобразования
if (error != ippStsNoErr)
{
printf("ERROR!!!\n\n");
return 1;
}
ippsFree(pBuffer);
Последний шаг, который необходимо выполнить, – преобразовать координаты линий из полярной системы координат в декартову систему, связанную с изображением, и освободить вспомогательную память.
for (int lineIdx = 0; lineIdx < lineCount; lineIdx++)
{
float rho = lines[lineIdx].rho,
theta = lines[lineIdx].theta;
Point pt1, pt2;
double cosTheta = cos(theta),
sinTheta = sin(theta);
double x0 = rho * cosTheta, y0 = rho * sinTheta;
pt1.x = cvRound(x0 + 1000*(-sinTheta));
pt1.y = cvRound(y0 + 1000*(cosTheta));
pt2.x = cvRound(x0 - 1000*(-sinTheta));
pt2.y = cvRound(y0 - 1000*(cosTheta));
points1.push_back(pt1);
points2.push_back(pt2);
}
binImg.release();
free(lines);
return 0;
}
