
Оглавление
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 в панорамную картинку?
Спасбо
Подсажите плис:
Когда мы сделали преобразование — каким способом возможно «перспективное» перемещение, т.е. наблюдатель находится в состоянии покоя, а картинка перемещается (например как в навигационных картах при движении)?
а как Вы это на мк запихнули?