OpenCV 图像采样 插值 几何变换

摘要:
对多通道图像,每个通道独立单独完成提取。[编辑]GetQuadrangleSubPix提取象素四边形,使用子象素精度voidcvGetQuadrangleSubPix;src输入图像.dst提取的四边形.map_matrix3×2变换矩阵[A|b](见讨论).函数cvGetQuadrangleSubPix以子象素精度从图像src中提取四边形,使用子象素精度,并且将结果存储于dst,计算公式是:dst=src其中A和b均来自映射矩阵,映射矩阵为:其中在非整数坐标的象素点值通过双线性变换得到。=0){IplImage*dst=cvCloneImage;intdelta=1;intangle=0;cvNamedWindow;cvShowImage;for(;;){floatm[6];doublefactor=*3;CvMatM=cvMat;intw=src-˃width;inth=src-˃height;m[0]=;m[1]=;m[2]=w*0.5f;m[3]=-m[1];m[4]=m[0];m[5]=h*0.5f;cvGetQuadrangleSubPix;cvNamedWindow;cvShowImage;ifbreak;angle=%360;}}return0;}[编辑]Resize图像大小变换voidcvResize;src输入图像.dst输出图像.interpolation插值方法:CV_INTER_NN-最近邻插值,CV_INTER_LINEAR-双线性插值CV_INTER_AREA-使用象素关系重采样。

InitLineIterator

初始化线段迭代器

int cvInitLineIterator( const CvArr* image, CvPoint pt1, CvPoint pt2, CvLineIterator* line_iterator, int connectivity=8 );
image
带采线段的输入图像.
pt1
线段起始点
pt2
线段结束点
line_iterator
指向线段迭代器状态结构的指针
connectivity
被扫描线段的连通数,4 或 8.

函数 cvInitLineIterator 初始化线段迭代器,并返回两点之间的象素点数目。两个点必须在图像内。当迭代器初始化后,连接两点的光栅线上所有点,都可以连续通过调用 CV_NEXT_LINE_POINT 来得到。线段上的点是使用 4-连通或8-连通利用 Bresenham 算法逐点计算的。

例子:使用线段迭代器计算彩色线上象素值的和

CvScalar sum_line_pixels( IplImage* image, CvPoint pt1, CvPoint pt2 ) { CvLineIterator iterator; int blue_sum = 0, green_sum = 0, red_sum = 0; int count = cvInitLineIterator( image, pt1, pt2, &iterator, 8 ); for( int i = 0; i < count; i++ ){ blue_sum += iterator.ptr[0]; green_sum += iterator.ptr[1]; red_sum += iterator.ptr[2]; CV_NEXT_LINE_POINT(iterator); { int offset, x, y; offset = iterator.ptr - (uchar*)(image->imageData); y = offset/image->widthStep; x = (offset - y*image->widthStep)/(3*sizeof(uchar) ); printf("(%d,%d)\n", x, y ); } } return cvScalar( blue_sum, green_sum, red_sum ); }
[编辑]

SampleLine

将图像上某一光栅线上的像素数据读入缓冲区

int cvSampleLine( const CvArr* image, CvPoint pt1, CvPoint pt2, void* buffer, int connectivity=8 );
image
输入图像
pt1
光栅线段的起点
pt2
光栅线段的终点
buffer
存储线段点的缓存区,必须有足够大小来存储点 max( |pt2.x-pt1.x|+1, |pt2.y-pt1.y|+1 ) :8-连通情况下,或者 |pt2.x-pt1.x|+|pt2.y-pt1.y|+1 : 4-连通情况下.
connectivity
线段的连通方式, 4 or 8.

函数 cvSampleLine 实现了线段迭代器的一个特殊应用。它读取由 pt1 和 pt2 两点确定的线段上的所有图像点,包括终点,并存储到缓存中。

[编辑]

GetRectSubPix

从图像中提取象素矩形,使用子象素精度

void cvGetRectSubPix( const CvArr* src, CvArr* dst, CvPoint2D32f center );
src
输入图像.
dst
提取的矩形.
center
提取的象素矩形的中心,浮点数坐标。中心必须位于图像内部.

函数 cvGetRectSubPix 从图像 src 中提取矩形:

dst(x, y) = src(x + center.x - (width(dst)-1)*0.5, y + center.y - (height(dst)-1)*0.5)

其中非整数象素点坐标采用双线性插值提取。对多通道图像,每个通道独立单独完成提取。尽管函数要求矩形的中心一定要在输入图像之中,但是有可能出现矩形的一部分超出图像边界的情况,这时,该函数复制边界的模识(hunnish:即用于矩形相交的图像边界线段的象素来代替矩形超越部分的象素)。

[编辑]

GetQuadrangleSubPix

提取象素四边形,使用子象素精度

void cvGetQuadrangleSubPix( const CvArr* src, CvArr* dst, const CvMat* map_matrix );
src
输入图像.
dst
提取的四边形.
map_matrix
3 × 2 变换矩阵 [A|b] (见讨论).

函数 cvGetQuadrangleSubPix 以子象素精度从图像 src 中提取四边形,使用子象素精度,并且将结果存储于 dst ,计算公式是:

dst(x+width(dst) / 2,y+height(dst) / 2) =src(A11x+A12y+b1,A21x+A22y+b2)

其中 A和 b 均来自映射矩阵(译者注:A, b为几何形变参数) ,映射矩阵为:

map\_matrix = \begin{bmatrix} A_{11} & A_{12} & b_1 \\ A_{21} & A_{22} & b_2 \end{bmatrix}

其中在非整数坐标A \cdot (x,y)^T+b的象素点值通过双线性变换得到。当函数需要图像边界外的像素点时,使用重复边界模式(replication border mode)恢复出所需的值。多通道图像的每一个通道都单独计算。

例子:使用 cvGetQuadrangleSubPix 进行图像旋转

#include "cv.h" #include "highgui.h" #include "math.h" int main( int argc, char** argv ) { IplImage* src; if( argc==2 && (src = cvLoadImage(argv[1], -1))!=0) { IplImage* dst = cvCloneImage( src ); int delta = 1; int angle = 0; cvNamedWindow( "src", 1 ); cvShowImage( "src", src ); for(;;) { float m[6]; double factor = (cos(angle*CV_PI/180.) + 1.1)*3; CvMat M = cvMat( 2, 3, CV_32F, m ); int w = src->width; int h = src->height; m[0] = (float)(factor*cos(-angle*2*CV_PI/180.)); m[1] = (float)(factor*sin(-angle*2*CV_PI/180.)); m[2] = w*0.5f; m[3] = -m[1]; m[4] = m[0]; m[5] = h*0.5f; cvGetQuadrangleSubPix( src, dst, &M, 1, cvScalarAll(0)); cvNamedWindow( "dst", 1 ); cvShowImage( "dst", dst ); if( cvWaitKey(5) == 27 ) break; angle = (angle + delta) % 360; } } return 0; }
[编辑]

Resize

图像大小变换

void cvResize( const CvArr* src, CvArr* dst, int interpolation=CV_INTER_LINEAR );
src
输入图像.
dst
输出图像.
interpolation
插值方法:
  • CV_INTER_NN - 最近邻插值,
  • CV_INTER_LINEAR - 双线性插值 (缺省使用)
  • CV_INTER_AREA - 使用象素关系重采样。当图像缩小时候,该方法可以避免波纹出现。当图像放大时,类似于 CV_INTER_NN 方法..
  • CV_INTER_CUBIC - 立方插值.

函数 cvResize 将图像 src 改变尺寸得到与 dst 同样大小。若设定 ROI,函数将按常规支持 ROI.

[编辑]

WarpAffine

对图像做仿射变换

void cvWarpAffine( const CvArr* src, CvArr* dst, const CvMat* map_matrix, int flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS, CvScalar fillval=cvScalarAll(0) );
src
输入图像.
dst
输出图像.
map_matrix
2×3 变换矩阵
flags
插值方法和以下开关选项的组合:
  • CV_WARP_FILL_OUTLIERS - 填充所有输出图像的象素。如果部分象素落在输入图像的边界外,那么它们的值设定为 fillval.
  • CV_WARP_INVERSE_MAP - 指定 map_matrix 是输出图像到输入图像的反变换,因此可以直接用来做象素插值。否则, 函数从 map_matrix 得到反变换。
fillval
用来填充边界外面的值

函数 cvWarpAffine 利用下面指定的矩阵变换输入图像:dst(x',y') \leftarrow src(x,y)

  • 如果没有指定 CV_WARP_INVERSE_MAP ,(x',y')^T=map\_matrix \cdot (x,y,1)^T,
  • 否则,(x, y)^T=map\_matrix \cdot (x',y',1)^T

函数与 cvGetQuadrangleSubPix 类似,但是不完全相同。 cvWarpAffine 要求输入和输出图像具有同样的数据类型,有更大的资源开销(因此对小图像不太合适)而且输出图像的部分可以保留不变。而 cvGetQuadrangleSubPix 可以精确地从8位图像中提取四边形到浮点数缓存区中,具有比较小的系统开销,而且总是全部改变输出图像的内容。

要变换稀疏矩阵,使用 cxcore 中的函数 cvTransform 。

[编辑]

GetAffineTransform

由三对点计算仿射变换

CvMat* cvGetAffineTransform( const CvPoint2D32f* src, const CvPoint2D32f* dst, CvMat* map_matrix );
src
输入图像的三角形顶点坐标。
dst
输出图像的相应的三角形顶点坐标。
map_matrix
指向2×3输出矩阵的指针。

函数cvGetAffineTransform计算满足以下关系的仿射变换矩阵:

(x'_i,y'_i,1)^T=map\_matrix\cdot(x_i,y_i,1)^T

这里,dst(i) = (x'i,y'i),src(i) = (xi,yi),i= 0..2.
[编辑]

2DRotationMatrix

计算二维旋转的仿射变换矩阵

CvMat* cv2DRotationMatrix( CvPoint2D32f center, double angle, double scale, CvMat* map_matrix );
center
输入图像的旋转中心坐标
angle
旋转角度(度)。正值表示逆时针旋转(坐标原点假设在左上角).
scale
各项同性的尺度因子
map_matrix
输出 2×3 矩阵的指针

函数 cv2DRotationMatrix 计算矩阵:

[ α β | (1-α)*center.x - β*center.y ] [ -β α | β*center.x + (1-α)*center.y ] where α=scale*cos(angle), β=scale*sin(angle)

该变换并不改变原始旋转中心点的坐标,如果这不是操作目的,则可以通过调整平移量改变其坐标(译者注:通过简单的推导可知,仿射变换的实现是首先将旋转中心置为坐标原点,再进行旋转和尺度变换,最后重新将坐标原点设定为输入图像的左上角,这里的平移量是center.x, center.y).

[编辑]

WarpPerspective

对图像进行透视变换

void cvWarpPerspective( const CvArr* src, CvArr* dst, const CvMat* map_matrix,int flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS,CvScalar fillval=cvScalarAll(0));
src
输入图像.
dst
输出图像.
map_matrix
3×3 变换矩阵
flags
插值方法和以下开关选项的组合:
  • CV_WARP_FILL_OUTLIERS - 填充所有缩小图像的象素。如果部分象素落在输入图像的边界外,那么它们的值设定为 fillval.
  • CV_WARP_INVERSE_MAP - 指定 matrix 是输出图像到输入图像的反变换,因此可以直接用来做象素插值。否则, 函数从 map_matrix 得到反变换。
fillval
用来填充边界外面的值

函数 cvWarpPerspective 利用下面指定矩阵变换输入图像:dst(x',y') \leftarrow src(x,y)

  • 如果没有指定 CV_WARP_INVERSE_MAP ,(x',y')^T=map\_matrix \cdot (x,y,1)^T,
  • 否则,(x, y)^T=map\_matrix \cdot (x',y',1)^T

要变换稀疏矩阵,使用 cxcore 中的函数 cvTransform 。

[编辑]

WarpPerspectiveQMatrix

用4个对应点计算透视变换矩阵

CvMat* cvWarpPerspectiveQMatrix( const CvPoint2D32f* src, const CvPoint2D32f* dst, CvMat* map_matrix );
src
输入图像的四边形的4个点坐标
dst
输出图像的对应四边形的4个点坐标
map_matrix
输出的 3×3 矩阵

函数 cvWarpPerspectiveQMatrix计算透视变换矩阵,使得:

(tix'i,tiy'i,ti)T=matrix•(xi,yi,1)T

其中 dst(i)=(x'i,y'i), src(i)=(xi,yi), i=0..3.

[编辑]

GetPerspectiveTransform

由四对点计算透射变换

CvMat* cvGetPerspectiveTransform( const CvPoint2D32f* src, const CvPoint2D32f* dst, CvMat* map_matrix ); #define cvWarpPerspectiveQMatrixcvGetPerspectiveTransform
src
输入图像的四边形顶点坐标。
dst
输出图像的相应的四边形顶点坐标。
map_matrix
指向3×3输出矩阵的指针。

函数cvGetPerspectiveTransform计算满足以下关系的透射变换矩阵:

(t_ix'_i,t_iy'_i,t_i)^T=map\_matrix\cdot(x_i,y_i,1)^T

这里,dst(i) = (x'i,y'i),src(i) = (xi,yi),i= 0..3.
[编辑]

Remap

对图像进行普通几何变换

void cvRemap( const CvArr* src, CvArr* dst, const CvArr* mapx, const CvArr* mapy, int flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS, CvScalar fillval=cvScalarAll(0) );
src
输入图像.
dst
输出图像.
mapx
x坐标的映射 (32fC1 image).
mapy
y坐标的映射 (32fC1 image).
flags
插值方法和以下开关选项的组合:
  • CV_WARP_FILL_OUTLIERS - 填充边界外的像素. 如果输出图像的部分象素落在变换后的边界外,那么它们的值设定为 fillval。
fillval
用来填充边界外面的值.

函数 cvRemap 利用下面指定的矩阵变换输入图像:

dst(x,y)<-src(mapx(x,y),mapy(x,y))

与其它几何变换类似,可以使用一些插值方法(由用户指定,译者注:同cvResize)来计算非整数坐标的像素值。

[编辑]

LogPolar

把图像映射到极指数空间

void cvLogPolar( const CvArr* src, CvArr* dst, CvPoint2D32f center, double M, int flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS );
src
输入图像。
dst
输出图像。
center
变换的中心,输出图像在这里最精确。
M
幅度的尺度参数,见下面公式。
flags
插值方法和以下选择标志的结合
  • CV_WARP_FILL_OUTLIERS -填充输出图像所有像素,如果这些点有和外点对应的,则置零。
  • CV_WARP_INVERSE_MAP - 表示矩阵由输出图像到输入图像的逆变换,并且因此可以直接用于像素插值。否则,函数从map_matrix中寻找逆变换。
fillval
用于填充外点的值。

函数cvLogPolar用以下变换变换输入图像:

正变换 (CV_WARP_INVERSE_MAP 未置位):

dst(phi,rho)<-src(x,y)

逆变换 (CV_WARP_INVERSE_MAP 置位):

dst(x,y)<-src(phi,rho),

这里,

rho=M*log(sqrt(x2+y2)) phi=atan(y/x)

此函数模仿人类视网膜中央凹视力,并且对于目标跟踪等可用于快速尺度和旋转变换不变模板匹配。

Example. Log-polar transformation.

#include <cv.h> #include <highgui.h> int main(int argc, char** argv) { IplImage* src; if( argc == 2 && (src=cvLoadImage(argv[1],1)!= 0 ) { IplImage* dst = cvCreateImage( cvSize(256,256), 8, 3 ); IplImage* src2 = cvCreateImage( cvGetSize(src), 8, 3 ); cvLogPolar( src, dst, cvPoint2D32f(src->width/2,src->height/2), 40, CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS ); cvLogPolar( dst, src2, cvPoint2D32f(src->width/2,src->height/2), 40, CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS+CV_WARP_INVERSE_MAP ); cvNamedWindow( "log-polar", 1 ); cvShowImage( "log-polar", dst ); cvNamedWindow( "inverse log-polar", 1 ); cvShowImage( "inverse log-polar", src2 ); cvWaitKey(); } return 0; }

And this is what the program displays when opencv/samples/c/fruits.jpg is passed to it

OpenCV<wbr>图像采样<wbr>插值<wbr>几何变换OpenCV<wbr>图像采样<wbr>插值<wbr>几何变换

免责声明:文章转载自《OpenCV 图像采样 插值 几何变换》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇WCF中的数据契约(Continued)Django添加favicon.ico图标下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

I2S (Inter—IC Sound) 总线

I2S  I2S(Inter—IC Sound)总线, 又称 集成电路内置音频总线,是飞利浦公司为数字音频设备之间的音频数据传输而制定的一种总线标准,该总线专责于音频设备之间的数据传输,广泛应用于各种多媒体系统。它采用了沿独立的导线传输时钟与数据信号的设计,通过将数据和时钟信号分离,避免了因时差诱发的失真,为用户节省了购买抵抗音频抖动的专业设备的费用。...

ELM学习(一)

what?: 极限学习机(extreme learning machine)ELM是一种简单易用、有效的单隐层前馈神经网络SLFNs学习算法。2004年由南洋理工大学黄广斌副教授提出。传统的神经网络学习算法(如BP算法)需要人为设置大量的网络训练参数,并且很容易产生局部最优解。极限学习机只需要设置网络的隐层节点个数,在算法执行过程中不需要调整网络的输入权...

说说接口封装

今天给同事封装了一个接口,说起接口封装的事情,其实其实很有的聊。很多时候,说一个服务好,一个服务烂,实际上都是在吐槽服务队外暴露的接口好坏。不管什么语言,封装接口,抽象起来,就是由一个函数名,若干个参数,若干个返回值组成的。封装的好坏,就在这几个上面。 函数名 首先是函数名。函数名的好坏很明显,我的观点,是否简单,不重复。比如在一个User类中你封装一个...

libpcap编程实例

1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <pcap.h> 4 #include <errno.h> 5 #include <sys/socket.h> 6 #include <netinet/in...

CUDA学习:进一步理解块、线程

1. CUDA里的块和线程概念可以用下面的图来表示:   每个grid里包含可以用二维数组表示的block(块),每个block又包含一个可以用二维数组表示的thread(线程)。  2.  二维数组块和线程可以用dim3来定义:   dim3 blockPerGrid(3,2); //定义了3*2=6个blocks   dim3 threadsPerB...

NVIDIA深度学习Tensor Core性能解析(上)

NVIDIA深度学习Tensor Core性能解析(上) 本篇将通过多项测试来考验Volta架构,利用各种深度学习框架来了解Tensor Core的性能。 很多时候,深度学习这样的新领域会让人难以理解。从框架到模型,再到API和库,AI硬件的许多部分都是高度定制化的,因而被行业接受的公开基准测试工具很少也就不足为奇。随着ImageNet和一些衍生模型(Al...