广告
淘宝内部优惠券
当前位置: 开发异常方案库» Delphi » 图片旋转90度用什么方法比较快?

图片旋转90度用什么方法比较快?

开发异常方案库  收集整理于:2020-04-28 19:01:00  浏览:66次
图片是jpg格式,我需要加载到TBitmap对象,并旋转90度,不改变原图。 利用TBitmap的Canvas的Pixels[x][y]来旋转图片速度很慢。

------网友观点--------------------
https://bbs.csdn.net/topics/390897521

------网友观点--------------------
引用 1 楼 tanqth 的回复:
https://bbs.csdn.net/topics/390897521
他这个代码也是用的Pixels[x][y]逐个像素转。

------网友观点--------------------
openvc

------网友观点--------------------
uses jpeg;
function RotateJPG90(AJPG:TJPEGImage):TBitmap;
var
  bmp:TBitmap;
  p,pBuf:PChar;
  w,h,y,x,LineSize,nOfs:Integer;
begin
  bmp:=TBitmap.Create;
  bmp.PixelFormat:=pf24bit;
  bmp.Assign(AJPG);
  w:=bmp.Width;
  h:=bmp.Height;
  LineSize:=w*3;
  GetMem(pBuf,LineSize*h);
  try
    for y:=0 to bmp.Height-1 do
    begin
      p:=bmp.ScanLine[y];
      for x:=0 to bmp.Width-1 do
      begin
        nOfs:=((x+1)*h-y-1)*3;
        Move(p^,pBuf[nOfs],3);
        Inc(p,3);
      end;
    end;
    bmp.Width:=h;
    bmp.Height:=w;
    LineSize:=h*3;
    for y:=0 to bmp.Height-1 do
    begin
      nOfs:=y*LineSize;
      Move(pBuf[nOfs],bmp.scanline[y]^,LineSize);
    end;
    result:=bmp;
  finally
    FreeMem(pBuf);
  end;
end;

------网友观点--------------------
FMX组件都支持旋转、缩放,一行就完成了,VCL的话,因为是粘在windows上的,可以直接用PlgBlt

------网友观点--------------------
引用 4 楼 wdonghai 的回复:
uses jpeg;
function RotateJPG90(AJPG:TJPEGImage):TBitmap;
var
  bmp:TBitmap;
  p,pBuf:PChar;
  w,h,y,x,LineSize,nOfs:Integer;
begin
  bmp:=TBitmap.Create;
  bmp.PixelFormat:=pf24bit;
  bmp.Assign(AJPG);
  w:=bmp.Width;
  h:=bmp.Height;
  LineSize:=w*3;
  GetMem(pBuf,LineSize*h);
  try
    for y:=0 to bmp.Height-1 do
    begin
      p:=bmp.ScanLine[y];
      for x:=0 to bmp.Width-1 do
      begin
        nOfs:=((x+1)*h-y-1)*3;
        Move(p^,pBuf[nOfs],3);
        Inc(p,3);
      end;
    end;
    bmp.Width:=h;
    bmp.Height:=w;
    LineSize:=h*3;
    for y:=0 to bmp.Height-1 do
    begin
      nOfs:=y*LineSize;
      Move(pBuf[nOfs],bmp.scanline[y]^,LineSize);
    end;
    result:=bmp;
  finally
    FreeMem(pBuf);
  end;
end;
你这个代码有点看不太懂,在同一个bmp内变换ScanLine?

------网友观点--------------------
引用 5 楼 早打大打打核战争 的回复:
FMX组件都支持旋转、缩放,一行就完成了,VCL的话,因为是粘在windows上的,可以直接用PlgBlt
组件旋转可能没用,因为我最后要把TBitmap图像写到文件,需要旋转图像。 PlgBlt是啥? 帮我看看这个:https://bbs.csdn.net/topics/396082353

------网友观点--------------------
引用 7 楼 ooolinux 的回复:
Quote: 引用 5 楼 早打大打打核战争 的回复:
FMX组件都支持旋转、缩放,一行就完成了,VCL的话,因为是粘在windows上的,可以直接用PlgBlt
组件旋转可能没用,因为我最后要把TBitmap图像写到文件,需要旋转图像。 PlgBlt是啥? 帮我看看这个:https://bbs.csdn.net/topics/396082353
PlgBlt貌似是任意角度旋转,这样旋转出来怕影响清晰度(像素混合计算)?不知道速度怎么样。 手机相册里面图片旋转速度很快,是因为硬件DSP芯片功能吗?

------网友观点--------------------
FMX应用可以直接TBitmap.Rotate;(FMX的TBitmap可以加载多种格式,不是只限于windows位图),VCL应用可以直接用API PlgBlt,这个方法最简单,而且可以做到任意角度的旋转,代码量最少,或者用GDI+也可以,代码量略多

------网友观点--------------------
引用 9 楼 早打大打打核战争 的回复:
FMX应用可以直接TBitmap.Rotate;(FMX的TBitmap可以加载多种格式,不是只限于windows位图),VCL应用可以直接用API PlgBlt,这个方法最简单,而且可以做到任意角度的旋转,代码量最少,或者用GDI+也可以,代码量略多
FMX的TBitmap.Rotate和WinAPI PlgBlt都是任意角度旋转,这样旋转出来怕影响清晰度(像素混合计算)?不知道速度怎么样。 手机相册里面图片旋转速度很快,是因为硬件DSP芯片功能吗?

------网友观点--------------------
引用 3 楼 tanqth 的回复:
openvc
OpenCV的话有点大了。

------网友观点--------------------
FMX的旋转、缩放是基于硬件加速的,视觉效果很好,不会出现模糊、锯齿的情况。PlgBlt的内部实现不清楚,但是实测效果也还可以。速度都没有问题。

------网友观点--------------------
引用 12 楼 早打大打打核战争 的回复:
FMX的旋转、缩放是基于硬件加速的,视觉效果很好,不会出现模糊、锯齿的情况。PlgBlt的内部实现不清楚,但是实测效果也还可以。速度都没有问题。
如果对90度、180度、270度这三种角度的旋转以及上下、左右翻转有单独的算法就好了,像素能够精确。

------网友观点--------------------
可以给TBitmap写个Helper,补上一些方法来实现,我有空研究一下

------网友观点--------------------
openCV就可以了呀。如果是图像太大 可以先缩放 再旋转 再回复原来分辨率。如果担心图像经过缩放后变模糊了  可以通过拉普拉斯金字塔重建高分辨率图像 就得到旋转过后的清晰图像了。

------网友观点--------------------
引用 16 楼 早打大打打核战争 的回复:
可以给TBitmap写个Helper,补上一些方法来实现,我有空研究一下
ok。我那个旋转慢了点尚且可以接受,小程序不怎么打算再整了。

------网友观点--------------------
引用 17 楼 哦吼? 的回复:
openCV就可以了呀。如果是图像太大 可以先缩放 再旋转 再回复原来分辨率。如果担心图像经过缩放后变模糊了  可以通过拉普拉斯金字塔重建高分辨率图像 就得到旋转过后的清晰图像了。
这个厉害了,假如给你10块钱,能否拉普拉斯变成100块,买100块钱的东西回来?

------网友观点--------------------
引用 16 楼 早打大打打核战争 的回复:
可以给TBitmap写个Helper,补上一些方法来实现,我有空研究一下
不过如果研究出来也是很有用的。

------网友观点--------------------
引用 19 楼 ooolinux的回复:
Quote: 引用 17 楼 哦吼? 的回复:
openCV就可以了呀。如果是图像太大 可以先缩放 再旋转 再回复原来分辨率。如果担心图像经过缩放后变模糊了  可以通过拉普拉斯金字塔重建高分辨率图像 就得到旋转过后的清晰图像了。
这个厉害了,假如给你10块钱,能否拉普拉斯变成100块,买100块钱的东西回来?
。。这两回事。。 我的意思是将原来的高清的图像建立拉普拉斯金字塔将它的细节保存起来,然后将图像缩小后旋转,然后通过低分辨率图像加上保存的细节部分放大到原尺寸,这样就可以减少细节损失。如果你对细节无要求,那直接缩小旋转后再放大到原尺寸就可以。如果你的图像本来就是正常尺寸,那直接用openCV的API去旋转就可以。

------网友观点--------------------
引用 19 楼 ooolinux的回复:
Quote: 引用 17 楼 哦吼? 的回复:
openCV就可以了呀。如果是图像太大 可以先缩放 再旋转 再回复原来分辨率。如果担心图像经过缩放后变模糊了  可以通过拉普拉斯金字塔重建高分辨率图像 就得到旋转过后的清晰图像了。
这个厉害了,假如给你10块钱,能否拉普拉斯变成100块,买100块钱的东西回来?
什么叫10块钱变100块钱。。。。直接去把10x10的图像放大到100x100就要进行插值,插值后细节就和原来的图像不一致了。但是它的分辨率实实在在是变大了。

------网友观点--------------------
uses jpeg;
 
function RotateJPG90(AJPG:TJPEGImage):TBitmap;//顺时针90
var
  bmp:TBitmap;
  p,pBuf:PChar;
  w,h,y,x,LineSize,nOfs:Integer;
begin
  bmp:=TBitmap.Create;
  bmp.PixelFormat:=pf24bit;
  bmp.Assign(AJPG);
  w:=bmp.Width;
  h:=bmp.Height;
  LineSize:=w*3;
  GetMem(pBuf,LineSize*h);
  try
    for y:=0 to bmp.Height-1 do
    begin
      p:=bmp.ScanLine[y];
      for x:=0 to bmp.Width-1 do
      begin
        nOfs:=(x*h+h-y-1)*3;
        Move(p^,pBuf[nOfs],3);
        Inc(p,3);
      end;
    end;
    bmp.Width:=h;
    bmp.Height:=w;
    LineSize:=h*3;
    for y:=0 to bmp.Height-1 do
    begin
      nOfs:=y*LineSize;
      Move(pBuf[nOfs],bmp.scanline[y]^,LineSize);
    end;
    result:=bmp;
  finally
    FreeMem(pBuf);
  end;
end;
function RotateJPG270(AJPG:TJPEGImage):TBitmap;//顺时针270
var
  bmp:TBitmap;
  p,pBuf:PChar;
  w,h,y,x,LineSize,nOfs:Integer;
begin
  bmp:=TBitmap.Create;
  bmp.PixelFormat:=pf24bit;
  bmp.Assign(AJPG);
  w:=bmp.Width;
  h:=bmp.Height;
  LineSize:=w*3;
  GetMem(pBuf,LineSize*h);
  try
    for y:=0 to bmp.Height-1 do
    begin
      p:=bmp.ScanLine[h-y-1];
      for x:= bmp.Width-1 downto 0 do
      begin
        nOfs:=(x*h+h-y-1)*3;
        Move(p^,pBuf[nOfs],3);
        Inc(p,3);
      end;
    end;
    bmp.Width:=h;
    bmp.Height:=w;
    LineSize:=h*3;
    for y:=0 to bmp.Height-1 do
    begin
      nOfs:=y*LineSize;
      Move(pBuf[nOfs],bmp.scanline[y]^,LineSize);
    end;
    result:=bmp;
  finally
    FreeMem(pBuf);
  end;
end;
function RotateJPG180(AJPG:TJPEGImage):TBitmap;//顺时针180
var
  bmp:TBitmap;
  p1,p2:PChar;
  h,y,x:Integer;
begin
  bmp:=TBitmap.Create;
  try
    bmp.PixelFormat:=pf24bit;
    bmp.Assign(AJPG);
    result:=TBitmap.Create;
    Result.PixelFormat:=pf24bit;
    Result.Width:=bmp.Width;
    Result.Height:=bmp.Height;
    h:=bmp.Height;
    for y:=0 to bmp.Height-1 do
    begin
      p1:=result.ScanLine[y];
      p2:=PChar(Integer(bmp.ScanLine[h-1-y])+bmp.Width*3);
      for x:=0 to bmp.Width-1 do
      begin
        Move(p2^,p1^,3);
        inc(p1,3);
        Dec(p2,3);
      end;
    end;
  finally
    bmp.Free;
  end;
end;
function FlipVertical(AJPG:TJPEGImage):TBitmap;//水平镜像
var
  bmp:TBitmap;
  p1,p2:PChar;
  h,y,LineSize:Integer;
begin
  bmp:=TBitmap.Create;
  try
    bmp.PixelFormat:=pf24bit;
    bmp.Assign(AJPG);
    Result:=TBitmap.Create;
    Result.PixelFormat:=pf24bit;
    Result.Width:=bmp.Width;
    Result.Height:=bmp.Height;
    LineSize:=bmp.Width*3;
    h:=bmp.Height;
    for y:=0 to bmp.Height-1 do
    begin
      p1:=result.ScanLine[y];
      p2:=bmp.ScanLine[h-1-y];
      Move(p2^,p1^,LineSize);
    end;
  finally
    bmp.Free;
  end;
end;
function FlipHorizontal(AJPG:TJPEGImage):TBitmap;//垂直镜像
var
  bmp:TBitmap;
  p1,p2:PChar;
  y,x:Integer;
begin
  bmp:=TBitmap.Create;
  try
    bmp.PixelFormat:=pf24bit;
    bmp.Assign(AJPG);
    Result:=TBitmap.Create;
    Result.PixelFormat:=pf24bit;
    Result.Width:=bmp.Width;
    Result.Height:=bmp.Height;
    for y:=0 to bmp.Height-1 do
    begin
      p1:=result.ScanLine[y];
      p2:=PChar(Integer(bmp.ScanLine[y])+bmp.Width*3);
      for x:=0 to bmp.Width-1 do
      begin
        Move(p2^,p1^,3);
        inc(p1,3);
        Dec(p2,3);
      end;
    end;
  finally
    bmp.Free;
  end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
  jpg:TJPEGImage;
  bmp:TBitmap;
begin
  bmp:=nil;
  jpg:=TJPEGImage.Create;
  try
    jpg.LoadFromFile('c:\1.jpg');
    bmp:=RotateJPG90(jpg);//顺时针90
//    bmp:=RotateJPG180(jpg);//顺时针180
//    bmp:=RotateJPG270(jpg);//顺时针270
//    bmp:=FlipHorizontal(jpg);//垂直镜像
//    bmp:=FlipVertical(jpg);//水平镜像
    Image1.Picture.Assign(bmp);
  finally
    bmp.Free;
    jpg.Free;
  end;
end;

------网友观点--------------------
引用 23 楼 wdonghai 的回复:
uses jpeg;
代码看不是很懂,你这个是在同一个bmp内挪动scanline的RGB数据吗? 不知道每一行的scanline是不是就是精确的RGB RGB RGB……这样三个字节的重复,不多(末尾)也不少?

------网友观点--------------------
windows bitmap的每行数据对齐到4字节边界,所以每行末尾可能有填充

------网友观点--------------------
引用 25 楼 早打大打打核战争 的回复:
windows bitmap的每行数据对齐到4字节边界,所以每行末尾可能有填充
如果旋转90度,把scanline数据从行变换为列,这个增加了一点复杂性。 帮我看看这个:https://bbs.csdn.net/topics/396123023

------网友观点--------------------
见这帖:https://bbs.csdn.net/topics/396124599

------网友观点--------------------
我是把图像数据取出,放到线程里旋转

------网友观点--------------------
引用 28 楼 m0_46901103的回复:
我是把图像数据取出,放到线程里旋转
同时旋转多个图对应用多个线程才有用。
发布此文章仅为传递网友分享,不代表本站观点,若侵权请联系我们删除,本站将不对此承担任何责任。
软件开发 程序错误 异常 ybaby.netCopyright © 2020-2026  ybaby 版权所有  桂ICP备17004385号-2 网站地图