Anti-aliasing para LineTo

Delphi

10/05/2004

Olá!
Alguem tem alguma função que traceja um LineTo em um canvas com Anti-aliasing (sem rebarba)?

Obrigado!


Nildo

Nildo

Curtidas 0

Respostas

Cebikyn

Cebikyn

10/05/2004

[b:57810accca]Depois[/b:57810accca] do LineTo e qualquer outro método que vc for usar, vc pode usar esta função (que irá colocar anti-aliasing em tudo que já estiver no Image):

procedure Antialiasing(Image: TImage; Percent: Integer);
type
  TRGBTripleArray = array[0..32767] of TRGBTriple;
  PRGBTripleArray = ^TRGBTripleArray;
var
  SL, SL2: PRGBTripleArray;
  l, m, p: Integer;
  R, G, B: TColor;
  R1, R2, G1, G2, B1, B2: Byte;
begin
  with Image.Canvas do
  begin
    Brush.Style  := bsClear;
    Pixels[1, 1] := Pixels[1, 1];
    for l := 0 to Image.Height - 1 do
    begin
      SL := Image.Picture.Bitmap.ScanLine[l];
      for p := 1 to Image.Width - 1 do
      begin
        R1 := SL[p].rgbtRed;
        G1 := SL[p].rgbtGreen;
        B1 := SL[p].rgbtBlue;

        // Left
        if (p < 1) then m := Image.Width
        else
          m := p - 1;
        R2 := SL[m].rgbtRed;
        G2 := SL[m].rgbtGreen;
        B2 := SL[m].rgbtBlue;
        if (R1 <> R2) or (G1 <> G2) or (B1 <> B2) then
        begin
          R := Round(R1 + (R2 - R1) * 50 / (Percent + 50));
          G := Round(G1 + (G2 - G1) * 50 / (Percent + 50));
          B := Round(B1 + (B2 - B1) * 50 / (Percent + 50));
          SL[m].rgbtRed := R;
          SL[m].rgbtGreen := G;
          SL[m].rgbtBlue := B;
        end;

        //Right
        if (p > Image.Width - 2) then m := 0
        else
          m := p + 1;
        R2 := SL[m].rgbtRed;
        G2 := SL[m].rgbtGreen;
        B2 := SL[m].rgbtBlue;
        if (R1 <> R2) or (G1 <> G2) or (B1 <> B2) then
        begin
          R := Round(R1 + (R2 - R1) * 50 / (Percent + 50));
          G := Round(G1 + (G2 - G1) * 50 / (Percent + 50));
          B := Round(B1 + (B2 - B1) * 50 / (Percent + 50));
          SL[m].rgbtRed := R;
          SL[m].rgbtGreen := G;
          SL[m].rgbtBlue := B;
        end;

        if (l < 1) then m := Image.Height - 1
        else
          m := l - 1;
        //Over
        SL2 := Image.Picture.Bitmap.ScanLine[m];
        R2  := SL2[p].rgbtRed;
        G2  := SL2[p].rgbtGreen;
        B2  := SL2[p].rgbtBlue;
        if (R1 <> R2) or (G1 <> G2) or (B1 <> B2) then
        begin
          R := Round(R1 + (R2 - R1) * 50 / (Percent + 50));
          G := Round(G1 + (G2 - G1) * 50 / (Percent + 50));
          B := Round(B1 + (B2 - B1) * 50 / (Percent + 50));
          SL2[p].rgbtRed := R;
          SL2[p].rgbtGreen := G;
          SL2[p].rgbtBlue := B;
        end;

        if (l > Image.Height - 2) then m := 0
        else
          m := l + 1;
        //Under
        SL2 := Image.Picture.Bitmap.ScanLine[m];
        R2  := SL2[p].rgbtRed;
        G2  := SL2[p].rgbtGreen;
        B2  := SL2[p].rgbtBlue;
        if (R1 <> R2) or (G1 <> G2) or (B1 <> B2) then
        begin
          R := Round(R1 + (R2 - R1) * 50 / (Percent + 50));
          G := Round(G1 + (G2 - G1) * 50 / (Percent + 50));
          B := Round(B1 + (B2 - B1) * 50 / (Percent + 50));
          SL2[p].rgbtRed := R;
          SL2[p].rgbtGreen := G;
          SL2[p].rgbtBlue := B;
        end;
      end;
    end;
  end;
end;


Em que Percent é quanto de anti-aliasing vc quer.


GOSTEI 0
Nildo

Nildo

10/05/2004

Obrigado Cebikyn, mas...
Do canvas inteiro somente esta linha pode ficar anti-aliasinged. É um grafico que eu estou fazendo em um canvas, de velocidade atingida, e só somente estas linhas devem ficar com anti-aliasign. Será que nao tem como?


GOSTEI 0
Cebikyn

Cebikyn

10/05/2004

Se for viável:

Faz a(s) linha(s) -> antialiazing -> faz o resto do gráfico

Se não for:

Desenha a linha pixel a pixel (usando um for-to-do c/ a equação da reta que pode ser obtida facilmente a partir dos pontos que seriam passados pro LineTo), combinando os pixels ao redor do pixel principal com o fundo (vai demorar bem mais, mas vai funcionar).


GOSTEI 0
Nildo

Nildo

10/05/2004

Bom vou fazer esta função e posto aqui quando acabar.

[quote:10f0733ed3=´C:>´]combinando os pixels ao redor do pixel principal com o fundo[/quote:10f0733ed3]

Qual seria o algoritmo para fazer esta combinação, com 50¬ de agregação? Digo... se o Fundo eh Branco, e a linha eh Preta, este pixel deveria ficar Cinza (50¬ branca e 50¬ preta). Qual seria o algoritmo para isso?


GOSTEI 0
Marcelo Saviski

Marcelo Saviski

10/05/2004

De uma olhada nisso aqui, http://www.swissdelphicenter.ch/en/showcode.php?id=1812
achei esse site num dos tópicos do cebikyn


GOSTEI 0
Fórum Vini

Fórum Vini

10/05/2004

Ae nildo, foi mal pela demora...
Eu procurei lah em casa mas ainda naum achei.. mas pelo que vi ela naum vai resolver o seu problema, pois funciona da mesma forma que a do cebikyn..
Qual seria o algoritmo para fazer esta combinação, com 50¬ de agregação? Digo... se o Fundo eh Branco, e a linha eh Preta, este pixel deveria ficar Cinza (50¬ branca e 50¬ preta). Qual seria o algoritmo para isso?

No algoritmo que eu tenho, a imagem eh ampliada três vezes(com StretchDraw mesmo..) e depois ele tirava a média das cores de cada pixel...(isso eh o que eu lembro, mas faz mais coisas tbm..)


T+,
Vinicius;


GOSTEI 0
Nildo

Nildo

10/05/2004

Firmeza Vini nao se preocupa não! Isso é só implementação, não necessidade aqui!

Mesmo assim obrigado mesmo!


GOSTEI 0
Nildo

Nildo

10/05/2004

[quote:1df62fe198=´Marcelo Saviski´]De uma olhada nisso aqui, http://www.swissdelphicenter.ch/en/showcode.php?id=1812
achei esse site num dos tópicos do cebikyn[/quote:1df62fe198]
Valew marcelo, parece que é exatamente o que eu quero!
Mas parece que nao funcionou...

Eu chamo da seguinte maneira:

WuLine( Image1.Picture.Bitmap, Point( 10, 10 ), Point( 100, 100 ), clRed );

Só que ele apaga todo meu bitmap...


GOSTEI 0
Nildo

Nildo

10/05/2004

Alias, nao apaga nao. Se eu traco qualquer reta na diagonal ele nao funciona


GOSTEI 0
Marcelo Saviski

Marcelo Saviski

10/05/2004

bom,vamos por partes

Garante que você seta um tamanho para o bitmap antes?
[color=green:bdd3b12767]Image.Picture.Bitmap.Width := X;
Image.Picture.Bitmap.Heught := Y;[/color:bdd3b12767]


GOSTEI 0
Marcelo Saviski

Marcelo Saviski

10/05/2004

Alias, nao apaga nao. Se eu traco qualquer reta na diagonal ele nao funciona


Deve ter a ver com essa parte:

  deltax := abs(x2 - x1);  
  deltay := abs(y2 - y1); 
  if (deltax = 0) or (deltay = 0) then begin // straight lines 
    ABitmap.Canvas.Pen.Color := AColor; 
    ABitmap.Canvas.MoveTo(x1, y1); 
    ABitmap.Canvas.LineTo(x2, y2); 
    exit; 
  end; 


Talvez o seu pen.Style esteja em algo diferente....


GOSTEI 0
Nildo

Nildo

10/05/2004

[quote:ecaa483da1=´Marcelo Saviski´]Garante que você seta um tamanho para o bitmap antes?
[color=green:ecaa483da1]Image.Picture.Bitmap.Width := X;
Image.Picture.Bitmap.Heught := Y;[/color:ecaa483da1][/quote:ecaa483da1]

Eu já carrego um bitmap dentro dele. Isso já auto-atribue estas propriedades


GOSTEI 0
Beppe

Beppe

10/05/2004

Uma pergunta boba?

Tem certeza de que é um bitmap, não um jpeg?


GOSTEI 0
Nildo

Nildo

10/05/2004

Quando a imagem sumia, era um JPG :oops: Mas o fato de nao traçar era realmente um BMP. Mas eu achei uma função que faz isso, e então eu adaptei pro meu componente que herda de um TQrImage.

procedure TQrGrafico.LineTo2(x, y: Single);

  function CrossFadeColor(FromColor, ToColor: TColor; Rate: Single): TColor;
  var
    r, g, b: byte;
  begin
    r := Round(GetRValue(FromColor) * Rate + GetRValue(ToColor) * (1 - Rate));
    g := Round(GetGValue(FromColor) * Rate + GetGValue(ToColor) * (1 - Rate));
    b := Round(GetBValue(FromColor) * Rate + GetBValue(ToColor) * (1 - Rate));
    Result := RGB(r, g, b);
  end;
  procedure hpixel(x: single; y: integer);
  var
    FadeRate: single;
  begin
    FadeRate := x - trunc(x);
    with canvas do
    begin
      pixels[trunc(x), y] := CrossFadeColor(Canvas.Pen.Color, Pixels[Trunc(x), y], 1 - FadeRate);
      pixels[trunc(x) + 1, y] := CrossFadeColor(Canvas.Pen.Color, Pixels[Trunc(x) + 1, y],
        FadeRate);
    end;
  end;

  procedure vpixel(x: integer; y: single);
  var
    FadeRate: single;
  begin
    FadeRate := y - trunc(y);
    with canvas do
    begin
      pixels[x, trunc(y)] := CrossFadeColor(Canvas.Pen.Color, Pixels[x, Trunc(y)], 1 - FadeRate);
      pixels[x, trunc(y) + 1] := CrossFadeColor(Canvas.Pen.Color, Pixels[x, Trunc(y) + 1],
        FadeRate);
    end;
  end;

var
  i: integer;
  ly, lx, currentx, currenty, deltax, deltay, l, skipl: single;
  x1,x2,y1,y2: Single;
begin
  x1 := canvas.PenPos.X;
  x2 := X;
  y1 := canvas.PenPos.Y;
  y2 := Y;

  if (x1 <> x2) or (y1 <> y2) then
  begin
    currentx := x1;
    currenty := y1;
    lx := abs(x2 - x1);
    ly := abs(y2 - y1);

    if lx > ly then
    begin
      l := trunc(lx);
      deltay := (y2 - y1) / l;
      if x1 > x2 then
      begin
        deltax := -1;
        skipl := (currentx - trunc(currentx));
      end
      else
      begin
        deltax := 1;
        skipl := 1 - (currentx - trunc(currentx));
      end;
    end
    else
    begin
      l := trunc(ly);
      deltax := (x2 - x1) / l;
      if y1 > y2 then
      begin
        deltay := -1;
        skipl := (currenty - trunc(currenty));
      end
      else
      begin
        deltay := 1;
        skipl := 1 - (currenty - trunc(currenty));
      end;
    end;

    currentx := currentx + deltax * skipl;
    currenty := currenty + deltay * skipl; {}

    for i := 1 to trunc(l) do
    begin
      if lx > ly then
        vpixel(trunc(currentx), currenty)
      else
        hpixel(currentx, trunc(currenty));
      currentx := currentx + deltax;
      currenty := currenty + deltay;
    end;
  end;
end;



GOSTEI 0
Beppe

Beppe

10/05/2004

Como está de velocidade? Não se se ficou lento pra ti, mas pode ser bem melhor...eu tb tinha escrito uma função q calculava pontos de reta, usando doubles(ao menos, use Double´s, são mais rápidos q Single´s). Achei uma implementação q portei para Delphi, sem comparação, bem melhor...Mas nem é necessário tanto, a função LineDDA da GDI faz isto, e tão eficiente quato a q portei. É só passar um callback pra ela, chamada para cada ponto da reta. Mas veja se não vai complicar sua implementação, pois vc vai ter q remover o código q esta inline na função de calcula, pode ser meio chato...só faça isso se quiser mais eficiência...


GOSTEI 0
Nildo

Nildo

10/05/2004

Valew Beppe, mas processamento não é problema aqui. As máquinas que usam o sistema normalmente são máquinas foderosas. E eu também não posso te afirmar a velocidade, pois aqui no trampo estou com um P4 2.8ghz e 512 de ram. Então o processo é imediato, isso que eu traço mais de 5 mil retas com esta função e o resultado é imediato


GOSTEI 0
Beppe

Beppe

10/05/2004

Valew Beppe, mas processamento não é problema aqui. As máquinas que usam o sistema normalmente são máquinas foderosas. E eu também não posso te afirmar a velocidade, pois aqui no trampo estou com um P4 2.8ghz e 512 de ram. Então o processo é imediato, isso que eu traço mais de 5 mil retas com esta função e o resultado é imediato

hehe, cuidado pra naum se acostumar com esses PCzinhos aí...


GOSTEI 0
Nildo

Nildo

10/05/2004

hehe, cuidado pra naum se acostumar com esses PCzinhos aí...


Hehe O pior é que eu dá mó raiva porque o P3 850 lá de casa ja ta mó lerdo. E olha que nem é, mas eu jah me acostumei com esses daqui, esse foi o problema :cry:


GOSTEI 0
Marcelo Saviski

Marcelo Saviski

10/05/2004

(ao menos, use Double´s, são mais rápidos q Single´s)


Doubles são mais rápidos? mais eles não são maiores? ou não tem nada a ver?


GOSTEI 0
Nildo

Nildo

10/05/2004

Quando se usa linhas duplas, o afastamento em pixels de uma rebarba até uma distancia X é menor do que o afastamento de uma linha dupla. O processamento mesmo é gerar as cores Alpha para colocar nas rebarbas. Eu não consigo me expressar muito bem, mas é mais ou menos assim que funciona


GOSTEI 0
Beppe

Beppe

10/05/2004

[quote:7993b16e02=´Marcelo Saviski´]
(ao menos, use Double´s, são mais rápidos q Single´s)


Doubles são mais rápidos? mais eles não são maiores? ou não tem nada a ver?[/quote:7993b16e02]
Senhor, sim, sim, sim!(by GVT)

Single: 4 bytes
Double: 8 bytes
Extended: 10 bytes

O Double é o mais rápido(na verdade, menos lento) dos três, segundo meus testes. Extended é o maior e um pouco mais lento que Double, embora seja do formato nativo da máquina. Por formato nativo, digo o tamanho de um registrador de ponto flutuante, ST(r). Eu poderia até explicar pq Single é mais lento ainda(conversão para Double, opera sobre, e converte de volta), mas nada sobre Extended. Eu nunca precisei usar pf em assembly, por isto não sei certo, mas vou checar isto.


GOSTEI 0
Marcelo Saviski

Marcelo Saviski

10/05/2004

Eu sempre usei Singles porque achava que eles eram mais ´ligth´, interessante isso :)


GOSTEI 0
POSTAR