您的位置:首页 > 移动开发

DELPHI 图片任意角旋转。 我看着书上的C++代码改的,加了点自己的理解。huruihappy

2009-07-07 22:44 525 查看
//==============================================================================
//图片旋转
//输入参数
//    srcImg : TBitmap 源图
//    angle : extended 旋转角度
//输出参数
//   result : TBitmap ; 旋转后的图
//作者:胡睿 CSDN: huruihappy. 欢迎访问www.googler.cc 更多惊喜
//QQ : 235483710
//Email : 235483710@qq.com
//代码仅限交流
//==============================================================================
function TForm1.ImageRotate(srcImg1: TBitmap; angle: extended): TBitmap;
var
radius, n: integer;
alpha: extended;
DestBmp : TBitmap ;
fRotateAngle : extended ; //弧度
fsrcX1,fsrcX2,fsrcX3,fsrcX4, fsrcY1,fsrcY2,fsrcY3,fsrcY4 : Extended ; //原图4个定点坐标
fDestX1,fDestX2,fDestX3,fDestX4, fDestY1,fDestY2,fDestY3,fDestY4 : Extended ; //目标图4个顶点坐标
fSina,fCosa : Extended ; //旋转角的正弦和余弦值
f1,f2 : Extended ; //常数
coX,coY : Extended ; //输出图像在输入图像中待插值的坐标,必须为浮点
Iu,Iv,i,j,k,t1,t2 : Integer ;

begin

//作者:胡睿 CSDN: huruihappy. 欢迎访问www.googler.cc 更多惊喜
//QQ : 235483710
//Email : 235483710@qq.com
//代码仅限交流
DestBmp := TBitmap.Create ;

//将角度转化为弧度
fRotateAngle := Pi * angle / 180 ;

//计算旋转角的正弦
fSina := Sin(fRotateAngle) ;

//计算旋转角的余弦
fCosa := Cos(fRotateAngle) ;

//计算原图4点坐标,以图像中心为坐标原点
fSrcX1 := -( srcImg1.Width - 1 ) / 2 ;
fSrcY1 := (srcImg1.Height - 1) / 2 ;
fSrcX2 := ( srcImg1.Width - 1 ) / 2 ;
fSrcY2 := (srcImg1.Height - 1) / 2 ;
fSrcX3 := -( srcImg1.Width - 1 ) / 2 ;
fSrcY3 := -(srcImg1.Height - 1) / 2 ;
fSrcX4 := ( srcImg1.Width - 1 ) / 2 ;
fSrcY4 := -(srcImg1.Height - 1) / 2 ;

//计算新图4个角坐标,以图像中心为坐标原点
fDestX1 :=  fCosa * fSrcX1 + fSina * fSrcY1 ;
fDestY1 := -fSina * fSrcX1 + fCosa * fSrcY1 ;
fDestX2 :=  fCosa * fSrcX2 + fSina * fSrcY2 ;
fDestY2 := -fSina * fSrcX2 + fCosa * fSrcY2 ;
fDestX3 :=  fCosa * fSrcX3 + fSina * fSrcY3 ;
fDestY3 := -fSina * fSrcX3 + fCosa * fSrcY3 ;
fDestX4 :=  fCosa * fSrcX4 + fSina * fSrcY4 ;
fDestY4 := -fSina * fSrcX4 + fCosa * fSrcY4 ;

//输出后图像宽度和高度
DestBmp.Width := Round( Max( Abs(fDestX4 - fDestX1) , Abs(fDestX3 - fDestX2) ) + 0.5 ) ;
DestBmp.Height := Round( Max( Abs(fDestY4 - fDestY1) , Abs(fDestY3 - fDestY2) ) + 0.5 ) ;

//计算常数
f1 := -0.5 * (DestBmp.Width - 1) * fCosa + 0.5 * (DestBmp.Height - 1) * fSina + 0.5 * (DestBmp.Width - 1) ;
f2 := -0.5 * (DestBmp.Width - 1) * fSina - 0.5 * (DestBmp.Height - 1) * fCosa + 0.5 * (DestBmp.Height - 1) ;

//----------------------------------------------------------------------------
//开始旋转
//双线性插值抗锯齿,更好效果可以使用立体卷积(速度奇慢)
for i := 0 to DestBmp.Height - 1 do
for j := 0 to DestBmp.Width - 1 do
begin

//输出J,I 映射到原图像坐标
coX := j * fCosa - i * fSina + f1 ;
coY := j * fSina + i * fCosa + f2 ;

//坐标取整
Iu := Round(coX) ;
Iv := Round(coY) ;

//判断是否在原图范围内
if ( coX  >= 0 ) and ( coX < srcImg1.Width - 1 ) and
( coY >= 0 ) and ( coY < srcImg1.Height - 1 ) then
begin

if ( Iv >= 1 ) and ( Iv <= srcImg1.Height - 1 ) and
( Iu >= 1 ) and ( Iu <= srcImg1.Width - 1 ) then
begin

//abcd=(ab+cd) / 2=(A+B+C+D) / 4
//ab= A + (B-A) / 2
//cd=C +(D-C) / 2

//双线性插值
DestBmp.Canvas.Pixels[j,i] := RGB(
( GetRValue( srcImg1.Canvas.Pixels[Iu-1,Iv-1] ) + GetRValue( srcImg1.Canvas.Pixels[Iu+1,Iv-1] )
+ GetRValue( srcImg1.Canvas.Pixels[Iu-1,Iv+1] ) + GetRValue( srcImg1.Canvas.Pixels[Iu+1,Iv+1] ) ) div 4 ,

( GetGValue( srcImg1.Canvas.Pixels[Iu-1,Iv-1] ) + GetGValue( srcImg1.Canvas.Pixels[Iu+1,Iv-1] )
+ GetGValue( srcImg1.Canvas.Pixels[Iu-1,Iv+1] ) + GetGValue( srcImg1.Canvas.Pixels[Iu+1,Iv+1] ) ) div 4 ,

( GetBValue( srcImg1.Canvas.Pixels[Iu-1,Iv-1] ) + GetBValue( srcImg1.Canvas.Pixels[Iu+1,Iv-1] )
+ GetBValue( srcImg1.Canvas.Pixels[Iu-1,Iv+1] ) + GetBValue( srcImg1.Canvas.Pixels[Iu+1,Iv+1] ) ) div 4
) ;

end
else
begin
//错误点也设置为白色,可替换成背景色
DestBmp.Canvas.Pixels[j,i] := RGB(255,255,255);
end ;

end
else
begin
//不在原图范围内,则设置为白点
DestBmp.Canvas.Pixels[j,i] := RGB(255,255,255);
end ;

application.processmessages ;

end ;

Result := DestBmp  ;

end;


DELPHI 图片任意角旋转。

我看着书上的C++代码改的,加了点自己的理解。

如果用SCANLINE的话, 速度会提高很多。要用的朋友自己改下吧。

//测试用

Img_Src.Picture.Assign( ImageRotate(Img_Src.Picture.Bitmap , -3 ) ) ;
Img_Src.Picture.SaveToFile('c:/1.bmp');
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: