会员: 密码:  免费注册 | 忘记密码 | 会员登录 网页功能: 加入收藏 设为首页 网站搜索  
技术文档 > Delphi
基本图象处理代码(1)
发表日期:2003-03-07 00:00:00作者:e 出处:  

[图像的旋转和翻转]

以下代码用ScanLine配合指针移动实现,用于24位色,至于其它色深的处理和有些代码为什么要这样写的问题可查看我的另一篇文章!

//旋转90度

procedure Rotate90(const Bitmap:TBitmap);

var

 i,j:Integer;

 rowIn,rowOut:pRGBTriple;

 Bmp:TBitmap;

 Width,Height:Integer;

begin

 Bmp:=TBitmap.Create;

 Bmp.Width := Bitmap.Height;

 Bmp.Height := Bitmap.Width;

 Bmp.PixelFormat := pf24bit;

 Width:=Bitmap.Width-1;

 Height:=Bitmap.Height-1;

 for j := 0 to Height do

 begin

  rowIn := Bitmap.ScanLine[j];

  for i := 0 to Width do

  begin

   rowOut := Bmp.ScanLine[i];

   Inc(rowOut,Height - j);

   rowOut^ := rowIn^;

   Inc(rowIn);

  end;

 end;

 Bitmap.Assign(Bmp);

end;

//旋转180度

procedure Rotate180(const Bitmap:TBitmap);

var

 i,j:Integer;

 rowIn,rowOut:pRGBTriple;

 Bmp:TBitmap;

 Width,Height:Integer;

begin

 Bmp:=TBitmap.Create;

 Bmp.Width := Bitmap.Width;

 Bmp.Height := Bitmap.Height;

 Bmp.PixelFormat := pf24bit;

 Width:=Bitmap.Width-1;

 Height:=Bitmap.Height-1;

 for j := 0 to Height do

 begin

  rowIn := Bitmap.ScanLine[j];

  for i := 0 to Width do

  begin

   rowOut := Bmp.ScanLine[Height - j];

   Inc(rowOut,Width - i);

   rowOut^ := rowIn^;

   Inc(rowIn);

  end;

 end;

 Bitmap.Assign(Bmp);

end;

//旋转270度

procedure Rotate270(const Bitmap:TBitmap);

var

 i,j:Integer;

 rowIn,rowOut:pRGBTriple;

 Bmp:TBitmap;

 Width,Height:Integer;

begin

 Bmp:=TBitmap.Create;

 Bmp.Width := Bitmap.Height;

 Bmp.Height := Bitmap.Width;

 Bmp.PixelFormat := pf24bit;

 Width:=Bitmap.Width-1;

 Height:=Bitmap.Height-1;

 for j := 0 to Height do

 begin

  rowIn := Bitmap.ScanLine[j];

  for i := 0 to Width do

  begin

   rowOut := Bmp.ScanLine[Width - i];

   Inc(rowOut,j);

   rowOut^ := rowIn^;

   Inc(rowIn);

  end;

 end;

 Bitmap.Assign(Bmp);

end;

任意角度旋转就是将原图上的像素映射到新图上,以下代码为了好理解,并未进行充分优化!但速度上已经比较快了!我的另一篇文章中对优化问题进行了些简单说明,也就是尽量少用浮点运算!

前面为判断部分,如果是90,180,270这类特殊角度,将调用上面的代码,这样效率更高!

//任意角度

function RotateBitmap(Bitmap:TBitmap;Angle:Integer;BackColor:TColor):TBitmap;

var

 i,j,iOriginal,jOriginal,CosPoint,SinPoint : integer;

 RowOriginal,RowRotated : pRGBTriple;

 SinTheta,CosTheta : Extended;

 AngleAdd : integer;

begin

 Result:=TBitmap.Create;

 Result.PixelFormat := pf24bit;

 Result.Canvas.Brush.Color:=BackColor;

 Angle:=Angle Mod 360;

 if Angle<0 then Angle:=360-Abs(Angle);

 if Angle=0 then

  Result.Assign(Bitmap)

 else if Angle=90 then

 begin

  Result.Assign(Bitmap);

  Rotate90(Result);//如果是旋转90度,直接调用上面的代码

 end

 else if (Angle>90) and (Angle<180) then

 begin

  AngleAdd:=90;

  Angle:=Angle-AngleAdd;

 end

 else if Angle=180 then

 begin

  Result.Assign(Bitmap);

  Rotate180(Result);//如果是旋转180度,直接调用上面的过程

 end

 else if (Angle>180) and (Angle<270) then

 begin

  AngleAdd:=180;

  Angle:=Angle-AngleAdd;

 end

 else if Angle=270 then

 begin

  Result.Assign(Bitmap);

  Rotate270(Result);//如果是旋转270度,直接调用上面的过程

 end

 else if (Angle>270) and (Angle<360) then

 begin

  AngleAdd:=270;

  Angle:=Angle-AngleAdd;

 end

 else

  AngleAdd:=0;

 if (Angle>0) and (Angle<90) then

 begin

 SinCos((Angle + AngleAdd) * Pi / 180, SinTheta, CosTheta);

 if (SinTheta * CosTheta) < 0 then

 begin

  Result.Width := Round(Abs(Bitmap.Width * CosTheta - Bitmap.Height * SinTheta));

  Result.Height := Round(Abs(Bitmap.Width * SinTheta - Bitmap.Height * CosTheta));

 end

 else

 begin

  Result.Width := Round(Abs(Bitmap.Width * CosTheta + Bitmap.Height * SinTheta));

  Result.Height := Round(Abs(Bitmap.Width * SinTheta + Bitmap.Height * CosTheta));

 end;

 CosTheta:=Abs(CosTheta);

 SinTheta:=Abs(SinTheta);

 if (AngleAdd=0) or (AngleAdd=180) then

 begin

  CosPoint:=Round(Bitmap.Height*CosTheta);

  SinPoint:=Round(Bitmap.Height*SinTheta);

 end

 else

 begin

  SinPoint:=Round(Bitmap.Width*CosTheta);

  CosPoint:=Round(Bitmap.Width*SinTheta);

 end;

 for j := 0 to Result.Height-1 do

 begin

  RowRotated := Result.Scanline[j];

  for i := 0 to Result.Width-1 do

  begin

   Case AngleAdd of

    0:

    begin

     jOriginal := Round((j+1)*CosTheta-(i+1-SinPoint)*SinTheta)-1;

     iOriginal := Round((i+1)*CosTheta-(CosPoint-j-1)*SinTheta)-1;

    end;

    90:

    begin

     iOriginal := Round((j+1)*SinTheta-(i+1-SinPoint)*CosTheta)-1;

     jOriginal := Bitmap.Height-Round((i+1)*SinTheta-(CosPoint-j-1)*CosTheta);

    end;

    180:

    begin

     jOriginal := Bitmap.Height-Round((j+1)*CosTheta-(i+1-SinPoint)*SinTheta);

     iOriginal := Bitmap.Width-Round((i+1)*CosTheta-(CosPoint-j-1)*SinTheta);

    end;

    270:

    begin

     iOriginal := Bitmap.Width-Round((j+1)*SinTheta-(i+1-SinPoint)*CosTheta);

     jOriginal := Round((i+1)*SinTheta-(CosPoint-j-1)*CosTheta)-1;

    end;

   end;

   if (iOriginal >= 0) and (iOriginal <= Bitmap.Width-1)and

     (jOriginal >= 0) and (jOriginal <= Bitmap.Height-1)

   then

   begin

    RowOriginal := Bitmap.Scanline[jOriginal];

    Inc(RowOriginal,iOriginal);

    RowRotated^ := RowOriginal^;

    Inc(RowRotated);

   end

   else

   begin

    Inc(RowRotated);

   end;

  end;

 end;

 end;

end;

虽然这已经实现了图像任意角度的旋转,但注意看看上面的代码,都是用Round取整,也就是在原图中找最近的像素填充到新图中,这样在边缘会产生锯齿!如果想效果更好,应该是用四个像素的值运算后得到新像素的值!

如对应到原图的坐标是(6.3,8.6),用第一种方法可能就用(6,9)填充了该像素,但如果想消除边缘锯齿,就应该用(6,8)、(6,9)、(7,8)、(7,9)运算得出新点的像素,而边缘就用颜色等于背景色的点代替!

感兴趣的朋友可以找些二次线性插值资料看看,或者以后再讨论,这里就不多说了!

后面的浮雕滤镜效果其实就用到了线性插值的思想!

//水平翻转

procedure FlipHorz(const Bitmap:TBitmap);

var

 i,j:Integer;

 rowIn,rowOut:pRGBTriple;

 Bmp:TBitmap;

 Width,Height:Integer;

begin

 Bmp:=TBitmap.Create;

 Bmp.Width := Bitmap.Width;

 Bmp.Height := Bitmap.Height;

 Bmp.PixelFormat := pf24bit;

 Width:=Bitmap.Width-1;

 Height:=Bitmap.Height-1;

 for j := 0 to Height do

 begin

  rowIn := Bitmap.ScanLine[j];

  for i := 0 to Width do

  begin

   rowOut := Bmp.ScanLine[j];

   Inc(rowOut,Width - i);

   rowOut^ := rowIn^;

   Inc(rowIn);

  end;

 end;

 Bitmap.Assign(Bmp);

end;

//垂直翻转

procedure FlipVert(const Bitmap:TBitmap);

var

 i,j:Integer;

 rowIn,rowOut:pRGBTriple;

 Bmp:TBitmap;

 Width,Height:Integer;

begin

 Bmp:=TBitmap.Create;

 Bmp.Width := Bitmap.Height;

 Bmp.Height := Bitmap.Width;

 Bmp.PixelFormat := pf24bit;

 Width:=Bitmap.Width-1;

 Height:=Bitmap.Height-1;

 for j := 0 to Height do

 begin

  rowIn := Bitmap.ScanLine[j];

  for i := 0 to Width do

  begin

   rowOut := Bmp.ScanLine[Height - j];

   Inc(rowOut,i);

   rowOut^ := rowIn^;

   Inc(rowIn);

  end;

 end;

 Bitmap.Assign(Bmp);

end;

其实旋转90、180、270度,水平垂直翻转的原理基本类似,所以也可以改写为一个过程!

如果灵活的使用指针,减少用ScanLine的次数,代码效率还能有所提升~~~

返回顶部】 【打印本页】 【关闭窗口

关于我们 / 给我留言 / 版权举报 / 意见建议 / 网站编程QQ群   
Copyright ©2003- 2024 Lihuasoft.net webmaster(at)lihuasoft.net 加载时间 0.00403