Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2006.12.03;
Скачать: [xml.tar.bz2];

Вниз

Масштабирование изображений(квадрат -> трапеция)   Найти похожие ветки 

 
zirus   (2006-10-18 15:47) [0]

Вот есть изображение, квадратное. Надо преобразовать это изображение в другое, с новыми коодрдинатами углов. То есть преобразование квадрата в трапецию. И даже с возможным поворотом. Как?..


 
Jeer ©   (2006-10-18 16:19) [1]

Честно говоря, все начинается и заканчивается на Sin и Cos + сложение/умножение.
Можно, конечно, употребить термин "афинные преобразования", но зачем ?


 
Сергей М. ©   (2006-10-18 16:30) [2]


> есть изображение, квадратное


ой..

галиматьища редкостная) ...


> преобразование квадрата в трапецию


достаточно изменить (произвольным образом) координаты одной из вершин "квадрата"


 
Jeer ©   (2006-10-18 16:34) [3]

Сергей М. ©   (18.10.06 16:30) [2]

17579482

Зашел бы.:)


 
zirus   (2006-10-18 16:37) [4]

Начал думать над задачей, вопрос упирается в масштибирование линий.

То есть разлиновываем исходное изображение, линии масштабируем(такие цветные линии получаются) и рисуем под нужными угалами в результирующее изображение. Надо бы ещё смасштабировать линию правильно, чтобы где-то 1 пиксел не преобразовался в два, или наоборот не исчез.

С синусами. Задача: узнать полярные координать новой точки (r,фи). Ага? С чего начать думать?

Может применим термин "афинные преобразования"? :-) (э-эх, не учил я вышку!)


 
Сергей М. ©   (2006-10-18 16:46) [5]


> Jeer ©   (18.10.06 16:34) [3]


Как-нибудь зайду, Серега...
Сей секунд, увы, не обещаю.


 
zirus   (2006-10-18 17:09) [6]

Думы в сторону полярных коодринат:
 Результирующий 4-угольник. Для каждой точки внутри его проводим вектор (угол 4-угольника - точка внутри 4-угольника). Найти угол на исходном изображении не составляет труда, составляем пропорцию.
Как найти длину вектора при переносе его на исходное изображение?


 
Pavia ©   (2006-10-18 19:23) [7]


> Думы в сторону полярных коодринат:

Отставить полярные координаты. Тебе же не нужно делать закручивоние.
Первое расчитать координаты точек контура четырех угольника для пространственных координат, и для текстурных координат. Для текстурных координат пременяем теже самы преобразования котоые применили для координатных, а они нам заданы. После сканирующим методом строим четырех угольник. Для красоты применяем фильрацию: билинейную, триленейную, или др.


 
Pavia ©   (2006-10-18 21:38) [8]

Я уже сделал, правда код не оптимизировал. Сейчас ошибочки отлавливаю.  Исходник выложит?


 
Pavia ©   (2006-10-18 23:15) [9]

Вообщем вот исходник.
Что можно, нужно сделать:
заменить Bp.Canvas.Pixels на BP.ScanLine, там же добавить фильтрацию.

unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, ExtCtrls;

type
 TForm1 = class(TForm)
   Image1: TImage;
   procedure FormCreate(Sender: TObject);
   procedure Image1MouseDown(Sender: TObject; Button: TMouseButton;
     Shift: TShiftState; X, Y: Integer);
   procedure Image1MouseUp(Sender: TObject; Button: TMouseButton;
     Shift: TShiftState; X, Y: Integer);
   procedure Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
     Y: Integer);
   procedure FormDestroy(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

var
 Form1: TForm1;
const
R=10;
type
 TVector=record X,Y,U,V:Double end;
 PVector=^TVector;

 TRect=array [0..3]of TVector;
var
 a:TRect;
 b:array of array [0..1] of TVector;
 p:PVector;
 BP:TBitmap;

implementation

{$R *.dfm}

procedure DrawEdge(p1,p2:PVector);
var
Temp:PVector;
side,y:Integer;
x,uslope,vslope,xslope:Double;
begin
side:=0;
xslope:=0;
if p2.y-p1.y<>0 then
begin
xslope:=(p2.x-p1.x)/(p2.y-p1.y);
vslope:=(p2.v-p1.v)/(p2.y-p1.y);
uslope:=(p2.u-p1.u)/(p2.y-p1.y);
end;
if (p1.y >= p2.y) then
 begin
 side:=1;
 temp:=p1;
 p1:=p2;
 p2:=temp;
 end;
new(Temp);
temp^:=p1^;
for y:=Trunc(p1.y) to Trunc(p2.y) do
 begin
 b[y][side]:=Temp^;
 temp.x:=temp.x+xslope;
 temp.u:=temp.u+uslope;
 temp.v:=temp.v+vslope;
 end;
Dispose(Temp);
end;

procedure DrawImage;
var i,j,MaxY,MinY:Integer;
uslope,vslope,u,v:Double;
t:Int64;
p:PByteArray;
begin
t:=GetTickCount;
DrawEdge(@a[0],@a[1]);
DrawEdge(@a[1],@a[2]);
DrawEdge(@a[2],@a[3]);
DrawEdge(@a[3],@a[0]);

MaxY:=Trunc(a[0].y);
MinY:=Trunc(a[0].y);
for i:=1 to 3 do
begin
if MaxY<Trunc(a[i].Y) then MaxY:=Trunc(a[i].Y);
if MinY>Trunc(a[i].Y) then MinY:=Trunc(a[i].Y);
end;

for i:=MinY to MaxY do
begin

u:=b[i][1].u;
v:=b[i][1].v;
if b[i][0].x-b[i][1].x<>0 then
 begin
 vslope:=(b[i][0].v-b[i][1].v)/(b[i][0].x-b[i][1].x);
 uslope:=(b[i][0].u-b[i][1].u)/(b[i][0].x-b[i][1].x);
 end;
p:=Form1.Image1.Picture.Bitmap.ScanLine[i];
for j:=Trunc(b[i][1].x) to Trunc(b[i][0].x) do
 begin
{  Form1.Image1.Canvas.Pixels[j,i]:=Bp.Canvas.Pixels[Trunc(u),Trunc(v)];}
 p[j*3+2]:=Bp.Canvas.Pixels[Trunc(u),Trunc(v)];
 p[j*3+1]:=Bp.Canvas.Pixels[Trunc(u),Trunc(v)] shr 8;
 p[j*3+0]:=Bp.Canvas.Pixels[Trunc(u),Trunc(v)] shr 16;
 u:=u+uslope;
 v:=v+vslope;
 end;
end;
Form1.Caption:=IntToStr(GetTickCount-t);
end;

function Vector(X,Y,U,V:Double):TVector;
begin
result.X:=X;
result.Y:=Y;
result.U:=U;
result.V:=V;
end;

procedure TForm1.FormCreate(Sender: TObject);
var i:Integer;
begin
DoubleBuffered:=True;
Bp:=TBitmap.Create;
Bp.LoadFromFile("f:\фоне.bmp");
image1.Picture.Bitmap.PixelFormat:=pf24Bit;
image1.Picture.Bitmap.width:=800;
image1.Picture.Bitmap.height:=600;
SetLength(b,Image1.Height);

with BP do
 begin
 a[0]:=Vector(0,0,0,0);
 a[1]:=Vector(Width-1,0,Width-1,0);
 a[2]:=Vector(Width-1,Height-1,Width-1,Height-1);
 a[3]:=Vector(0,Height-1,0,Height-1);
 end;
DrawImage;
With Image1.Canvas do
 begin
 Pen.Color:=clBlack;
 Pen.Mode:=pmNotXor;
 Pen.Style:=psSolid;
 Brush.Style:=bsClear;
 Pen.Width:=3;
 Ellipse(Trunc(a[0].X-R),Trunc(a[0].Y-R),Trunc(a[0].X+R),Trunc(a[0].Y+R));
 for i:=1 to 3 do
  Ellipse(Trunc(a[I].X-R),Trunc(a[I].Y-R),Trunc(a[I].X+R),Trunc(a[I].Y+R));
 end;
end;

procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
 Shift: TShiftState; X, Y: Integer);
var i:Integer;
begin
With Image1.Canvas do
 begin
 MoveTo(Trunc(a[0].X),Trunc(a[0].Y));
 for i:=1 to 3 do
  LineTo(Trunc(a[i].X),Trunc(a[i].Y));
 LineTo(Trunc(a[0].X),Trunc(a[0].Y));
 end;
for i:= 0 to 3 do
if Sqr(X-a[i].X)+Sqr(Y-a[i].Y)<Sqr(R) then
 begin
 p:=@a[i];
 end;
end;

procedure TForm1.Image1MouseUp(Sender: TObject; Button: TMouseButton;
 Shift: TShiftState; X, Y: Integer);
var i:Integer;
begin
p:=Nil;
With Image1.Canvas do
 begin
 MoveTo(Trunc(a[0].X),Trunc(a[0].Y));
 for i:=1 to 3 do
  LineTo(Trunc(a[i].X),Trunc(a[i].Y));
 LineTo(Trunc(a[0].X),Trunc(a[0].Y));

 Pen.Color:=clWhite;
 Pen.Mode:=pmCopy;
 Pen.Style:=psSolid;
 Brush.Style:=bsSolid;
 Brush.Color:=clWhite;
 Pen.Width:=3;
 Rectangle(0,0,Width,Height);
 Pen.Color:=clBlack;
 Pen.Mode:=pmNotXor;
 Pen.Style:=psSolid;
 Brush.Style:=bsClear;
 Pen.Width:=3;
 DrawImage;
 Ellipse(Trunc(a[0].X-R),Trunc(a[0].Y-R),Trunc(a[0].X+R),Trunc(a[0].Y+R));
 for i:=1 to 3 do
  Ellipse(Trunc(a[I].X-R),Trunc(a[I].Y-R),Trunc(a[I].X+R),Trunc(a[I].Y+R));
end;
end;

procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
 Y: Integer);
var i:Integer;
begin
If X<0 then x:=0;
If y<0 then y:=0;
If X>=Image1.Width then x:=Image1.Width-1;
If y>=Image1.Height then y:=Image1.Height-1;

if p<> nil then
begin
With Image1.Canvas do
 begin
 MoveTo(Trunc(a[0].X),Trunc(a[0].Y));
 for i:=1 to 3 do
  LineTo(Trunc(a[i].X),Trunc(a[i].Y));
 LineTo(Trunc(a[0].X),Trunc(a[0].Y));
 Ellipse(Trunc(a[0].X-R),Trunc(a[0].Y-R),Trunc(a[0].X+R),Trunc(a[0].Y+R));
 for i:=1 to 3 do
  Ellipse(Trunc(a[I].X-R),Trunc(a[I].Y-R),Trunc(a[I].X+R),Trunc(a[I].Y+R));
 end;
p.X:=x;
p.Y:=y;
With Image1.Canvas do
 begin
 MoveTo(Trunc(a[0].X),Trunc(a[0].Y));
 for i:=1 to 3 do
  LineTo(Trunc(a[i].X),Trunc(a[i].Y));
 LineTo(Trunc(a[0].X),Trunc(a[0].Y));
 Ellipse(Trunc(a[0].X-R),Trunc(a[0].Y-R),Trunc(a[0].X+R),Trunc(a[0].Y+R));
 for i:=1 to 3 do
  Ellipse(Trunc(a[I].X-R),Trunc(a[I].Y-R),Trunc(a[I].X+R),Trunc(a[I].Y+R));
 end;
end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
bp.Destroy;
end;

end.


 
zirus   (2006-10-19 15:27) [10]

оооойййй...Спасибки за программулину.
Но ненавистные поинтеры!.. чегой-то не работают, ругается дельфи(6й) кругом. В основном, обращения к поинтерам не нравятся.

аццесс виолэйшн, например тут:
b[y][side]:=Temp^;
Ok, сделал setlength для b

DrawImage
p[j*3+2]:=Bp.Canvas.Pixels[Trunc(u),Trunc(v)];
тож ругается, даже и не знаю что противопоставить ему.

Весь день рисовал геометрию, продолжаю пока что, разбираться в чужих неработающих поинтерах... страшный сон :-) Я хочу понять принцип.


 
Сергей М. ©   (2006-10-19 15:56) [11]


> хочу понять принцип


Он чрезвычайно сложен.
Даже не пытайся)

Лучше определись таки с терминами "квадратное изображение", "преобразование изображения в другое" ...


 
Romkin ©   (2006-10-19 15:58) [12]

Основных принципов здесь несколько:
Во-первых, идти надо не от исходного изображения, а от результата, то есть, берем точку результата и ищем ее цвет в исходном изображении.
Во-вторых, есть точки привязки: углы. Следовательно, прямые, их соединяющие, переходят в прямые. Остальные точки между ними - пропорционально.
В-третьих, при таком преобразовании в общем случае нельзя четко сопоставить точку одного изображения точке в другом. Просто потому, что их разное количество :) Поэтому цвет точки результата определяется по разным алгоритмам, простейший - брать цвет ближайшей точки исходного изображения (естественно, с учетом преобразования). Более сложный - брать среднее по области ближайших точек.


 
zirus   (2006-10-19 15:58) [13]

вай-вай, какая красота :-)
mea culpa, Oncreate забыл
Ну я попал... pointer-ы придётся изучать всё таки


 
zirus   (2006-10-19 16:03) [14]

> Romkin Огромное спасибо, ещё раз. Про прямые из углов 4-угольника я не додумался, на моём рисунке чего-то сложное выходит. Будет хоть пища для размышлений.


 
Pavia ©   (2006-10-19 17:28) [15]

У меня Delphi 7 и он позволяет опускать ^.
procedure DrawEdge(p1,p2:PVector);
var
Temp:PVector;
Temp1:TVector;
side,y:Integer;
x,uslope,vslope,xslope:Double;
begin
side:=0;
xslope:=0;
if p2^.y-p1^.y<>0 then
begin
xslope:=(p2^.x-p1^.x)/(p2^.y-p1^.y);
vslope:=(p2^.v-p1^.v)/(p2^.y-p1^.y);
uslope:=(p2^.u-p1^.u)/(p2^.y-p1^.y);
end;
if (p1^.y >= p2^.y) then
 begin
 side:=1;
 temp:=p1;
 p1:=p2;
 p2:=temp;
 end;
temp1:=p1^;
for y:=Trunc(p1^.y) to Trunc(p2^.y) do
 begin
 b[y][side]:=Temp1;
 temp1.x:=temp1.x+xslope;
 temp1.u:=temp1.u+uslope;
 temp1.v:=temp1.v+vslope;
 end;
end;

В DrawImage
 p^[j*3+2]:=Bp.Canvas.Pixels[Trunc(u),Trunc(v)];
 p^[j*3+1]:=Bp.Canvas.Pixels[Trunc(u),Trunc(v)] shr 8;
 p^[j*3+0]:=Bp.Canvas.Pixels[Trunc(u),Trunc(v)] shr 16;
В Image1MouseMove
p^.X:=x;
p^.Y:=y;

Про построение изображения. Romkin уже все сказал. Добавлю что не мы сначала делаем преобразование четырех точек вершин треугольника. Далее от этих точек идет перерасчет всех остальных. Но задача эта разбивается на две это расчет граничных точек DrawEdge, и затем имея две граничные точки на одной линии b[y][0] и b[y][1] заполняем все пространство между этими двумя точками. Надеюсь расчет точек понятен, если же нет можешь найти в Интернете алгоритм построения линии, или почитать про линейное интерполирование.  И также посмотреть алгоритм построение треугольника.
У меня в алгоритме программа выбирает точку, просто беря ближайшею точку. Но как уже говорили можно брать 2*2 точки для расчета цвета Билинейная интерполяция. Или 3*3 Трилинейная. Есть и другие фильтры.


 
Gero ©   (2006-10-19 22:24) [16]

> [11] Сергей М. ©   (19.10.06 15:56)

А чем тебя смущает термин «квадратное изображение»? Не можешь представить картинку с равными шириной и высотой?


 
Sapersky   (2006-10-20 14:15) [17]

В graphics32 вроде было такое масштабирование.

"Билинейная интерполяция" означает не 2*2, а "в двух направлениях" - по ширине и по высоте.
Трилинейная в 3D графике = билинейная + интерполяция между мип-уровнями, т.е. копиями картинки (текстуры) разного масштаба. Подобный подход (даже не трилинейку, просто "мип-мэппинг") можно применять и в 2D, если планируется сильное, в несколько раз, уменьшение картинки по сравнению с оригиналом - должно уменьшить кол-во артефактов.

Кстати, можно задейстовать и 3D-ускоритель, хотя если раньше этим не занимался - вряд ли будет проще, чем программная реализация.


 
guav ©   (2006-10-20 16:30) [18]

SetWorldTransform ?



Страницы: 1 вся ветка

Форум: "Основная";
Текущий архив: 2006.12.03;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.52 MB
Время: 0.045 c
15-1163311268
Сало
2006-11-12 09:01
2006.12.03
Кличко! Кличко!


2-1163416043
TrainerOfDolphins
2006-11-13 14:07
2006.12.03
Отмена действия


4-1153425976
Батыр
2006-07-21 00:06
2006.12.03
Как узнать цвет заданной точки экранна


2-1163243363
lsvit
2006-11-11 14:09
2006.12.03
TList


15-1163397237
Cerberus
2006-11-13 08:53
2006.12.03
Сайты с заказами на разработку интернет сайтов.





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский