Оглавление
1. OpenCV шаг за шагом. Введение.
2. Установка.
3. Hello World.
4. Загрузка картинки.
…
27. Детектор границ Кенни (Canny)
28. Преобразование Хафа
29. Интегральное изображение
30. Трансформация изображения — аффинные преобразования, гомография
Преобразование плоскости(изображения) называется аффинным, если оно взаимно однозначно и образом любой прямой является прямая.
Взаимно однозначное преобразование, переводит каждую точку плоскости(изображения) I в другую точку плоскости(изображения) I’, таким образом, что каждой точке I соответствует какая-то точка I’.
Примеры аффинных преобразований:
* обычное движение — фактически движение является параллельным переносом
* повороты
* растяжения или сжатия относительно прямой
Для осуществления аффинных преобразований, обычно используется матрица перехода.
В OpenCV аффинные преобразования осуществляются функцией cvWarpAffine():
CVAPI(void) cvWarpAffine( const CvArr* src, CvArr* dst, const CvMat* map_matrix, int flags CV_DEFAULT(CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS), CvScalar fillval CV_DEFAULT(cvScalarAll(0)) );
— применение аффинной трансформации
src — исходное изображение
dst — целевое изображение
map_matrix — матрица трансформации 2х3
flags — комбинация флагов метода интерполяции и флагов:
#define CV_WARP_FILL_OUTLIERS 8 #define CV_WARP_INVERSE_MAP 16
CV_WARP_FILL_OUTLIERS — заполнить все пиксели целевого изображения (если пиксели отсутствуют на исходном изображени используются fillval)
CV_WARP_INVERSE_MAP — используется обратная трансформация из dst в src
fillval — значение для заполнения пикселей вне исходного изображения
dst(x', y') = src(x; y)
Важным параметром функции cvWarpAffine() является map_matrix — матрица трансформации.
Сгенерировать эту матрицу можно с помощью двух методов — cvGetAffineTransform() или cv2DRotationMatrix():
CVAPI(CvMat*) cvGetAffineTransform( const CvPoint2D32f * src, const CvPoint2D32f * dst, CvMat * map_matrix );
— рассчёт матрицы аффинной трансформации из трёх пар точек
src — 3 координаты исходного изображения
dst — 3 соотносящихся координаты целевого изображения
map_matrix — получаемая матрица трансформации 2х3
CVAPI(CvMat*) cv2DRotationMatrix( CvPoint2D32f center, double angle, double scale, CvMat* map_matrix );
— рассчитывает аффинную матрицу 2D-вращения
center — центр вращения на исходном изображении
angle — угол поворота в гардусах (положительная величина означает вращение против часовой стрелки)
scale — масштаб
map_matrix — указатель на получаемую матрицу 2х3
a b (1 - a)*center.x - b*center.y b-1 a center.x - (1 - a)*center.y
, где
a = scale - cos(angle) b = scale - sin(angle)
Пример программы, которая выполняет 2 аффинных преобразования — сначала по матрице, полученной из 3 пар точек, а затем по сгенерированной матрице вращения (поворот вокруг центра изображения на 60 градусов по часовой стрелке с масштабом 0.7).
// // модифицированный пример Example 6-2. Аффинные трансформации // // из книги: // Learning OpenCV: Computer Vision with the OpenCV Library // by Gary Bradski and Adrian Kaehler // Published by O'Reilly Media, October 3, 2008 // // https://robocraft.ru // #include <cv.h> #include <highgui.h> #include <stdlib.h> #include <stdio.h> int main(int argc, char* argv[]) { IplImage *src=0, *dst=0; // имя картинки задаётся первым параметром char* filename = argc == 2 ? argv[1] : "Image0.jpg"; // получаем картинку src = cvLoadImage(filename,1); printf("[i] image: %s\n", filename); assert( src != 0 ); // покажем изображение cvNamedWindow( "image", 1 ); cvShowImage( "image", src ); CvPoint2D32f srcTri[3], dstTri[3]; // матрицы трансформации CvMat* rot_mat = cvCreateMat(2, 3, CV_32FC1); CvMat* warp_mat = cvCreateMat(2, 3, CV_32FC1); // клонируем изображение dst = cvCloneImage(src); #if 1 // // трансформация по точкам // // по заданным точкам // вычислим матрицу преобразования srcTri[0].x = 0; //src Top left srcTri[0].y = 0; srcTri[1].x = src->width - 1; //src Top right srcTri[1].y = 0; srcTri[2].x = 0; //src Bottom left srcTri[2].y = src->height - 1; //- - - - - - - - - - - - - - -// dstTri[0].x = src->width*0.0; //dst Top left dstTri[0].y = src->height*0.33; dstTri[1].x = src->width*0.85; //dst Top right dstTri[1].y = src->height*0.25; dstTri[2].x = src->width*0.15; //dst Bottom left dstTri[2].y = src->height*0.7; // получаем матрицу cvGetAffineTransform(srcTri,dstTri,warp_mat); // выполняем трансформацию cvWarpAffine(src,dst,warp_mat); #endif // сохраним результат трансформации cvCopy(dst, src); #if 1 // // поворот изображения // // рассчёт матрицы вращения CvPoint2D32f center = cvPoint2D32f(src->width/2, src->height/2); double angle = -60.0; // на 60 градусов по часовой стрелке double scale = 0.7; // масштаб cv2DRotationMatrix(center,angle,scale,rot_mat); // выполняем вращение cvWarpAffine(src, dst, rot_mat); #endif // показываем cvNamedWindow( "cvWarpAffine"); cvShowImage( "cvWarpAffine", dst ); // ждём нажатия клавиши cvWaitKey(0); // освобождаем ресурсы cvReleaseMat(&rot_mat); cvReleaseMat(&warp_mat); cvReleaseImage(&src); cvReleaseImage(&dst); // удаляем окна cvDestroyAllWindows(); return 0; }
скачать иcходник (30-cvWarpAffine.cpp)
Именно афинное преобразование я использовал для поворота картинки, получаемой с управляемой камеры, конструкция которой вынудила закрепить её боком:
для этого я просто написал функцию-обёртку:
// функция поворота изображения на заданный угол void rotate(IplImage* _image, double _angle=90) { // матрицы трансформации CvMat* rot_mat = cvCreateMat(2, 3, CV_32FC1); // вращение относительно центра изображения CvPoint2D32f center = cvPoint2D32f(_image->width/2, _image->height/2); double angle = _angle; double scale = 1; cv2DRotationMatrix(center,angle,scale,rot_mat); IplImage* Temp = 0; Temp = cvCreateImage(cvSize(_image->width, _image->height) , _image->depth, _image->nChannels); // выполняем вращение cvWarpAffine(_image,Temp,rot_mat); // сохраняем результат cvCopy(Temp, _image); cvReleaseImage(&Temp); cvReleaseMat(&rot_mat); }
Перспективная трансформация (гомография)
CVAPI(void) cvPerspectiveTransform( const CvArr* src, CvArr* dst, const CvMat* mat );
— выполнение перспективной трансформации каждого элемента массива
src — исходный массив (32FC3)
dst — целевой массив (32FC3)
mat — матрица трансформации 3×3 или 4×4
CVAPI(void) cvWarpPerspective( const CvArr* src, CvArr* dst, const CvMat* map_matrix, int flags CV_DEFAULT(CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS), CvScalar fillval CV_DEFAULT(cvScalarAll(0)) );
— применение перспективной трансформации изображения
src — исходное изображение
dst — целевое изображение
map_matrix — матрица трансформации 3х3
flags — комбинация флагов метода интерполяции и флагов:
#define CV_WARP_FILL_OUTLIERS 8 #define CV_WARP_INVERSE_MAP 16
CV_WARP_FILL_OUTLIERS — заполнить все пиксели целевого изображения (если пиксели отсутствуют на исходном изображени используются fillval)
CV_WARP_INVERSE_MAP — используется обратная трансформация из dst в src
fillval — значение для заполнения пикселей вне исходного изображения
CVAPI(CvMat*) cvGetPerspectiveTransform( const CvPoint2D32f* src, const CvPoint2D32f* dst, CvMat* map_matrix );
— рассчёт матрицы перспективной трансформации из 4 пар точек
src — 4 координаты исходного изображения
dst — 4 соотносящихся координаты целевого изображения
map_matrix — получаемая матрица трансформации 3х3
// // модифицированный пример Example 6-3. Перспективная трансформация // // из книги: // Learning OpenCV: Computer Vision with the OpenCV Library // by Gary Bradski and Adrian Kaehler // Published by O'Reilly Media, October 3, 2008 // // https://robocraft.ru // #include <cv.h> #include <highgui.h> #include <stdlib.h> #include <stdio.h> int main(int argc, char* argv[]) { IplImage *src=0, *dst=0; // имя картинки задаётся первым параметром char* filename = argc == 2 ? argv[1] : "Image0.jpg"; // получаем картинку src = cvLoadImage(filename,1); printf("[i] image: %s\n", filename); assert( src != 0 ); // покажем изображение cvNamedWindow( "image", 1 ); cvShowImage( "image", src ); // точки CvPoint2D32f srcQuad[4], dstQuad[4]; // матрица преобразования CvMat* warp_matrix = cvCreateMat(3,3,CV_32FC1); // клонируем картинку dst = cvCloneImage(src); // задаём точки srcQuad[0].x = 0; //src Top left srcQuad[0].y = 0; srcQuad[1].x = src->width - 1; //src Top right srcQuad[1].y = 0; srcQuad[2].x = 0; //src Bottom left srcQuad[2].y = src->height - 1; srcQuad[3].x = src->width - 1; //src Bot right srcQuad[3].y = src->height - 1; //- - - - - - - - - - - - - -// dstQuad[0].x = src->width*0.05; //dst Top left dstQuad[0].y = src->height*0.33; dstQuad[1].x = src->width*0.9; //dst Top right dstQuad[1].y = src->height*0.25; dstQuad[2].x = src->width*0.2; //dst Bottom left dstQuad[2].y = src->height*0.7; dstQuad[3].x = src->width*0.8; //dst Bot right dstQuad[3].y = src->height*0.9; // получаем матрицу преобразования cvGetPerspectiveTransform(srcQuad,dstQuad,warp_matrix); // преобразование перспективы cvWarpPerspective(src,dst,warp_matrix); // показываем cvNamedWindow( "cvWarpPerspective", 1 ); cvShowImage( "cvWarpPerspective", dst ); // ждём нажатия клавиши cvWaitKey(0); // освобождаем ресурсы cvReleaseMat(&warp_matrix); cvReleaseImage(&src); cvReleaseImage(&dst); // удаляем окна cvDestroyAllWindows(); return 0; }
скачать иcходник (30-cvWarpPerspective.cpp)
Ещё методы OpenCV для трансформации изображения:
CVAPI(void) cvRemap( const CvArr* src, CvArr* dst, const CvArr* mapx, const CvArr* mapy, int flags CV_DEFAULT(CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS), CvScalar fillval CV_DEFAULT(cvScalarAll(0)) );
— применяет базовую геометрическую трансформацию, используя специальную координатную карту
формула:
dst(x, y) = src(mapx(x, y), mapy(x, y))
src — исходное изображение
dst — целевое изображение
mapx — карта координат по x (изображение типа 32FC1)
mapy — карта координат по y (изображение типа 32FC1)
flags — флаг — комбинация флагов метода интерполяции и следующего флага:
#define CV_WARP_FILL_OUTLIERS 8
CV_WARP_FILL_OUTLIERS — заполнить все пиксели целевого изображения (если пиксели отсутствуют на исходном изображени используются fillval)
fillval — значение для заполнения пикселей вне исходного изображения
— используется для устранения дисторсии
CVAPI(void) cvTransform( const CvArr* src, CvArr* dst, const CvMat* transmat, const CvMat* shiftvec CV_DEFAULT(NULL)); #define cvMatMulAddS cvTransform
— матричная трансформация каждого элемента массива
src — исходный массив
dst — целевой массив
transmat — матрица трансформации (типа float)
shiftvec — вектор сдвига (типа float)
формула:
dst(I) = transmat*src(I) + shiftvec
Каждый элемент N-мерного массива src представляется N-элементным вектором, который трансформируется MxN матрицой transmat и вектором сдвига shiftvec.
CVAPI(void) cvGetQuadrangleSubPix( const CvArr* src, CvArr* dst, const CvMat* map_matrix );
— получение изображения с субпиксельной точностью
src — исходное изображение
dst — получаемый quadrangle
map_matrix — матрица трансформации 2х3
dst(x, y) = src(A11x' + A12y' + b1, A21x' + A22y' + b2)
, где
x' = x - (width(dst) - 1)/2 y' = y - (height(dst) - 1)/2 map_matrix = A11 A12 b1 A21 A22 b2
Далее: 31. Типы данных OpenCV — хранилище памяти, последовательность
Ссылки
http://ru.wikibooks.org/wiki/Аффинные_преобразования
http://ru.wikipedia.org/wiki/Аффинное_преобразование
http://ru.wikipedia.org/wiki/Матрица_перехода
0 комментариев на «“30. OpenCV шаг за шагом. Трансформация изображения — аффинные преобразования, гомография”»
объясните пли разницу между аффинными и перспективными преобразованиями
А почему вы видео уроки не делаете?
как избежать обрезки углов при повороте?
увеличить размер картинки для хранения результата 🙂
Пробывал, но изображение все равно обрезается с лева + не нашел адекватного способа определения размеров результата операции.
Есть какие-то предложение как это преодолеть?
поворачивайте по центру, а не от координат 0,0
ВОПРОС!
А как получить изображение из кадра с FISH EYE в панорамную картинку?
Спасбо
Подсажите плис:
Когда мы сделали преобразование — каким способом возможно «перспективное» перемещение, т.е. наблюдатель находится в состоянии покоя, а картинка перемещается (например как в навигационных картах при движении)?
а как Вы это на мк запихнули?