PDA

View Full Version : سوال: RotateImage



peymanjon
یک شنبه 19 خرداد 1392, 11:14 صبح
سلام..
من می خواهم یک عکس که در Timage لود کرده ام را 90 درجه (ساعتگرد و پاد ساعتگرد بچرخانم).
کد های زیادی را امتحان کردم بعضی ها مثل کد زیر دقیق انجام می دهد ولی زمان زیادی صرف این کار می کند:

function TFrmImageViewer.RotateBitmap(
DstB, SrcB : TBitmap;
AngleDeg : Single;
RotCentX : Single = 0;
RotCentY : Single = 0;
OffsetX : Integer = 0;
OffsetY : Integer = 0;
ScaleX : Single = 1.0;
ScaleY : Single = 1.0):Boolean;
const PI_DIV_180 = 0.01745329251994329576923690768489;
var
p : array[0..2] of TPoint;
cos_, sin_, x, y : Extended;
begin
if ((DstB = nil) or (SrcB = nil)) then
begin
Result := False;
Exit;
end;
SinCos(-AngleDeg * PI_DIV_180, sin_, cos_);
(*
rotation 2D
x = x` cos - y` sin
y = x` sin + y` cos
*)
x := ScaleX * -RotCentX;
y := ScaleY * -RotCentY;
p[0] := Point( Trunc(cos_ * x - sin_ * y + RotCentX) + OffsetX,
Trunc(sin_ * x + cos_ * y + RotCentY) + OffsetY);
x := ScaleX * (SrcB.Width - RotCentX);
y := ScaleY * -RotCentY;
p[1] := Point( Trunc(cos_ * x - sin_ * y + RotCentX) + OffsetX,
Trunc(sin_ * x + cos_ * y + RotCentY) + OffsetY);
x := ScaleX * -RotCentX;
y := ScaleY * (SrcB.Height - RotCentY);
p[2] := Point( Trunc(cos_ * x - sin_ * y + RotCentX) + OffsetX,
Trunc(sin_ * x + cos_ * y + RotCentY) + OffsetY);
Result := PlgBlt(
DstB.Canvas.Handle,
p,
SrcB.Canvas.Handle,
0, 0, SrcB.Width, SrcB.Height,
0, 0, 0);
end;
بعضی کدها موجود نیز وقتی استفاده می کنم بعد از چند بار چرخش حاشیه عکس من کمی از بین می رود و عکس کوچکتر می شود.
خلاصه کسی از دوستان کدی داره که بصورت صحیح و سرعت بالا بتونم عکس را بچرخونم؟ (دارم با دلفی7 کار می کنم)

peymanjon
یک شنبه 19 خرداد 1392, 13:28 عصر
من این و پیدا کردم که خوب جواب داد اگه کسی کد بهتر داره لطفاً کمک کنه.

procedure SZRotateBmp90(Src, Dest: TBitmap);
var
x, y : integer;
dY : array of PDWORD; // Array for destination scanline
sH, dH: integer; // Height variables
P : PDWORD; // Source pointer
begin
if Src.PixelFormat<>pf32bit then
Src.PixelFormat := pf32bit;
if Dest.PixelFormat<>pf32bit then
Dest.PixelFormat := pf32bit;
try
Dest.Width := Src.Height;
Dest.Height := Src.Width;
sH:=Src.Height-1;
dH:=Dest.Height-1;
// Initialize dynamic array
SetLength(DY,dH+1);
// Save pointers to array for acceleration
for y := 0 to dH do
DY[y] := Dest.ScanLine[y];
// Copy Src horizontal lines to be Dest vertical by +90 degree
for y := 0 to sH do
begin
P:=Src.ScanLine[y];
for x := dH downto 0 do
begin
Dy[x]^:=P^;
inc(Dy[x]);
inc(P);
end;
end;
finally
SetLength(DY,0);
end;
end;
procedure SZRotateBmp270(Src, Dest: TBitmap);
var
x, y : integer;
dY : array of PDWORD; // Array for destination scanline
sH, dH: integer; // Height variables
P : PDWORD; // Source pixel pointer
begin
if Src.PixelFormat<>pf32bit then
Src.PixelFormat := pf32bit;
if Dest.PixelFormat<>pf32bit then
Dest.PixelFormat := pf32bit;
try
Dest.Width := Src.Height;
Dest.Height := Src.Width;
sH:=Src.Height-1;
dH:=Dest.Height-1;
// Initialize dynamic array
SetLength(DY,dH+1);
// Save pointers to array for acceleration
for y := 0 to dH do
DY[y] := Dest.ScanLine[y];
// Copy Src horizontal lines to be Dest vertical by +270 degree
for y := sh downto 0 do
begin
P:=Src.ScanLine[y];
for x := 0 to dH do
begin
Dy[x]^:=P^;
inc(Dy[x]);
inc(P);
end;
end;
finally
SetLength(DY,0);
end;
end;

یوسف زالی
یک شنبه 19 خرداد 1392, 13:41 عصر
سلام.
استفاده از ScanLine تقریبا سریع ترین نتیجه رو داره. اما یک کمی درکش رو مشکل می کنه.
الان در چی این کد مشکل دارید؟

peymanjon
یک شنبه 19 خرداد 1392, 16:14 عصر
من سریعترین الگوریتم برای rotate عکس را در timage می خواهم در روش اولی که گذاشتم یک عکس سنگین حدود 10 تا 12 ثانیه طول می کشید تا rotate شود ولی کد دومی زمان به 2 تا 4 ثانیه کم شد که سریعتر از اولی می باشد و برای من بهتر بود، آیا شما کدی یا روشی می توانید معرفی کنید که rotate را با سرعت بیشتری انجام دهد بدون اینکه سایز عکس تغییر کند؟

یوسف زالی
یک شنبه 19 خرداد 1392, 18:40 عصر
سرعت بیشتر بله. اما اگر سایز عکس 100 در 200 باشه بعدش می شه 200 در 100 و این یعنی تغییر سایز عکس. بدون تغییر یعنی چی؟

Ananas
دوشنبه 20 خرداد 1392, 01:45 صبح
سلام..
من می خواهم یک عکس که در Timage لود کرده ام را 90 درجه (ساعتگرد و پاد ساعتگرد بچرخانم).
کد های زیادی را امتحان کردم بعضی ها مثل کد زیر دقیق انجام می دهد ولی زمان زیادی صرف این کار می کند:

function TFrmImageViewer.RotateBitmap(
DstB, SrcB : TBitmap;
AngleDeg : Single;
RotCentX : Single = 0;
RotCentY : Single = 0;
OffsetX : Integer = 0;
OffsetY : Integer = 0;
ScaleX : Single = 1.0;
ScaleY : Single = 1.0):Boolean;
const PI_DIV_180 = 0.01745329251994329576923690768489;
var
p : array[0..2] of TPoint;
cos_, sin_, x, y : Extended;
begin
if ((DstB = nil) or (SrcB = nil)) then
begin
Result := False;
Exit;
end;
SinCos(-AngleDeg * PI_DIV_180, sin_, cos_);
(*
rotation 2D
x = x` cos - y` sin
y = x` sin + y` cos
*)
x := ScaleX * -RotCentX;
y := ScaleY * -RotCentY;
p[0] := Point( Trunc(cos_ * x - sin_ * y + RotCentX) + OffsetX,
Trunc(sin_ * x + cos_ * y + RotCentY) + OffsetY);
x := ScaleX * (SrcB.Width - RotCentX);
y := ScaleY * -RotCentY;
p[1] := Point( Trunc(cos_ * x - sin_ * y + RotCentX) + OffsetX,
Trunc(sin_ * x + cos_ * y + RotCentY) + OffsetY);
x := ScaleX * -RotCentX;
y := ScaleY * (SrcB.Height - RotCentY);
p[2] := Point( Trunc(cos_ * x - sin_ * y + RotCentX) + OffsetX,
Trunc(sin_ * x + cos_ * y + RotCentY) + OffsetY);
Result := PlgBlt(
DstB.Canvas.Handle,
p,
SrcB.Canvas.Handle,
0, 0, SrcB.Width, SrcB.Height,
0, 0, 0);
end;
بعضی کدها موجود نیز وقتی استفاده می کنم بعد از چند بار چرخش حاشیه عکس من کمی از بین می رود و عکس کوچکتر می شود.
خلاصه کسی از دوستان کدی داره که بصورت صحیح و سرعت بالا بتونم عکس را بچرخونم؟ (دارم با دلفی7 کار می کنم)
سلام. قیافه ی کد که میگه بنده نوشتمش.:متفکر: تابع PlgBlt سخت افزاری کار میکنه و شاید سخت افزار شما برای تصاویر بزرگ درست پشتیبانی نمیکنه.

peymanjon
دوشنبه 20 خرداد 1392, 08:42 صبح
بله این دقیقاً کد شماست و من از آن استفاده کردم و به خوبی جواب گرفتم ولی برای عکس با کیفیت و حجم بالا کمی کند است (10 تا 15 ثانیه)

شاید سخت افزار شما برای تصاویر بزرگ درست پشتیبانی نمیکنه.
اتفاقاً تصاویر اکثراً اسکن اسناد A4 میباشد ولی با 200 dpi و فرمت bmp اسکن شده که حجم و کیفیت را بالا برده و rotate زمان بر می شود ، من آن ها را ابتدا به jpg تبدیل می کنم و بعد compress می کنم و در نهایت در timage نشان می دهم وبا این کار ها سرعت rotate به 10 ثانیه کاهش یافته ولی با استفاده از روش دوم که در پست 2 گذاشتم سرعت rotate به 3 تا 5ثانیه کاهش یافت که برای من مطلوب تر است !!! ایا شما روش بهینه تری (از نظر کاهش زمان rotate) برای کد خود می توانید اعمال کنید؟


سرعت بیشتر بله. اما اگر سایز عکس 100 در 200 باشه بعدش می شه 200 در 100 و این یعنی تغییر سایز عکس. بدون تغییر یعنی چی؟
در توضیح پست 1 گفتم دوست عزیزم که بعضی کدها موجود در سایت های متفاوت که تست کردم بعد از چند بار چرخش حاشیه عکس من کمی از بین می رود و عکس کوچکتر می شود.(منظورم تغییر سایز عکس در rotate نیست منظورم در چرخش عکس بخشی ار حاشیه عکسم حذف می شد و سایز کلی عکس کمتر می شد )
ممنون از وقت و تلاشتون

یوسف زالی
دوشنبه 20 خرداد 1392, 12:56 عصر
نمی خواستم این سورس رو فعلا بگذارم. اما در قالب یک تاپیک توضیح می دم.
برای یک عکس 2000 در 2000 زمان 330 میلی ثانیه خوبه؟
اینجا رو ببینید:
http://barnamenevis.org/showthread.php?402734-%D8%AF%D8%B3%D8%AA%D8%B1%D8%B3%DB%8C-%D8%A2%D8%B3%D8%A7%D9%86-%D8%A7%D9%85%D8%A7-%D8%A8%D8%B3%DB%8C%D8%A7%D8%B1-%D8%B3%D8%B1%DB%8C%D8%B9-(%DA%A9%D9%85%DB%8C-%D8%B3%D8%B1%DB%8C%D8%B9-%D8%AA%D8%B1-%D8%A7%D8%B2-ScanLine)-%D8%A8%D9%87-%D9%BE%DB%8C%DA%A9%D8%B3%D9%84-%D9%87%D8%A7%DB%8C-%DB%8C%DA%A9-%D8%A8%DB%8C%D8%AA-%D9%85%D9%BE&p=1790292#post1790292

یوسف زالی
دوشنبه 20 خرداد 1392, 13:20 عصر
سرعتتون باز هم بالاست؟
الان با این نمونه کد که داذم چقدر زمان می بره؟

Ananas
دوشنبه 20 خرداد 1392, 14:24 عصر
تصویر رو تو چند مرحله میچرخونیم قطعه قطعه مثلا با سایز 1024x1024:

function RotateBitmap(
DstB, SrcB : TBitmap;
AngleDeg : Single;
RotCentX : Single = 0;
RotCentY : Single = 0;
OffsetX : Integer = 0;
OffsetY : Integer = 0;
ScaleX : Single = 1.0;
ScaleY : Single = 1.0):Boolean;
const PI_DIV_180 = 0.01745329251994329576923690768489;
var
p : array[0..2] of TPoint;
cos_, sin_, x, y : Extended;
begin
if ((DstB = nil) or (SrcB = nil)) then
begin
Result := False;
Exit;
end;
SineCosine(-AngleDeg * PI_DIV_180, sin_, cos_);
(*
rotation 2D
x = x` cos - y` sin
y = x` sin + y` cos
*)
x := ScaleX * -RotCentX;
y := ScaleY * -RotCentY;
p[0] := Point( Trunc(cos_ * x - sin_ * y + RotCentX) + OffsetX,
Trunc(sin_ * x + cos_ * y + RotCentY) + OffsetY);
x := ScaleX * (SrcB.Width - RotCentX);
y := ScaleY * -RotCentY;
p[1] := Point( Trunc(cos_ * x - sin_ * y + RotCentX) + OffsetX,
Trunc(sin_ * x + cos_ * y + RotCentY) + OffsetY);
x := ScaleX * -RotCentX;
y := ScaleY * (SrcB.Height - RotCentY);
p[2] := Point( Trunc(cos_ * x - sin_ * y + RotCentX) + OffsetX,
Trunc(sin_ * x + cos_ * y + RotCentY) + OffsetY);
Result := PlgBlt(
DstB.Canvas.Handle,
p,
SrcB.Canvas.Handle,
0, 0, SrcB.Width, SrcB.Height,
0, 0, 0);
end;

function Rotate90BigBitmap(DstB, SrcB : TBitmap):Boolean;
const
BLOCK_SIZE = 1024;
var
i, j : Integer;
b_src, b_dst : TBitmap;
begin
j := 0;
b_src := TBitmap.Create;
b_dst := TBitmap.Create;
b_src.SetSize(BLOCK_SIZE, BLOCK_SIZE);
b_dst.SetSize(BLOCK_SIZE, BLOCK_SIZE);
while (j * BLOCK_SIZE < SrcB.Height) do
begin
i := 0;
while (i * BLOCK_SIZE < SrcB.Width) do
begin
BitBlt(b_src.Canvas.Handle, 0, 0, BLOCK_SIZE, BLOCK_SIZE, SrcB.Canvas.Handle, i * BLOCK_SIZE, j * BLOCK_SIZE, SRCCOPY);
RotateBitmap(b_dst, b_src, 90.0, 0, 0, 0, BLOCK_SIZE, 1.0, 1.0);
DstB.Canvas.Draw(j * BLOCK_SIZE, DstB.Height - (i + 1) * BLOCK_SIZE, b_dst);
Inc(i);
end;
Inc(j);
end;
b_src.Free;
b_dst.Free;
Result := True;
end;

khorsandreza
دوشنبه 20 خرداد 1392, 14:38 عصر
سرعتتون باز هم بالاست؟
الان با این نمونه کد که داذم چقدر زمان می بره؟
sسلام
من کدهائی را که گذاشته بودید بداشتم ولی هیج کاری نکرد لطفا فایل را ببینید که اشکالش کجاست؟

یوسف زالی
دوشنبه 20 خرداد 1392, 15:02 عصر
چیزی که شما دادید فقط یونیت من بود. همین. هیچ کدی که توش نزدید.
این مثال رو ببینید.