- 浏览: 1407846 次
- 性别:
- 来自: 广州
文章分类
最新评论
-
sdgxxtc:
[quo[color=red]te][/color]
C#使用OleDb读取Excel,生成SQL语句 -
zcs302567601:
博主,你好,一直都有个问题没有搞明白,就是 2.x的版本是通过 ...
NGUI所见即所得之UIPanel -
一样的追寻:
感谢楼主!
有向强连通和网络流大讲堂——史无前例求解最大流(最小割)、最小费用最大流 -
cp1993518:
感谢!从你的博客里学到了很多
Unity日志工具——封装,跳转 -
cp1993518:
学习了~,话说现在的版本custom还真的变委托了
NGUI所见即所得之UIGrid & UITable
一、放射变换
最为常用的几何变换都是线性变换,这包括旋转、缩放、切变、反射以及正投影。在二维空间中,线性变换可以用 2×2 的变换矩阵表示。
1.旋转变换
绕原点逆时针旋转 θ 度角的变换公式是 与 ,用矩阵表示为:
2.伸缩变换
缩放公式为 与 ,用矩阵表示为:
3.错切变换
错切变换公式: x = x0 + b*y0; y = d*x0 + y0; b,d分别是x,y平移的分量
用矩阵乘法表示变换为:
4.平移变换
矩阵乘法表示变换。 ; 变为
二、图像插值放大
1.最邻近插值(近邻取样法):
最临近插值的的思想很简单。对于通过反向变换得到的的一个浮点坐标,对其进行简单的取整,得到一个整数型坐标,这个整数型坐标对应的像素值就是目的像素的像素值,也就是说,取浮点坐标最邻近的左上角点对应的像素值。可见,最邻近插值简单且直观,但得到的图像质量不高。
2.双线性内插值:
对于一个目的像素,设置坐标通过反向变换得到的浮点坐标为(i+u,j+v),其中i、j均为非负整数,u、v为[0,1)区间的浮点数,则这个像素得值 f(i+u,j+v) 可由原图像中坐标为 (i,j)、(i+1,j)、(i,j+1)、(i+1,j+1)所对应的周围四个像素的值决定,即:
f(i+u,j+v) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) +
uvf(i+1,j+1)
其中f(i,j)表示源图像(i,j)处的像素值,以此类推。
这就是双线性内插值法。双线性内插值法计算量大,但缩放后图像质量高,不会出现像素值不连续的的情况。由于双线性插值具有低通滤波器的性质,使高频分量受损,所以可能会使图像轮廓在一定程度上变得模糊。
3.三次卷积法
能够克服以上两种算法的不足,计算精度高,但计算亮大,他考虑一个浮点坐标(i+u,j+v)周围的16个邻点,目的像素值f(i+u,j+v)可由如下插值公式得到:
f(i+u,j+v) = [A] * [B] * [C]
[A]=[ S(u + 1) S(u + 0) S(u - 1) S(u - 2) ]
┏ f(i-1, j-1) f(i-1, j+0) f(i-1, j+1) f(i-1, j+2) ┓
[B]=┃ f(i+0, j-1) f(i+0, j+0) f(i+0, j+1) f(i+0, j+2) ┃
┃ f(i+1, j-1) f(i+1, j+0) f(i+1, j+1) f(i+1, j+2) ┃
┗ f(i+2, j-1) f(i+2, j+0) f(i+2, j+1) f(i+2, j+2) ┛
┏ S(v + 1) ┓
[C]=┃ S(v + 0) ┃
┃ S(v - 1) ┃
┗ S(v - 2) ┛
┏
1-2*Abs(x)^2+Abs(x)^3 , 0<=Abs(x)<1
S(x)={ 4-8*Abs(x)+5*Abs(x)^2-Abs(x)^3 , 1<=Abs(x)<2 其中
S(x)是对 Sin(x*Pi)/x 的逼近(Pi是圆周率——π)
┗ 0 , Abs(x)>=2
最邻近插值(近邻取样法)、双线性内插值、三次卷积法 等插值算法对于旋转变换、错切变换、一般线性变换 和 非线性变换 都适用。
三、编程实现
Java类库内置方法实现了图像几何变换有:旋转,缩放,错切和平移等变换,图像放大使用的算法是最临近插值方法,下面自己实现的算法进行实验,至于Java内置的方法通过调用Graphics2D相关函数设置参数就可以完成,可以查看相应文档。
1.旋转
/**************************************************** * 图像旋转 * pix --原图像像素数组 * opix--输出图像像素数组 * (x,y) --原图像坐标 0<=x<=w, 0<=y<=h * (i,j) --输出图像坐标0<=i,j<=owh * beta --旋转角度 ****************************************************/ public int[] imRotate(int[] pix, float beta, int iw, int ih, int owh) { //1.旋转后的新图像最大最小包围盒宽高 int[] opix = new int[owh * owh]; double t = beta / 180; float cos_beta = (float)Math.cos(t * Math.PI);//顺时针旋转 float sin_beta = (float)Math.sin(t * Math.PI); //2.逆旋转变换, 计算输出图像点p(i,j)所对应的原图像的坐标(x,y) for(int i = 0;i < owh;i++) { for(int j = 0;j < owh;j++) { //旋转变换的逆变换 float u = (j-owh/2)*cos_beta+(i-owh/2)*sin_beta; float v = (i-owh/2)*cos_beta-(j-owh/2)*sin_beta; //换成相对于原图像的绝对坐标 u += iw/2; v += ih/2; int x = (int)u; int y = (int)v; int index = i * owh + j; //3.检验条件, 对满足条件的点(x,y),赋值F(i,j)=f(x,y) if((x >= 0) && (x <= iw - 1) && (y >= 0) && (y <= ih - 1)) opix[index] = pix[y * iw + x]; } } return opix; }
实验效果如下:
2.镜像变换
//镜象变换 public int[] imMirror(int[] pixs, int w, int h, int n) { int[] pix = new int[w * h]; //根据镜象变换公式,计算(u,v)并赋值F(u,v)=f(i,j) for(int j = 0; j < h; j++) { for(int i = 0; i < w; i++) { if(n == 0) //水平 { int u = w - 1 - i; int v = j; pix[v*w+u] = pixs[j*w+i]; } else if(n == 1)//垂直 { int u = i; int v = h - 1 - j; pix[v*w+u] = pixs[j*w+i]; } } } return pix; }
实验效果如下:
3.错切变换
* 错切变换算法 * 1.计算图像四角点坐标 * 2.计算包围图像的最小矩形,即包围盒的宽和高 * 3.将处理包围盒内的所有像素设置为背景色 * 4.根据错切变换公式, * u = (int)(i + j * shx) * v = (int)(i * shy + j) * 计算(u,v)并赋值 F(u,v) = f(i,j) **********************************************/ public int[] imShear(int[] pixs, double shx, double shy, int w, int h, int ow, int oh) { int[] pix = new int[ow * oh]; //根据错切变换公式,计算(u,v)并赋值F(u,v)=f(i,j) for(int j = 0; j < h; j++) { for(int i = 0; i < w; i++) { int u = (int)(i + j * shx); int v = (int)(i * shy + j); pix[v*ow+u] = pixs[j*w+i]; } } return pix; }
实验效果如下:
4.平移变换
//平移变换算法 public int[] imTrans(int[] pixs, int tx, int ty, int w, int h, int ow, int oh) { int u, v; int[] pix = new int[ow * oh]; //根据错切变换公式,计算(u,v)并赋值F(u,v)=f(i,j) for(int j = 0; j < h; j++) { for(int i = 0; i < w; i++) { u = i + tx; v = j + ty; pix[v*ow+u] = pixs[j*w+i]; } } return pix; }
实验效果如下:
5.最邻近插值
//最邻近插值 public int[] nearNeighbor(int pixs[], int iw, int ih, int ow, int oh, float p) { int opix[] = new int[ow * oh];//目标图像素数组 ColorModel cm = ColorModel.getRGBdefault(); for(int i = 0; i < oh; i++) { int u = (int)(i/p); for(int j = 0; j < ow; j++) { int r, g, b; int v = (int)(j/p); r = cm.getRed(pixs[u*iw+v]); g = cm.getGreen(pixs[u*iw+v]); b = cm.getBlue(pixs[u*iw+v]); opix[i*ow+j] = 255 << 24|r << 16|g << 8|b; } } return opix; }
实验效果如下:
6.双线性插值
//双线性插值算法 public int[] bilinear(int pixs[], int iw, int ih, int ow, int oh, float p) { int pixd[]=new int[ow * oh];//目标图像素数组 ColorModel cm = ColorModel.getRGBdefault(); for(int i = 0; i < oh-1; i++) { float dy = i/p; int iy = (int)dy; if(iy > ih-2) iy = ih-2; float d_y = dy - iy; for(int j = 0; j < ow-1; j++) { int a,r,g,b; float dx = j/p; int ix = (int)dx; if(ix > iw-2) ix = iw-2; float d_x= dx - ix; //f(i+u,j+v)=(1-u)(1-v)f(i,j)+u(1-v)f(i+1,j)+ // (1-u)vf(i,j+1)+uvf(i+1,j+1) r = (int)((1-d_x)*(1-d_y)*cm.getRed(pixs[iy*iw+ix])+ d_x*(1-d_y)*cm.getRed(pixs[iy*iw+ix+1])+ (1-d_x)*d_y*cm.getRed(pixs[(iy+1)*iw+ix])+ d_x*d_y*cm.getRed(pixs[(iy+1)*iw+ix+1])); g = (int)((1-d_x)*(1-d_y)*cm.getGreen(pixs[iy*iw+ix])+ d_x*(1-d_y)*cm.getGreen(pixs[iy*iw+ix+1])+ (1-d_x)*d_y*cm.getGreen(pixs[(iy+1)*iw+ix])+ d_x*d_y*cm.getGreen(pixs[(iy+1)*iw+ix+1])); b = (int)((1-d_x)*(1-d_y)*cm.getBlue(pixs[iy*iw+ix])+ d_x*(1-d_y)*cm.getBlue(pixs[iy*iw+ix+1])+ (1-d_x)*d_y*cm.getBlue(pixs[(iy+1)*iw+ix])+ d_x*d_y*cm.getBlue(pixs[(iy+1)*iw+ix+1])); pixd[i*ow+j] = 255 << 24|r << 16|g << 8|b; } } return pixd; }
实验效果如下:
7.三次卷积插值
//对整个图像按给定的宽度和高度比例进行缩放 public int[] scale(int[] pix, int iw, int ih, int ow, int oh, float scalex, float scaley) { int pixelsSrc[] = new int[iw * ih]; int pixelsDest[] = new int[ow * oh]; //第三步,缩放图像 this.scale(pix, 0, 0, iw, ih, iw, scalex, scaley, pixelsDest); return (pixelsDest); } /******************************************************** * src 原图像的像素数据, * (x, y) 被缩放的区域在左上角的坐标, * (w, h) 缩放区域的宽度和高度 * scansize 原图像的扫描宽度 * (scalex, scaley) 水平和垂直方向上的缩放比 * dst 缩放后的图像像素数据 ********************************************************/ public void scale(int[] src, int x, int y, int w, int h, int scansize, float scalex, float scaley, int[] dst) { //原图像的宽度 int srcWidth = scansize; //原图像可以扫描的总行数:即原图像的高度 int srcHeight = src.length / scansize; //width---height:处理区域的宽度和高度, //如果参数传递是合法的,那么它们就是w,h int width = w; int height = h; if((x + w) > scansize) width = scansize - x; if((y + h) > srcHeight) height = srcHeight - y; int dstWidth = (int)( width * scalex + 0.5f); int dstHeight = (int)(height * scaley + 0.5f); //进行反向变换 //i--按行,j--按列 for(int i = 0;i < dstHeight;i++) { //按反向变换法,获取第i行所对应的原图像的位置:行:yy float y_inverse_map = i / scaley; int y_lt = (int)y_inverse_map; //垂直方向偏移量 float v = y_inverse_map - y_lt; //左上角的y坐标 y_lt += y; int indexBase = i * dstWidth; for(int j = 0;j < dstWidth;j++) { float x_inverse_map = j / scalex; int x_lt = (int)x_inverse_map; //水平方向偏移量 float u = x_inverse_map - x_lt; //左上角的y坐标 x_lt += x; //通过计算获取变换后的点 int index = indexBase + j; dst[index] = interpolate(src, x_lt, y_lt, u, v, srcWidth, srcHeight); } } } /************************************************************** * src:原图像的像素, * (x,y):经过反向变换后,与反向变换点最接近的原图像的左上角的点 * (u,v):反向变换点相对(x,y)点的偏移量. * scanw:原图像的扫描宽度,scanh原图像的高度 **************************************************************/ private int interpolate(int[] src, int x, int y, float u, float v, int scanw, int scanh) { ColorModel colorModel = ColorModel.getRGBdefault(); int r = 0; int g = 0; int b = 0; //邻近区域的像素值 int red[][] = new int[4][4]; int green[][] = new int[4][4]; int blue[][] = new int[4][4]; //邻近区域的坐标 int xx[] = new int[4]; int yy[] = new int[4]; xx[0] = x - 1; xx[1] = x; xx[2] = x + 1; xx[3] = x + 2; yy[0] = y - 1; yy[1] = y; yy[2] = y + 1; yy[3] = y + 2; if(xx[0] < 0) xx[0] = 0; if(yy[0] < 0) yy[0] = 0; if(xx[2] > scanw - 1) xx[2] = scanw - 1; if(yy[2] > scanh - 1) yy[2] = scanh - 1; if(xx[3] > scanw - 1) xx[3] = scanw - 1; if(yy[3] > scanh - 1) yy[3] = scanh - 1; //获取4*4区域的像素值 int i = 0; int j = 0; for(i = 0; i < 4; i++) { int indexBase = yy[i] * scanw; //j处理像素行 for(j = 0; j < 4; j++) { int index = indexBase + xx[j]; red[i][j] = colorModel.getRed(src[index]); green[i][j] = colorModel.getGreen(src[index]); blue[i][j] = colorModel.getBlue(src[index]); } } float su[] = new float[4]; float sv[] = new float[4]; su[0] = sinx_x(1.0f + u); su[1] = sinx_x(u); su[2] = sinx_x(1.0f - u); su[3] = sinx_x(2.0f - u); sv[0] = sinx_x(1.0f + v); sv[1] = sinx_x(v); sv[2] = sinx_x(1.0f - v); sv[3] = sinx_x(2.0f - v); //作矩阵乘积:sv * red,sv * green,sv * blue float sv_r[] = new float[4]; float sv_g[] = new float[4]; float sv_b[] = new float[4]; for(i = 0; i < 4; i++) { for(j = 0; j < 4; j++) { sv_r[i] += (sv[j] * red[j][i]); sv_g[i] += (sv[j] * green[j][i]); sv_b[i] += (sv[j] * blue[j][i]); } } r = (int)(su[0] * sv_r[0] + su[1] * sv_r[1] + su[2] * sv_r[2] + su[3] * sv_r[3]); g = (int)(su[0] * sv_g[0] + su[1] * sv_g[1] + su[2] * sv_g[2] + su[3] * sv_g[3]); b = (int)(su[0] * sv_b[0] + su[1] * sv_b[1] + su[2] * sv_b[2] + su[3] * sv_b[3]); r = (r < 0) ? 0 : ((r > 255) ? 255 : r); g = (g < 0) ? 0 : ((g > 255) ? 255 : g); b = (b < 0) ? 0 : ((b > 255) ? 255 : b); return (0xFF000000 | (( r << 16 ) | ( g << 8 ) | b )); } //计算 sin(x)/x 的值,采用多项式展开 private float sinx_x(float x) { float x_abs = Math.abs(x); float x_x = x_abs * x_abs; float x_x_x = x_x * x_abs; if(x_abs < 1.0f) return (1.0f - 2.0f * x_x + x_x_x); else if(x_abs < 2.0f) return (4.0f - 8.0f * x_abs + 5.0f * x_x - x_x_x); else return 0.0f; }
实验效果如下:
发表评论
-
模式识别
2012-09-03 06:00 309由于时间关系,不能详细整理这部分的内容,但还是先以代码来学习 ... -
图像形态学
2012-09-03 05:56 265由于时间关系,不能详细整理这部分的内容,但还是先以代码来学习 ... -
图像特征与分析
2012-09-03 05:54 294由于时间关系,不能详细整理这部分的内容,但还是先以代码来学习 ... -
图像分割
2012-09-03 03:04 28359终于写完数字图像分割 ... -
图像分割
2012-09-03 03:00 0终于写完数字图像分割这部分内容了,由于内容比较多,因此做一个 ... -
图像分割
2012-09-03 02:55 7终于写完数字图像分割这部分内容了,由于内容比较多,因此做一个 ... -
图像锐化(增强)和边缘检测
2012-08-20 21:18 99054图像锐化和边缘检测 ... -
图像增强——频域增强
2012-08-20 01:16 17254在进行图像处理的过程中,获取原始图像后,首先需要对图像进 ... -
图像增强——空域增强
2012-08-19 16:01 4100图像增强分为空域增强 ... -
图像的时频变换——离散余弦变换
2012-08-18 23:12 7879研究过离散傅里叶变换的,都会觉得离散余弦变换的会更简单,不过不 ... -
图像的时频变换——离散傅里叶变换
2012-08-18 01:03 33190一直很纳闷,几乎所有数字图像处理的书都会介绍数字时频变 ... -
图像的时频变换
2012-08-17 15:25 0一直很纳闷,几乎所有 ... -
图像点运算
2012-08-17 13:33 2601一、彩色图像转变为灰度图像 将彩色图像进行灰度处理的原理就 ... -
图像的数字化
2012-08-17 03:42 1570一、采样 采样就是指把时间域或空间域的连续量转化成离散量 ... -
灰度直方图
2012-08-17 03:02 4199图像的统计特性 图像的基本统计分析量如下:1.熵 一个 ...
相关推荐
数字图像几何变换论文 数字图像几何变换是图像处理中最常见的手段之一,通过对变形的图像进行几何校正,可以得出准确的图像。常用的几何变换功能包括图像的平移、图像的镜像变换、图像的转置、图像的缩放、图像的...
在计算机视觉和图像处理领域,图像几何变换是一种重要的技术,用于改变图像的位置、尺寸或方向。本主题将深入探讨C++实现的几种基本图像几何变换:平移、镜像、转置、缩放和旋转。这些操作对于图像分析、图像配准、...
在计算机视觉和图像处理领域,图像几何变换是基础且重要的技术之一。这些变换可以改变图像的位置、方向或形状,以适应不同的应用场景。本教程将深入探讨如何使用C++语言实现图像的几何变换,包括平移、旋转、镜像和...
1. **图像几何变换**:这是图像处理的一个基本概念,它涉及将图像从一个坐标系映射到另一个坐标系。常见的几何变换有平移、旋转、缩放、剪切和扭曲等。在Python中,通常使用OpenCV库来实现这些操作,如`geometric_...
图像几何变换是图像处理中的重要组成部分,主要用于改变图像的形状和位置。本文将重点讨论图像仿射变换、图像透视变换以及基于图像透视变换的图像校正,并进行总结。这些概念和方法在Python中通常借助OpenCV库来实现...
"C++实现图像几何变换"这一主题,意味着我们将在C++编程环境下,利用特定的库和算法来改变图像的位置、大小、形状或者方向,以满足不同的应用需求。在本项目中,通过VC++(Visual C++)这一集成开发环境,可以实现...
"图像几何变换处理框架"是一个专门用于实现这些变换的软件框架,它提供了丰富的功能,包括图像增强、去噪、几何变换和形态学处理等核心模块。下面我们将深入探讨这些知识点。 首先,**图像增强**是提升图像质量的...
在计算机视觉和图像处理领域,图像几何变换是一种重要的技术,用于改变图像的形状、位置或大小,以适应不同的应用场景。这种变换通常涉及到坐标系统的转换,包括平移、旋转、缩放、剪切和投影等。在C++编程环境中,...
数字图像几何变换的分析与实现 数字图像几何变换是计算机视觉和图像处理领域中的一个重要方向,本文档对数字图像几何变换的分析和实现进行了深入的研究和讨论。 第一章 前言中,作者对数字图像进行了概述,包括...
图像几何变换程序设计 图像几何变换程序设计是计算机视觉和图像处理领域中的一个重要研究方向。本文档是兰州理工大学计算机与通信学院2012年秋季学期的学位论文,主要研究图像几何变换程序设计。下面是本文档的详细...
在数字图像处理领域,几何变换是一种重要的技术,用于改变图像的空间布局或形状。这通常涉及到图像的平移、旋转、缩放、错切等操作。本资源提供的代码着重于图像校正,它可以帮助理解并实践这些概念。VS2008是Visual...
在计算机视觉和数字图像处理领域,几何变换是至关重要的技术之一。本项目通过VC++编程语言实现对BMP图像的几何变换,包括180度旋转、平移等操作,这些变换有助于理解和处理图像的不同应用场景,如图像校正、目标识别...
进行图像几何变换时,通常会先分析图像特点,例如图像的尺寸、分辨率和色彩模式,以确定合适的变换方法。在MATLAB中,可以使用`imresize`进行图像缩放,`flipud`和`fliplr`进行上下或左右镜像,`rot90`进行图像转置...
"图像几何变换" 图像几何变换是指对图像进行平移、剪切、缩放、旋转、镜像、错切等操作,以改变图像的几何位置和形状。这些操作都是图像处理中的基本操作,广泛应用于图像编辑、图像识别、计算机视觉等领域。 图像...
图像几何变换是计算机视觉和图像处理领域中的重要概念,它涉及到图像在二维空间中的位置、形状和大小的改变。在Matlab中,我们可以通过编程实现各种几何变换,以适应不同的应用场景,如图像矫正、图像拼接、目标定位...
通过实践这些代码,你可以更好地掌握图像几何变换和二维重建的原理和方法。 四、应用实例 在医学领域,几何变换和二维重建有多种应用。例如,在脑部MRI图像中,可以使用几何变换来对不同时间点的图像进行配准,以...
### 图像几何变换详解 #### 一、图像仿射变换 **定义与原理:** 图像仿射变换是一种基本的图像几何变换方式,它保持了图像中的平行性和直线性不变。在数学上,图像仿射变换可以理解为在一个二维平面内进行的一次...