图像处理之错切

2016-01-01 08:34:00 weixin_34146986 阅读数 637
  • Darknet安装与测试

    从理论到实践,快速入门Spring Boot 2.x 从Spring Boot扩展到Spring相关知识的学习和实战 Spring Boot与其他技术框架的集成 Spring Boot部分功能源码解析

    23742课时 0分钟 1015人学习 马孔伟
    免费试看

图像处理之错切变换

一:基本数学知识:

图像错切变换在图像几何形变方面很实用,常见的错切变换分为X方向与Y方向的

错切变换。相应的数学矩阵分别例如以下:

  

依据上述矩阵如果P(x1, y1)为错切变换之前的像素点。则错切变换以后相应的像素

P’(x2, y2)当X方向错切变换时:


当Y方向错切变换时:


二:程序实现基本思路

实现图像错切变换时,必须考虑图像将目标像素点坐标变为源相点坐标时小数部分对

像素值的影响,这里通过临近点插值算法实现了目标像素值的计算。依据目标像素计

算源像素的公式能够依据上面的数学公式运算以后分别求的x1,y1的值。因为错切以

后图像会在宽或者高上比原图像大,多出来的这些背景像素默认填充颜色为黑色。

类ShearFilter实现了图像水平或者垂直方向的错切变换,支持角度与背景颜色參数

设置。

 三:编程关键点解析

Ø  计算错切以后图像的宽与高

        double angleValue = (angle/180.0d) * Math.PI;
        outh = vertical ? (int)(height + width * Math.tan(angleValue)) : height;
        outw = vertical ? width : (int)(width + height * Math.tan(angleValue));
        System.out.println("after shear, new width : " + outw);
        System.out.println("after shear, new height: " + outh);
Ø  依据目标像素点坐标计算源像素点坐标

	double prow = vertical ? row + Math.tan(angleValue) * (col - width) : row;
	double pcol = vertical ?

col : col + Math.tan(angleValue) * (row - height); int[] rgb = getPixel(inPixels, width, height, prow, pcol);

Ø  临近点插值计算目标像素点像素值

private int[] getPixel(int[] input, int width, int height, 
		double prow, double pcol) {
	double row = Math.floor(prow);
	double col = Math.floor(pcol);
	if(row < 0 || row >= height) {
		return new int[]{backgroundColor.getRed(), 
				backgroundColor.getGreen(), 
				backgroundColor.getBlue()};
	}
	if(col < 0 || col >= width) {
		return new int[]{backgroundColor.getRed(), 
				backgroundColor.getGreen(), 
				backgroundColor.getBlue()};
	}
	double u = vertical ? (prow - row) : pcol - col;
	int nextCol = (int)(col + 1);
	int nextRow = (int)(row + 1);
	if((col + 1) >= width) {
		nextCol = (int)col;
	}
	if((row + 1) >= height) {
		nextRow = (int)row;
	}
	int index1 = (int)(row * width + col);
	int index2 = vertical ? (int)(nextRow * width + col) : (int)(row * width + nextCol);
	
	int tr1, tr2;
	int tg1, tg2;
	int tb1, tb2;
	
    tr1 = (input[index1] >> 16) & 0xff;
    tg1 = (input[index1] >> 8) & 0xff;
    tb1 = input[index1] & 0xff;
    
    tr2 = (input[index2] >> 16) & 0xff;
    tg2 = (input[index2] >> 8) & 0xff;
    tb2 = input[index2] & 0xff;
    
    int tr = (int)(tr1 * (1-u) + tr2 * u);
    int tg = (int)(tg1 * (1-u) + tg2 * u);
    int tb = (int)(tb1 * (1-u) + tb2 * u);
    
	return new int[]{tr, tg, tb};
}
四:执行效果


五:类ShearFilter完整代码

package com.gloomyfish.filter.study;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;

public class ShearFilter extends AbstractBufferedImageOp {
	private int outw;
	private int outh;
	private double angle;
	private Color backgroundColor;
	private boolean vertical;
	
	public void setVertical(boolean vertical) {
		this.vertical = vertical;
	}

	public ShearFilter()
	{
		backgroundColor = Color.BLACK;
		vertical = false;
		this.angle = 20;
	}
	
	public int getOutw() {
		return outw;
	}
	public void setOutw(int outw) {
		this.outw = outw;
	}
	public int getOuth() {
		return outh;
	}
	public void setOuth(int outh) {
		this.outh = outh;
	}
	public double getAngle() {
		return angle;
	}
	public void setAngle(double angle) {
		this.angle = angle;
	}
	public Color getBackgroundColor() {
		return backgroundColor;
	}
	public void setBackgroundColor(Color backgroundColor) {
		this.backgroundColor = backgroundColor;
	}
	@Override
	public BufferedImage filter(BufferedImage src, BufferedImage dest) {
		int width = src.getWidth();
        int height = src.getHeight();

        double angleValue = (angle/180.0d) * Math.PI;
        outh = vertical ? (int)(height + width * Math.tan(angleValue)) : height;
        outw = vertical ? width : (int)(width + height * Math.tan(angleValue));
        System.out.println("after shear, new width : " + outw);
        System.out.println("after shear, new height: " + outh);
        
        int[] inPixels = new int[width*height];
        int[] outPixels = new int[outh*outw];
        getRGB( src, 0, 0, width, height, inPixels );
        int index = 0;
        for(int row=0; row<outh; row++) {
        	int ta = 0;
        	for(int col=0; col<outw; col++) {
				double prow = vertical ? row + Math.tan(angleValue) * (col - width) : row;
				double pcol = vertical ?

col : col + Math.tan(angleValue) * (row - height); int[] rgb = getPixel(inPixels, width, height, prow, pcol); index = row * outw + col; outPixels[index] = (ta << 24) | (rgb[0] << 16) | (rgb[1] << 8) | rgb[2]; } } if ( dest == null ) dest = createCompatibleDestImage( src, null ); setRGB( dest, 0, 0, outw, outh, outPixels ); return dest; } private int[] getPixel(int[] input, int width, int height, double prow, double pcol) { double row = Math.floor(prow); double col = Math.floor(pcol); if(row < 0 || row >= height) { return new int[]{backgroundColor.getRed(), backgroundColor.getGreen(), backgroundColor.getBlue()}; } if(col < 0 || col >= width) { return new int[]{backgroundColor.getRed(), backgroundColor.getGreen(), backgroundColor.getBlue()}; } double u = vertical ? (prow - row) : pcol - col; int nextCol = (int)(col + 1); int nextRow = (int)(row + 1); if((col + 1) >= width) { nextCol = (int)col; } if((row + 1) >= height) { nextRow = (int)row; } int index1 = (int)(row * width + col); int index2 = vertical ? (int)(nextRow * width + col) : (int)(row * width + nextCol); int tr1, tr2; int tg1, tg2; int tb1, tb2; tr1 = (input[index1] >> 16) & 0xff; tg1 = (input[index1] >> 8) & 0xff; tb1 = input[index1] & 0xff; tr2 = (input[index2] >> 16) & 0xff; tg2 = (input[index2] >> 8) & 0xff; tb2 = input[index2] & 0xff; int tr = (int)(tr1 * (1-u) + tr2 * u); int tg = (int)(tg1 * (1-u) + tg2 * u); int tb = (int)(tb1 * (1-u) + tb2 * u); return new int[]{tr, tg, tb}; } public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM) { if ( dstCM == null ) dstCM = src.getColorModel(); return new BufferedImage(dstCM, dstCM.createCompatibleWritableRaster(outw, outh), dstCM.isAlphaPremultiplied(), null); } }

下半年事情比較多。博客一直没有更新,感谢众多网友的关注与留言

我会继续努力的!再次声明一下:请不要向我索取源代码!谢谢!

代码我在整理中,终于我会开源让大家自己下载,请耐心等待!

2015-06-28 21:29:22 u012005313 阅读数 3521
  • Darknet安装与测试

    从理论到实践,快速入门Spring Boot 2.x 从Spring Boot扩展到Spring相关知识的学习和实战 Spring Boot与其他技术框架的集成 Spring Boot部分功能源码解析

    23742课时 0分钟 1015人学习 马孔伟
    免费试看

图像的错切变换实际上是平面景物在投影平面上的非垂直投影效果。图像错切变换也称为图像剪切、错位或错移变换。图像错切的原理就是保持图像上各点的某一坐标不变,将另一个坐标进行线性变换,坐标不变的轴称为依赖轴,坐标变换的轴称为方向轴。图像错切一般分为两种情况:水平方向错切和垂直方向错切。


####################################################


水平方向的错切,即沿x轴方向关于y的错切,即x=x0+c*y0, y=y0

若c>0,则沿+x轴方向错切,反之,如果c<0,则沿-x轴方向错切.


void imageTwist(IplImage *src, IplImage *res, float ratio)
{
	cvZero(res);
	int res_wid;
	int res_hei;

	unsigned char* src_data = (unsigned char*)src->imageData;
	unsigned char* res_data = (unsigned char*)res->imageData;

	for (int i=0; i<src->height; i++)
	{
		if (ratio >= 0)
			for (int j=0; j<src->width; j++)
			{
				res_hei=i;
				res_wid=j+res_hei*ratio;
				res_data[res_hei*res->widthStep+res_wid] = src_data[i*src->widthStep+j];
			}
		else 
		{
			int offset=ratio*src->height;
			for (int j=src->width-1; j>=0; j--)
			{
				res_hei=i;
				res_wid=j+res_hei*ratio;
				res_data[res_hei*res->widthStep+res_wid+offset] = src_data[i*src->widthStep+j];
			}
		}
	}

	cvNamedWindow("src");
	cvNamedWindow("res");
	cvShowImage("src", src);
	cvShowImage("res", res);
	cvWaitKey(0);
	cvReleaseImage(&src);
	cvReleaseImage(&res);
	cvDestroyAllWindows();
}

void imageCutting(void)
{
	src=cvLoadImage("lena.jpg", 0);
	if (src == NULL)
		exit(0);

	float ratio;
	cout<<"输入水平错切比率:"<<endl;
	cin>>ratio;
	
	int res_wid;
	int res_hei;
	if (ratio < 0)
	{
		res_wid=src->width+src->height*ratio*(-1);
	} else {
		res_wid=src->width+src->height*ratio;
	}

	res_hei=src->height;
	CvSize size=cvSize(res_wid, res_hei);
	res=cvCreateImage(size, src->depth, src->nChannels);
	if (res == NULL)
		exit(0);

	imageTwist(src, res, ratio);//图像扭曲
}








#########################################################


垂直方向错切,即沿y轴方向关于x的错切。与水平错切类似变换,即x=x0, y=y0+b*x0


void imageTwistV(IplImage *src, IplImage *res, float ratio)
{
	cvZero(res);
	int res_wid;
	int res_hei;

	unsigned char* src_data = (unsigned char*)src->imageData;
	unsigned char* res_data = (unsigned char*)res->imageData;

	for (int i=0; i<src->width; i++)
	{
		if (ratio >= 0)
		{
			int offset=ratio*src->width;
			for (int j=0; j<src->height; j++)
			{
				res_wid=i;
				res_hei=j+offset-res_wid*ratio;
				res_data[res_hei*res->widthStep+res_wid] = src_data[j*src->widthStep+i];
			}
		}
		else 
		{
			//int offset=ratio*src->height*(-1);
			for (int j=src->height-1; j>=0; j--)
			{
				res_wid=i;
				res_hei=j+res_wid*ratio*(-1);
				res_data[res_hei*res->widthStep+res_wid] = src_data[j*src->widthStep+i];
			}
		}
	}

	cvNamedWindow("src");
	cvNamedWindow("res");
	cvShowImage("src", src);
	cvShowImage("res", res);
	cvWaitKey(0);
	cvReleaseImage(&src);
	cvReleaseImage(&res);
	cvDestroyAllWindows();
}

void imageCutting(void)
{
	src=cvLoadImage("lena.jpg", 0);
	if (src == NULL)
		exit(0);

	float ratio=0;
	cout<<"输入垂直错切比率:"<<endl;
	cin>>ratio;
	
	int res_wid;
	int res_hei;
	if (ratio < 0)
	{
		res_hei=src->height+src->width*ratio*(-1);
		//res_wid=src->width+src->height*ratio*(-1);
	} else {
		res_hei=src->height+src->width*ratio;
		//res_wid=src->width+src->height*ratio;
	}

	res_wid=src->width;
	//res_hei=src->height;
	CvSize size=cvSize(res_wid, res_hei);
	res=cvCreateImage(size, src->depth, src->nChannels);
	if (res == NULL)
		exit(0);

//	imageTwistH(src, res, ratio);//图像扭曲
	imageTwistV(src, res, ratio);
}





2012-04-18 12:15:55 caiqi1123 阅读数 11450
  • Darknet安装与测试

    从理论到实践,快速入门Spring Boot 2.x 从Spring Boot扩展到Spring相关知识的学习和实战 Spring Boot与其他技术框架的集成 Spring Boot部分功能源码解析

    23742课时 0分钟 1015人学习 马孔伟
    免费试看

1.1图像的裁剪:

在实际应用或科研领域,很多时候要对图像裁剪操作。图像裁剪就是在源图像或者大图像中裁剪图像块来,这个图像块一般是多边形的。图像裁剪是图像处理中最基本的操作之一。

使用imcrop函数对图像进行裁剪操作,然后制作出动画效果,该函数有两个参数,一个用来指定裁剪的图像,另一个用来指定裁剪矩形。一般格式如下:

           imcrop(A,[80,120,100,50]);

[80,120,100,50]的含义是:以图像的(80,,10)点位裁剪矩形的左上角坐标,裁剪的宽度是100,高度是50。

用roipoly函数进行多边形区域的裁剪,

             roipoly(A,c1,c2);c1,c2定义区域的向量。

1.2图像的缩放:

在图像缩放过程中,涉及图像数据的删除与增加。特别是图像放大的时候需要考虑如何自傲扩大后的空隙中加入新的图像颜色数据。增加颜色数据的方法主要根据周围相近像素的颜色值进行插值计算。

使用imresize函数缩放图像.形式为:imreseze(A,n)A为图像,n为放大倍数。

另外一种是:imreseze(A,[n,m])把原有的图像放大为行列分别为n,m的图像。

三种插值方法:

1.最近邻插值法:是imreseze默认的方法,

2.双线性插值方法:格式:imreseze(A,n,'bilinear').

3.双立方插值方法:格式:imreseze(A,n,'bicubic').

1.3图像的选转:

使用imrotate函数进行图像的旋转。

一般的格式为:imrotate(A,Angle,Method,Bbox).

Angle:旋转地角度,Method:为插值的方法,可以在,nearest、bilinear、bicubic中选着,Bbox为loose是底板放大,显示整个图形,导致图形变小是默认的情况,为crop时旋转图形的底板不变图形可能被切割,一般使用crop形式。

2.1图像的几何变换

图像二维仿射变换MATLAB使用imtransform函数完成图像空间变换。

格式imtransform(A,T)

其中参数A是要变换的图像,T是由makeform函数产生的变换结构.

在maketform('P',......)函数中,参数P可以议一下 形式:

affine:仿射变换形式。

projective:投影变换形式;

cusyom:自定义函数变换;

box:利用函数中的另外参数产生仿射变换结构;

composite:该参数是实现多次调用tformfwd功能;

maketform:函数就是利用给定的参数建立变换结构,然后把该变换结构赋予结构变量T。根据得到的结构体变量T,调用imtransform(A,T)函数进行变换。

3:图像的领域操作

领域操作指在图像处理时,处理像素的某领域内各个像素值,输出要处理的像素的新值。领域财政是图像处理(例如图像增强、图像滤波等)时经常用到的操作方法。使用该方法处理图像时一般使用算子模板进行再图像上滑动,划定的时候对模板进过区域进行运算,把计算的结果作为区域中心像素的新值,所以有时领域操作也称为划定领域操作。领域操作方法充分地领用了图像相领像素间的颜色关系,利用相邻像素间的颜色分布对图像进行平滑、增强、边缘提取、滤波、恢复等操作。

空间几何变换

将(w,z)坐标系上的图像变换为(x,y)坐标系上的图像,可以表示为: (x,y) = T{(w,z)}

比如:
(x,y) = T{(w,z)} = (w/2, z/2)


仿射变换

仿射变换是一种常用矩阵变换,它可以表示成矩阵的形式:

 

注意:

(1)上图Scaling中,如果A图宽高位(w1,h1)。现在要求将A图缩放为宽高为(w2,h2)的B图。那如何分别求宽高的缩放率呢?其实可以根据Scaling中的公式。既然知道A和B图的宽高,即知道了图像右下角的坐标(w1,h1)和(w2,h2).所以sx=w2/w1;sy=h2/h1。

(2)

在matlab里面实现

wz = [3 4 1];
T = [2 0 0; 0 3 0; 0 0 1];
xy = wz * T;
wz = xy * inv(T);

为了避免归一化参数,我们可以借助maketform函数:

T = [2 0 0; 0 3 0; 0 0 1];
tform = maketform('affine', T);
wz = [1 2; 3 4];
xy = tformfwd(wz, tform);
wz = tforminv(xy, tform);

我们可以用一个栅格图像来形象的表示这些变换的效果:

这些变换使用的变换矩阵分别是:

对图像应用空间变换

有两种方法:正向映射和反向映射

反向映射的过程是:对每一个输出像素,计算它在输入图像上的位置,根据输入图像上该位置附近的像素值决定输出像素的值。

在matlab中,简单的变换可以直接用单个函数实现。

图像缩放使用:

g = imresize(f, scale);
g = imresize(f, [ROW COL]);

图像旋转使用:

g = imrotate(f, angle);

图像剪切使用:

g = imcrop(f, [X, Y, WIDTH, HEIGHT]);

在matlab中使用imtransform实现图像的空间变换。语法是

g = imtransform(f, tform, interp);

其中,interp可以是'nearest','bilinear'或者'bicubic'。

比如:

f = chekerboard(50);
s = 0.8;
theta = pi/6;
T = [s*cos(theta) s*sin(theta) 0;
-s*sin(theta) s*cos(theta) 0;
0 0 1];
tform = maketform('affine', T);
g = imtransform(f, tform);

双线性滤波:


图像配准

根据两幅图像,算出一个变换参数,使得一幅图像经过这样的变换后和另一图像接近

AffineTransform类描述了一种二维仿射变换的功能,它是一种二维坐标到二维坐标之间的线性变换,保持二维图形的平直性(译注: straightness,即变换后直线还是直线不会打弯,圆弧还是圆弧)和平行性(译注:parallelness,其实是指保二维图形间的相对位置关系不变,平行线还是平行线,而直线上点的位置顺序不变,另特别注意向量间夹角可能会发生变化。)仿射变换可以通过一系列的原子变换的复合来实现,包括:平移Translation)、缩放Scale)、翻转Flip)、旋转Rotation)和错切Shear)。

PerspectiveTransform是描述一种实际三维空间到二维空间的变换。始终遵循“近大远小”的规律。当相机的光轴垂直于物体表面时{因为物体的表面点z坐标都相等,故没有“近大远小”的现象。},发生的是类似于某些仿射变换,如平移Translation)、缩放Scale)、翻转Flip)、旋转Rotation)【没有“错切”!】;当相机的光轴不垂直于物体表面时,发生的是透视变换。


2019-07-16 12:58:26 wujuxKkoolerter 阅读数 0
  • Darknet安装与测试

    从理论到实践,快速入门Spring Boot 2.x 从Spring Boot扩展到Spring相关知识的学习和实战 Spring Boot与其他技术框架的集成 Spring Boot部分功能源码解析

    23742课时 0分钟 1015人学习 马孔伟
    免费试看

图像几何变换-错切变换

图像的错切变换实际上是平面景物在投影平面上的非垂直投影。错切使图像中的图形产生扭变,这种扭变只在一个方向上产生,即分别为水平错切变换和垂直错切变换。

1 水平错切变换

水平错切变换只是在水平方向是发生形变,垂直方向保持不变,数学表达式如下:
(8-1){x=x+byy=y \begin{cases} x&#x27; = x + by \\ y&#x27; = y \end{cases} \tag{8-1}
其中,(x,y)(x,y)为图像的坐标;(x,y)(x&#x27;,y&#x27;)为变换后的坐标。b=tan(θ)b = \tan(\theta);当b&gt;0b \gt0时,沿X轴正方向作错切变换;当b&lt;0b \lt 0时,沿X轴负方向作错切变换。

2 垂直方向错切变换

垂直方向的错切变换只在垂直方向发生形变,水平方向保持不变。数学表达式如下:
(8-2){x=xy=y+dx \begin{cases} x&#x27; = x \\ y&#x27; = y + dx \end{cases} \tag{8-2}
其中,(x,y)(x,y)为图像的坐标;(x,y)(x&#x27;,y&#x27;)为变换后的坐标。d=tan(θ)d = \tan(\theta);当b&gt;0b \gt0时,沿Y轴正方向作错切变换;当b&lt;0b \lt 0时,沿Y轴负方向作错切变换。

2016-07-05 19:15:00 a18861227 阅读数 342
  • Darknet安装与测试

    从理论到实践,快速入门Spring Boot 2.x 从Spring Boot扩展到Spring相关知识的学习和实战 Spring Boot与其他技术框架的集成 Spring Boot部分功能源码解析

    23742课时 0分钟 1015人学习 马孔伟
    免费试看
Matlab实现图像错切源代码

%错切
im=(imread('robot.jpg'));
im1=rgb2gray(im);
figure,imshow(im1);
[row,col]=size(im1); %获取行数 和 列数

%图像的水平错切
G=zeros(row,col);
a=pi/6; %水平错切30度
b=tan(a);
for m=1:row
for n=1:col
G(round(m+b*n),n)=im1(m,n);
end
end
figure,imshow(uint8(G));

%图像的垂直错切
G=zeros(row,col);
a=pi/6; %水平错切30度
b=tan(a);
for m=1:row
for n=1:col
G(n,round(m+b*n))=im1(m,n);
end
end
figure,imshow(uint8(G));

 

 

  

转载于:https://www.cnblogs.com/Qsir/p/5644757.html