Fórum Brilho na imagem com RGB #268930

17/02/2005

0

Como fazer para intensificar as cores (dar brilho) de uma imagem que está em um componente image?
O efito que quero é semelhante ao que ocorre nos botões do outlook.
Tentei usando a função RGB, mas só em aumentar apenas uma unidade nos valores as cores já ficam muito diferentes.
Quero também o inverso. Escurecer um pouquinho a imagem.


Raserafim

Raserafim

Responder

Posts

17/02/2005

Beppe

Você terá que converter para HSV(ou seria HSB, B de Bright?), Aí é só alterar o valor e converter pra RGB de volta.


Responder

Gostei + 0

17/02/2005

Marcelo Saviski

Numa edição da revista saiu uma matéria sobre isso, naõ na última, acho que na edição 57, não tenho certeza.

Ou vc pode tentar ver nesse [url=http://forum.clubedelphi.net/viewtopic.php?t=5986&highlight=brilho+imagem]outro tópico[/url]


Responder

Gostei + 0

17/02/2005

Raserafim

Beppe, vc poderia explicar melhor como utilizar esta função? como fazer esta conversão?

Marcelo, eu já havia visto este tópico, mas não entendi o código. Não gosto de escrever uma função sem saber exatamente o q esto fazendo. Caso o código da revista seja mais simples, vc poderia colocar aqui?


Responder

Gostei + 0

17/02/2005

Beppe

Cara, até vou pesquisar melhor sobre isto. Se conseguir algo concreto(ou não, rsrsrs) eu posto.


Responder

Gostei + 0

17/02/2005

Massuda

Se você estiver usando D6 ou mais recente, dê uma olhada na função ColorAdjustLuma da unit GraphUtils. Talvez você consiga ´garimpar´ mais informações [url=http://www.efg2.com/Lab/Library/Delphi/Graphics/Color.htm]nesta página[/url].


Responder

Gostei + 0

17/02/2005

Beppe

Colega,

Como o Massuda disse vc pode usar a rotina ColorAdjustLuma, mas também existem lá as rotinas GetHighLightColor e GetShadowColor(note que elas tomam um argumento padrão), entretanto, eu chequei, elas não fazem exatamente o que o Outlook faz. Se vc quer duplicar o efeito, acho que terá que usar uma destas 3 funções com um valor baseado na luminosidade atual.

Eu também olhei a implementação, e isto me desencorajou de implementar em MMX. Como elas me parecem(não testei) lentas, considere fazer um ´cache´ das imagens, ou monte uma tabela de hash com as cores. Em GraphUtils isto é feito apenas para a última cor.

T+


Responder

Gostei + 0

17/02/2005

Beppe

Eu definitivamente não gostei em ter que decompor os canais e compor de novo, então parti para uma solução aditiva, eficiente e com um ótimo resultado.

unit Unit1;

interface

uses
  Windows, Forms, Controls, StdCtrls, Buttons, Graphics, Classes, ExtCtrls,
  SysUtils, GraphUtil;

type
  TForm1 = class(TForm)
    Image1: TImage;
    BitBtn1: TBitBtn;
    BitBtn2: TBitBtn;
    BitBtn3: TBitBtn;
    procedure FormCreate(Sender: TObject);
    procedure BitBtn1Click(Sender: TObject);
    procedure BitBtn2Click(Sender: TObject);
    procedure BitBtn3Click(Sender: TObject);
  private
    { Private declarations }
  public
    Bmp: TBitmap;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

function ColorAddChannel(C: TColor; N: Integer): TColor;
asm
    pxor        mm0, mm0
    movd        mm1, C
    movd        mm2, N
    punpcklbw   mm1, mm0
    packuswb    mm2, mm2
    packuswb    mm2, mm2

    paddusb     mm2, mm1
    packuswb    mm2, mm0

    movd        eax, mm2
    and         eax, $ffffff

    emms
end;

procedure ColorAddChannelArray32(A, B: PIntegerArray; Size, N: Integer);
asm
    pxor        mm0, mm0
    movd        mm2, N
    packuswb    mm2, mm2
    packuswb    mm2, mm2

@loop:
    movd        mm1, [A]
    punpcklbw   mm1, mm0
    paddusb     mm1, mm2
    packuswb    mm1, mm0
    movd        [B], mm1
    and         [B], $ffffff
    add         A, 4
    add         B, 4
    dec         Size
    jnz         @loop

    emms
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  A: TColor;
  X, Y: TColor;
begin
  A := clRed;
  X := ColorAddChannel(A, 30);
  ColorAddChannelArray32(@A, @Y, 1, 30);
  Caption := Format(´¬x - ¬x´, [X, Y]);

  Image1.Picture.Bitmap.PixelFormat := pf32bit;
  Bmp := TBitmap.Create;
  Bmp.Assign(Image1.Picture.Graphic);
  Image1.Picture.Assign(Bmp);
end;

procedure TForm1.BitBtn1Click(Sender: TObject);
var
  X, Y: Integer;
begin
  for X := 0 to Bmp.Width - 1 do
    for Y := 0 to Bmp.Height - 1 do
      Image1.Canvas.Pixels[X, Y] := ColorAddChannel(Bmp.Canvas.Pixels[X, Y], 90);
end;

procedure TForm1.BitBtn2Click(Sender: TObject);
var
  I: Integer;
  A, B: Pointer;
  S, F: Int64;
begin
  QueryPerformanceCounter(S);

//  A := Bmp.ScanLine[Image1.Height - 1];
//  B := Image1.Picture.Bitmap.ScanLine[Image1.Height - 1];
//  ColorAddChannelArray32(A, B, Bmp.Width * Bmp.Height, 90);

  for I := 0 to Bmp.Height - 1 do
  begin
    A := Bmp.ScanLine[I];
    B := Image1.Picture.Bitmap.ScanLine[I];
    ColorAddChannelArray32(A, B, Bmp.Width, 90);
  end;

  QueryPerformanceCounter(F);
  Caption := IntToStr(F - S);
end;

procedure TForm1.BitBtn3Click(Sender: TObject);
var
  X, Y: Integer;
begin
  for X := 0 to Bmp.Width - 1 do
    for Y := 0 to Bmp.Height - 1 do
      Image1.Canvas.Pixels[X, Y] := GetHighLightColor(Bmp.Canvas.Pixels[X, Y]);
end;

end.


Pode ver que o resultado é diferente, mas melhor, na minha opinião.


Responder

Gostei + 0

18/02/2005

Raserafim

valeu beep pela atenção e pelo trabalhão. p.... até assembler ;) valeu.

mas valeu tb massuda, era mesmo o q eu queria, algo simples. E a procedure ColorAdjustLuma caiu certinho. É só eu passar como parâmetro o pixel que quero modificar (ex: Image1.Canvas.Pixels[X, Y]), mais um parämetro que diz o brilho (coloquei 35 e -35, para clarear e escurecer respectivamente), e mais um parâmetro que não entendi pra q serve mas coloquei true.

Mas agora preciso resolver um outro problema:
Tive que criar um laço for para varrer toda imagem pegando pixel por pixel e colando em um outro image. Mas o problema é que essa varredura é muito lenta e demora um pouco para a imagem alterada aparecer.
Como faço para agilizar esse processo?


Responder

Gostei + 0

18/02/2005

Marcelo Saviski

Como faço para agilizar esse processo?

Usa a função do Beppe :) :P


Responder

Gostei + 0

18/02/2005

Beppe

valeu beep pela atenção e pelo trabalhão. p.... até assembler ;) valeu.

Trabalho algum, apenas uma oportunidade para treinar meu MMX.

e mais um parâmetro que não entendi pra q serve mas coloquei true.

O último parâmetro é ignorado pela função.

Mas agora preciso resolver um outro problema: Tive que criar um laço for para varrer toda imagem pegando pixel por pixel e colando em um outro image. Mas o problema é que essa varredura é muito lenta e demora um pouco para a imagem alterada aparecer. Como faço para agilizar esse processo?


Está sendo gentil né? ColorAdjustLuma foi umas 100x mais lenta que a minha função. O problema é que vc deve estar usando Canvas.Pixels[], que é bem lento por design. Use ScanLine, que recupera o array de pixels(lembre-se de chamar Refresh na imagem depois, eu esqueci disso no exemplo).

[quote:709c368e52=´Marcelo Saviski´]
Como faço para agilizar esse processo?

Usa a função do Beppe :) :P[/quote:709c368e52]
Eu concordo. :P Mas se ele prefere fazer do modo lento, doloroso, e mais feim, opção dele... :D

ColorAdjustLuma(60), ColorAddChannelArray32(90)
[URL=http://img67.exs.cx/my.php?loc=img67&image=high6sw.jpg][img:709c368e52]http://img67.exs.cx/img67/8725/high6sw.th.jpg[/img:709c368e52][/URL]


Responder

Gostei + 0

18/02/2005

Marcelo Saviski

esse MMX funciona em qualquer processador? ou só nos da Intel?


Responder

Gostei + 0

18/02/2005

Beppe

[quote:27a9e17db0=´Marcelo Saviski´]esse MMX funciona em qualquer processador? ou só nos da Intel?[/quote:27a9e17db0]
MMX é mais básico que tem. Mas é meu preferido, questão de utilidade e padronização.

MMX - Desde o Pentium (I) MMX. AMD também tem. Aritmética inteira.
SS2 - Desde o Pentium III. AMD também tem. Aritmética flutuante.
SS3 - Desde o Pentium 4. Aritmética inteira.
3DNOW - Apenas AMD.

Todos são SIMD(instrução única operando sobre dados múltiplos, i.e. um array)


Responder

Gostei + 0

18/02/2005

Marcelo Saviski

ha ta, vlw
quem sabe um dia ainda acordo sabendo isso...


Responder

Gostei + 0

22/02/2005

Raserafim

beppe, como posso utilizar a função ScanLine, associada com o ColorAdjustLuma?


Responder

Gostei + 0

22/02/2005

Beppe

Uma desvantagem de ScanLine é que vc precisa ter uma versão para cada formato, esta que segue é apenas para bitmaps de 32 bits.

procedure TForm1.BitBtn2Click(Sender: TObject);
var
  I: Integer;
  A, B: Pointer;
  S, F: Int64;
begin
  QueryPerformanceCounter(S);

  A := Bmp.ScanLine[Image1.Height - 1];
  B := Image1.Picture.Bitmap.ScanLine[Image1.Height - 1];

  for I := 0 to Bmp.Height * Bmp.Width - 1 do
    PIntegerArray(B)[I] := ColorAdjustLuma(PIntegerArray(A)[I], Valor);

  QueryPerformanceCounter(F);
  ShowMessage(´Demorou ´ + IntToStr(F - S) + ´ ciclos.´);
end;


Este é um exemplo básico, pode aplicar qualquer transformação de cor assim.


Responder

Gostei + 0

Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.

Aceitar