Os exemplos neste artigo resumem os métodos básicos de processamento de imagens do Delphi. Compartilhe com todos para sua referência. A análise específica é a seguinte:
//Procedimento de gravação Emboss(SrcBmp,DestBmp:TBitmap;AzimuthChange:integer);overload;var i, j, Gray, Azimuthvalue, R, G, B: inteiro; SrcRGB, SrcRGB1, SrcRGB2, DestRGB: pRGBTriple;begin for i: = 0 para SrcBmp.Height - 1 inicia SrcRGB := SrcBmp.ScanLine[i]; DestRGB := DestBmp.ScanLine[i]; if (AzimuthChange >= -180) e (AzimuthChange < -135) então comece se i > 0 então SrcBmp.ScanLine[i-1] senão SrcRGB1 := SrcRGB Inc(SrcRGB1); := SrcRGB; Inc(SrcRGB2); fim else if (AzimuthChange >= -135) e (AzimuthChange < -90) então começa se i > 0 então SrcRGB1 := SrcBmp.ScanLine[i-1] else SrcRGB1 := SrcRGB; SrcRGB2 := SrcRGB1; Inc(SrcRGB2); (AzimuthChange >= -90) e (AzimuthChange < -45) então comece se i > 0 então SrcRGB1 := SrcBmp.ScanLine[i-1] else SrcRGB1 := SrcRGB2 := SrcRGB1; -45) e (AzimuthChange < 0) então inicia SrcRGB1 := SrcRGB; se i > 0 então SrcRGB2 := SrcBmp.ScanLine[i-1] else SrcRGB2 := SrcRGB; SrcBmp.Height - 1) então SrcRGB1 := SrcBmp.ScanLine[i+1] else SrcRGB1 := SrcRGB; end else if (AzimuthChange >= 45) e (AzimuthChange < 90) então comece if (i < SrcBmp.Height - 1) then SrcRGB1 := SrcBmp.ScanLine[i +1] senão SrcRGB1 := SrcRGB; SrcRGB1; SrcRGB1; Inc(SrcRGB1); (AzimuthChange >= 135) e (AzimuthChange <= 180) então comece if (i < SrcBmp.Height - 1) then SrcRGB2 := SrcBmp.ScanLine[i+1] else SrcRGB2 := SrcRGB Inc(SrcRGB2 ): = SrcRGB;Inc(SrcRGB1); 0 para SrcBmp.Width - 1 comece se (AzimuthChange >= -180) e (AzimuthChange < -135) então comece Azimuthvalue := AzimuthChange + 180 R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed)*Azimuthvalue div; 45)-((SrcRGB2.rgbtRed)*(45-Azimuthvalue) div 45)+78; Valor de azimute)div 45)+78; B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue)*Azimuthvalue div 45)-((SrcRGB2.rgbtBlue)*(45-Azimuthvalue) div 45)+78; <-90) então comece o valor do azimute := AzimuteChange + 135 R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed)*Valor de azimute div 45)-((SrcRGB2.rgbtRed)*(45-Valor de azimute) div 45)+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen)*Valor de azimute div 45)-((SrcRGB2.rgbtGreen)*(45-Valor de azimute) div 45)+78 B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue) *Azimutevalor div 45)-((SrcRGB2.rgbtBlue)*(45-Azimuthvalue) div 45)+78; end else if (AzimuthChange >= -90) e (AzimuthChange < -45) então comece se j=1 então Inc(SrcRGB1,- 1);Azimutevalor := AzimuteChange + 90; R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed)*Valor de azimute div 45)-((SrcRGB2.rgbtRed)*(45-valor de azimute) div 45)+78 G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen) *Azimutevalor div 45)-((SrcRGB2.rgbtGreen)*(45-Valor de azimute) div 45)+78; Valor de azimute) div 45)+78; se (AzimuthChange >= -45) e (AzimuthChange < 0) então comece se j=1 então comece Inc(SrcRGB1,-1); SrcRGB.rgbtRed-((SrcRGB1.rgbtRed)*Azimutevalor div 45)-((SrcRGB2.rgbtRed)*(45-Azimuthvalue) div 45)+78; Valor de azimute)div 45)+78; B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue)*Azimuthvalue div 45)-((SrcRGB2.rgbtBlue)*(45-Azimuthvalue) div 45)+78 end else if (AzimuthChange >= 0) e (AzimuthChange < 45) então comece se j=1 então comece Inc(SrcRGB1,-1); Inc(SrcRGB2,-1);*Azimuthvalue div 45)-((SrcRGB2.rgbtRed)*( 45-Valor de azimute)div 45)+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen)*Valor de azimute div 45)-((SrcRGB2.rgbtGreen)*(45-Valor de azimute) div 45)+78 B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue) *Azimutevalor div 45)-((SrcRGB2.rgbtBlue)*(45-Azimuthvalue) div 45)+78; end else if (AzimuthChange >= 45) e (AzimuthChange < 90) então comece se j=1 então Inc(SrcRGB2,-1) ;Azimutevalor := AzimuteChange - 45; R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed)*Valor de azimute div 45)-((SrcRGB2.rgbtRed)*(45-Valor de azimute) div 45)+78 G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen) *Azimutevalor div 45)-((SrcRGB2.rgbtGreen)*(45-Valor de azimute) div 45)+78; Valor de azimute) div 45)+78; se (AzimuthChange >= 90) e (AzimuthChange < 135) então comece Azimuthvalue := AzimuthChange - 90; -Azimutevalor) div 45)+78; (SrcRGB1.rgbtBlue)*Valor de azimute div 45)-((SrcRGB2.rgbtBlue)*(45-Azimuthvalue) div 45)+78; R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed)*Valor de azimute div 45)-((SrcRGB2.rgbtRed)*(45-valor de azimute) div 45)+78 G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen) *Azimutevalor div 45)-((SrcRGB2.rgbtGreen)*(45-Valor de azimute) div 45)+78; Valor de azimute) div 45)+78; R:=Mín(R,255); R:=Máx(R,0); B:=Máx(B,0); Cinza := (R shr 2) + (R shr 4) + (G shr 1) + (G shr 4) + (B shr 3); DestRGB.rgbtRed:=Cinza; DestRGB.rgbtGreen:=Cinza; DestRGB.rgbtBlue:=Cinza se (j=-180) e (AzimuthChange<=180) ou ((AzimuthChange>=90) e (AzimuthChange<=180). ))) então comece Inc(SrcRGB1); (j=135) e (AzimuthChange<180)) ou ((AzimuthChange>=-180) e (AzimuthChange<=-90))) então comece Inc(SrcRGB2); fim; fim;fim;procedimento Emboss(Bmp:TBitmap;AzimuthChange:integer;ElevationChange:integer;WeightChange:integer);overload;var DestBmp:TBitmap;begin DestBmp:=TBitmap.Create; ,Alteração de peso); Bmp.Assign(DestBmp);end;//Procedimento inverso Negativo(Bmp:TBitmap);var i, j: PRGB: pRGBTriple;begin Bmp.PixelFormat:=pf24Bit; comece PRGB := Bmp.ScanLine[i]; para j := 0 para Bmp.Width - 1 faça começar PRGB^.rgbtRed :=não PRGB^.rgbtRed ;=não PRGB^.rgbtGreen :=não PRGB^.rgbtGreen :=não PRGB^.rgbtBlue Inc(PRGB); Procedimento de exposição Exposição(Bmp:TBitmap);var i, j: inteiro; Bmp.PixelFormat:=pf24Bit; para i := 0 para Bmp.Height - 1 comece PRGB := Bmp.ScanLine[i]; para j := 0 para Bmp.Width - 1 comece se PRGB^.rgbtRed<128 então PRGB^.rgbtRed :=não PRGB^.rgbtRed ; se PRGB^.rgbtGreen<128 então PRGB^.rgbtGreen :=não PRGB^.rgbtGreen; se PRGB^.rgbtBlue<128 então PRGB^.rgbtBlue :=não PRGB^.rgbtBlue Inc(PRGB); SrcBmp:TBitmap);var i, j:Integer;SrcRGB:pRGBTriple; SrcNextRGB:pRGBTriple;pRGBTriple Valor:Inteiro; procedimento Inc(SrcPreRGB,-1); SrcBmp.PixelFormat:=pf24Bit; para i := 0 para SrcBmp.Height - 1 comece se i > 0 então SrcPreRGB:=SrcBmp.ScanLine[i-1] else SrcPreRGB := SrcBmp.ScanLine[i]; SrcBmp.ScanLine[i]; se eu <SrcBmp.Height - 1 então SrcNextRGB:=SrcBmp.ScanLine[i+1] else SrcNextRGB:=SrcBmp.ScanLine[i]; para j := 0 para SrcBmp.Width - 1 comece se j > 0 então DecRGB; .rgbtRed+SrcNextRGB.rgbtRed; 0 então IncRGB Valor:=(Valor+SrcPreRGB.rgbtRed+SrcRGB.rgbtRed+SrcNextRGB.rgbtRed) div 9; DecRGB;SrcRGB.rgbtRed:=valor; se j > 0 então DecRGB Valor:=SrcPreRGB.rgbtGreen+SrcRGB.rgbtGreen+SrcNextRGB.rgbtGreen; Valor:=Valor+SrcPreRGB.rgbtGreen+SrcRGB.rgbtGreen+SrcNextRGB.rgbtGreen; se j < SrcBmp.Width - 1 então IncRGB Valor:=(Valor+SrcPreRGB.rgbtGreen+SrcRGB.rgbtGreen+SrcNextRGB.rgbtGreen) div 9; ; SrcRGB.rgbtGreen:=valor; se j>0 então DecRGB Valor:=SrcPreRGB.rgbtBlue+SrcRGB.rgbtBlue+SrcNextRGB.rgbtBlue; se j>0 então IncRGB; .rgbtBlue; se j < SrcBmp.Width - 1 então IncRGB Valor:=(Valor+SrcPreRGB.rgbtBlue+SrcRGB.rgbtBlue+SrcNextRGB.rgbtBlue) div 9; Nitidez(SrcBmp:TBitmap);var i, j: inteiro; SrcRGB: pRGBTriple; pRGBTriple Valor: inteiro;begin SrcBmp.PixelFormat:=pf24Bit; SrcPreRGB:=SrcBmp.ScanLine[i-1] else SrcPreRGB:=SrcBmp.ScanLine[i]; para j := 0 para SrcBmp.Width - 1 comece se j = 1 then Dec(SrcPreRGB); rgbtRed+(SrcRGB.rgbtRed-SrcPreRGB.rgbtRed)div 2; Máx(0,Valor);=Mín(255,Valor); SrcRGB.rgbtGreen:=valor;Valor:=SrcRGB.rgbtBlue+(SrcRGB.rgbtBlue-SrcPreRGB.rgbtBlue) div 2; valor Inc(SrcRGB); [Rotação e inversão de imagem] O código a seguir é implementado usando ScanLine com movimento de ponteiro, para cores de 24 bits! //Rodar 90 graus procedimento Rotate90(const Bitmap:TBitmap);var i,j:Integer; rowIn,rowOut:pRGBTriple; Bitmap.Altura;Bmp.Altura := Bitmap.Largura; pf24bit;Largura:=Bitmap.Largura-1;Altura:=Bitmap.Altura-1; = Bmp.ScanLine[i]; Inc(linhaOut,Altura - j); Bitmap.Assign(Bmp);end;//Girar 180 graus procedimento Rotate180(const Bitmap:TBitmap);var i,j:Integer;begin Bmp:= TBitmap.Create; Bitmap.Height; Bmp.PixelFormat := pf24bit; Largura:=Bitmap.Width-1; := 0 para Largura para iniciar rowOut := Bmp.ScanLine[Height - j]; rowOut^ := rowIn^; Inc(rowIn); pRGBTriple;TBitmap;Largura:Inteiro;início Bmp:=TBitmap.Create; := Bitmap.Height;= Bitmap.Width; para j:= 0 para Altura do início da linha; := Bitmap.ScanLine[j]; para i := 0 para Largura do início do rowOut := Bmp.ScanLine[Width - i]; Inc(rowOut,j); rowOut^ := rowIn^ end; TBitmap;Ângulo:Inteiro;BackColor:TColor):TBitmap;var i,j,iOriginal,jOriginal,CosPoint,SinPoint: inteiro; RowOriginal, RowRotated : pRGBTriple; CosTheta : Extended; ; se Ângulo<0 então Ângulo:=360-Abs(Angle); se Ângulo=0 então Result.Assign(Bitmap) senão se Ângulo=90 então comece Result.Assign(Bitmap);//Se for girado 90 graus, chame diretamente O código acima termina caso contrário if (Angle>90) e (Angle<180) então começa AngleAdd:=90; Ângulo:=Angle-AngleAdd; end else if Angle=180 then start Result.Assign(Bitmap); //Se for girado 180 graus, chame o processo acima diretamenteend else if (Angle>180) e ( Ângulo<270) então comece AngleAdd:=180; Result.Assign(Bitmap); Rotate270(Result);//Se for girado 270 graus, chame diretamente o processo acima end else if (Angle>270) e (Angle<360) então comece AngleAdd:=270; Ângulo -AngleAdd; end else AngleAdd:=0; se (Angle>0) e (Angle<90) então comece SinCos((Angle>0) + AngleAdd) * Pi / 180, SinTheta, CosTheta); if (SinTheta * CosTheta) < 0 então começa Result.Width := Round(Abs(Bitmap.Width * CosTheta - Bitmap.Height * SinTheta)); = Round(Abs(Bitmap.Largura * SinTheta - Bitmap.Altura * CosTheta)); end else start Result.Width := Round(Abs(Bitmap.Width * CosTheta + Bitmap.Height * SinTheta)); ; CosTeta:=Abs(CosTeta:=Abs(SinTeta); (AngleAdd=0) ou (AngleAdd=180) então comece CosPoint:=Round(Bitmap.Height*CosTheta); );CosPoint:=Round(Bitmap.Width*SinTheta); Result.Height-1 começa RowRotated := Result.Scanline[j]; for i := 0 para Result.Width-1 começa Case AngleAdd de 0: começa jOriginal := Round((j+1)*CosTheta-( i+1-SinPoint)*SinTheta)-1; Round((i+1)*CosTheta-(CosPoint-j-1)*SinTheta)-1; fim 90: início iOriginal := Round((j+1)*SinTheta-(i+1-SinPoint)*CosTheta )-1;jOriginal := Bitmap.Height-Round((i+1)*SinTheta-(CosPoint-j-1)*CosTheta); fim 180: início jOriginal := Bitmap.Height-Round((j+1)*CosTheta-(i+1-SinPoint)*iOriginal := Bitmap.Width-Round((i+1)*CosTheta-); (CosPoint-j-1)*SinTheta); fim 270: início iOriginal := Bitmap.Width-Round((j+1)*SinTheta-(i+1-SinPoint)*CosTheta := Round((i+1)*SinTheta-(CosPoint-j-1)*CosTheta)-1); ; fim; fim se (iOriginal >= 0) e (iOriginal <= Bitmap.Width-1)e (jOriginal >= 0) e (jOriginal <= Bitmap.Height-1) então comece RowOriginal := Bitmap.Scanline[jOriginal]; ; fim; fim; fim;fim;//procedimento de inversão horizontal FlipHorz(const Bitmap:TBitmap);var i,j:Integer rowIn,rowOut:pRGBTriple;Bmp:TBitmap;Altura:Inteiro;início Bmp:=TBitmap.Create; PixelFormat := pf24bit Largura:=Bitmap.Width-1; Altura:=Bitmap.Height-1; para j := 0 até Altura inicia rowIn := Bitmap.ScanLine[j]; ,Largura - i); rowOut^ := rowIn^; end; FlipVert(const Bitmap:TBitmap);var i,j:Integer;rowOut:pRGBTriple; Altura := Bitmap.Largura; Bmp.PixelFormat := pf24bit; Largura:=Bitmap.Width-1; Altura:=Bitmap.Height-1; para j := 0 até Altura para começar rowIn := Bitmap.ScanLine[j]; .ScanLine[Altura - j]; Inc(rowOut,i); Bitmap.Assign(Bmp);end;[Ajuste de brilho, contraste e saturação] O código a seguir é implementado usando ScanLine com movimento do ponteiro! função Min(a, b: inteiro): inteiro;início se a < b então resultado := a else resultado := b;fim;função Max(a, b: inteiro): inteiro;começo se a > b então resultado : = a else resultado := b;end;//Procedimento de ajuste de brilho BrightnessChange(const SrcBmp,DestBmp:TBitmap;ValueChange:integer);var i, j: inteiro; SrcRGB, DestRGB: pRGBTriple; começar para i := 0 para SrcBmp.Height - 1 começar SrcRGB := 0 para SrcBmp.Width - 1 comece se ValueChange > 0 então comece DestRGB.rgbtRed := Min(255, SrcRGB.rgbtRed + ValueChange); DestRGB.rgbtGreen := Min(255, SrcRGB.rgbtGreen + ValueChange := Min(255, SrcRGB.rgbtBlue + ValueChange); =Máx(0, SrcRGB.rgbtRed + ValueChange := Max(0, SrcRGB.rgbtGreen + ValueChange := Max(0, SrcRGB.rgbtBlue + ValueChange); ; fim; fim;fim;//procedimento de ajuste de contraste ContrastChange(const SrcBmp,DestBmp:TBitmap;ValueChange:integer);var i, j: inteiro; DestRGB: pRGBTriple;begin for i := 0 to SrcBmp.Height - 1 do start SrcRGB := SrcBmp.ScanLine[i] ;DestRGB :=DestBmp.ScanLine[i]; := 0 para SrcBmp.Width - 1 comece se ValueChange>=0 então comece se SrcRGB.rgbtRed >= 128 então DestRGB.rgbtRed := Min(255, SrcRGB.rgbtRed + ValueChange) else DestRGB.rgbtRed := Max(0 , SrcRGB.rgbtRed - ValueChange); SrcRGB.rgbtGreen >= 128 então DestRGB.rgbtGreen := Min(255, SrcRGB.rgbtGreen + ValueChange) else DestRGB.rgbtGreen := Max(0, SrcRGB.rgbtGreen - ValueChange); := Min(255, SrcRGB.rgbtBlue + ValueChange) else DestRGB.rgbtBlue := Max(0, SrcRGB.rgbtBlue - ValueChange); +ValorAlteração) else DestRGB.rgbtRed := Min(128, SrcRGB.rgbtRed - ValueChange); se SrcRGB.rgbtGreen >= 128 então DestRGB.rgbtGreen := Max(128, SrcRGB.rgbtGreen + ValueChange) senão DestRGB.rgbtGreen := Min(128, SrcRGB .rgbtVerde - ValueChange); se SrcRGB.rgbtBlue >= 128 então DestRGB.rgbtBlue := Max(128, SrcRGB.rgbtBlue + ValueChange) senão DestRGB.rgbtBlue := Min(128, SrcRGB.rgbtBlue - ValueChange); Inc(DestRGB); end;end;//Procedimento de ajuste de saturação SaturationChange(const SrcBmp,DestBmp:TBitmap;ValueChange:integer);var Grays: array[0..767] de Integer: array[0..255] de Word Gray , x, y: Inteiro;SrcRGB,DestRGB: pRGBTriple; Byte;beginValueChange:=ValueChange+255;for i := 0 a 255 do Alpha[i] := (i * ValueChange) Shr 8;x := 0;for i := 0 a 255 dobegin Gray := i - Alpha [i]; Cinzas[x] := Cinza Inc(x); Inc(x);end; para y := 0 para SrcBmp.Height - 1 dobegin SrcRGB := SrcBmp.ScanLine[Y]; comece Gray := Grays[SrcRGB.rgbtRed + SrcRGB.rgbtGreen + SrcRGB.rgbtBlue]; se Cinza + Alpha[SrcRGB.rgbtRed]>0 então DestRGB.rgbtRed := Min(255,Gray + Alpha[SrcRGB.rgbtRed]) senão DestRGB.rgbtRed := 0; rgbtGreen]>0 então DestRGB.rgbtGreen := Min(255,Gray + Alpha[SrcRGB.rgbtGreen]) else DestRGB.rgbtGreen := 0; se Gray + Alpha[SrcRGB.rgbtBlue]>0 então DestRGB.rgbtBlue := Min(255,Gray + Alpha[SrcRGB.rgbtBlue] ) senão DestRGB.rgbtBlue := 0; Inc(DestRGB); end;end; end;//procedimento de ajuste RGB RGBChange(SrcBmp,DestBmp:TBitmap;RedChange,GreenChange,BlueChange:integer);var SrcRGB, DestRGB: pRGBTriple; = 0 para SrcBmp.Height- 1 inicia SrcRGB := SrcBmp.ScanLine[i]; DestRGB :=DestBmp.ScanLine[i]; para j := 0 para SrcBmp.Width - 1 começa se RedChange> 0 então DestRGB.rgbtRed := Min(255, SrcRGB.rgbtRed + RedChange) senão DestRGB.rgbtRed := Max(0, SrcRGB.rgbtRed + RedChange); se GreenChange> 0 então DestRGB.rgbtGreen := Min(255, SrcRGB.rgbtGreen + GreenChange) senão DestRGB.rgbtGreen := Max(0, SrcRGB.rgbtGreen + GreenChange); .rgbtAzul := Min(255, SrcRGB.rgbtBlue + BlueChange) else DestRGB.rgbtBlue := Max(0, SrcRGB.rgbtBlue + BlueChange) Inc(SrcRGB); RGB2BGR(const Bitmap:TBitmap);var X: Inteiro Y: Inteiro; pRGBTriple; = PRGB^.rgbtBlue; PRGB^.rgbtBlue := Cor Inc(PRGB); end;end;//procedimento em escala de cinza (ponderada) Escala de cinza(const Bitmap:TBitmap);var X: Integer Y: PRGB: pRGBTriple: Byte;begin for Y := 0 to (Bitmap.Height - 1) comece PRGB := Bitmap.ScanLine[Y]; para X := 0 para (Bitmap.Width - 1) comece Gray := (77 * Vermelho + 151 * Verde + 28 * Azul) PRGB^.rgbtRed:=PRGB^.rgbtGreen:=PRGB^.rgbtBlue:=Gray end Inc(PRGB); ;
Teoria:
Palavras-chave:
Área de desenho - ou seja, a área onde a janela exibe a imagem, que também pode ser a tela inteira (o efeito de desenho é melhor na tela inteira do que na janela geral)
Ponto central - ou seja, as coordenadas do ponto central a serem exibidas na área de desenho da imagem original (isenção de responsabilidade: este conceito é particularmente importante)
Vamos falar primeiro sobre ampliação de imagem. Para ampliar uma imagem, nossa abordagem geral é ampliar a imagem diretamente, mas o método apresentado neste artigo amplia apenas a parte que podemos ver. a ampliação é maior que a área de desenho. É ainda menor. Não há muito a dizer sobre esta situação. Imagem; a segunda é que a imagem ampliada é maior que a área de desenho. Este é o tópico principal que discutiremos hoje. Neste caso, devemos primeiro determinar o tamanho da imagem ampliada e depois calcular o tamanho da imagem. imagem original com base na posição e tamanho do "ponto central" e, finalmente, ampliar a imagem capturada para a área de desenho.
Vamos falar sobre roaming de imagem. Quando a imagem exibida excede a área de desenho, precisamos percorrer a imagem para ver a imagem inteira. O princípio é: quando o mouse clica na área de desenho, ele inicia o roaming, primeiro registra a posição do clique do mouse, depois detecta o movimento do mouse e calcula o "ponto central" com base no mouse e no último deslocamento ( as coordenadas da tela precisam ser convertidas para as coordenadas da imagem original), retire a parte a ser exibida da imagem original de acordo com o princípio de ampliação acima, amplie-a e exiba-a na área de desenho.
Implementação do algoritmo:
1. Ampliação de imagem
Definição de variável:
PZoom: Taxa de ampliação (número inteiro: 100 é 100%, 100 pode ser alterado para 10.000 ou maior conforme necessário, mas números de ponto flutuante não são recomendados)
a, b: ponto central
w, h: largura e altura da imagem original a ser capturada
x, y: a posição a ser interceptada (canto superior esquerdo)
sw,sh: largura e altura da imagem original
p1, p2: taxa de ampliação
ah, ah: o tamanho da imagem ampliada
pw,ph: tamanho da área de desenho
vx,vy: a posição exibida na área de desenho (canto superior esquerdo)
vw, vh: o tamanho exibido na área de desenho
ptx, pty: variáveis temporárias
Variáveis conhecidas: PZoom, (a, b), (sw, sh), (p1, p2), (aw, ah), (pw, ph)
Variáveis a serem calculadas: (x,y),(w,h),(vx,vy),(vw,vh)
Comece a calcular:
aw=Round(PZoom*sw/100);ah=Round(PZoom*sh/100);p1=aw/pwp2=ah/ph// Nota: Round é usado para arredondamento, como Int(), Fix em outros idiomas ()etc se p1>1 então w=Round(sw/p1) else w=swif p2>1 então h=Round(sh/p2) else h=sh// Nota: shr é o operador de deslocamento direito, você pode usar ">>1", "div 2", "/2" ou "Round(w/2)" em vez de x=aw shr 1y=bh shr 1 // Nota: div é o operador de divisão inteira ptx=(w*PZoom) div 100pty=(h*PZoom) div 100// O seguinte calcula o tamanho e a posição da imagem exibida na área de desenho
variável
Pencent:double; // Taxa de zoom wx:double; // Taxa de zoom ampla hx:double; // Taxa de zoom alta // Obtém taxa de zoom wx:=pw/ptx hx:=ph/pty if wx>hx then Pcent: =hx else Pencent:=wx; // Obtém o tamanho final da imagem vw:=Round(Pencent*ptx); Calcule a posição da imagem vx:=(pw-vw) div vy:=(ph-vh) div 2;// -------------------- ----------------
Ok, duas tarefas importantes foram concluídas (x, y), (w, h), (vx, vy), (vw, vh) foram calculadas. O seguinte trabalho é exibido.
variável
sDC é o identificador do dispositivo (DC) da imagem original. tDC é o identificador do dispositivo temporário dDC e o identificador do dispositivo final BitBlt(tDC,0,0,w,h,sDC,0,0,SRCCOPY);SetStretchBltMode(dDC). ,STRETCH_DELETESCANS);StretchBlt(dDC ,0,0,vw,vh,tDC,0,0,w,h,SRCCOPY);
Finalmente, desenhe na área exibida:
Por exemplo:
BitBlt(GetDC(0),vx,vy,vx+vw,xy+vh,dDC,0,0,SRCCOPY);
2. Roaming de imagens
Primeiro defina três variáveis globais:
FBeginDragPoint :TPoint; // Registra a posição onde o mouse começa a arrastar FBeginDragSBPoint :TPoint; // Registra a posição do "ponto central" FBeginDrag :boolean; "Localização
Quando o botão esquerdo do mouse é clicado, registre a posição do mouse e a posição do "ponto central" e defina FBeginDrag como verdadeiro.
Quando o botão direito do mouse aparecer, defina FBeginDrag como false
Quando o mouse se move, FBeginDrag é julgado. Se for falso, nenhum processamento será executado. Se for verdadeiro, o seguinte processamento será executado.
Suponha que X e Y sejam a posição atual do mouse
a=FBeginDragPoint.X-((X-FBeginDragPoint.X)*100) div PZoomb=FBeginDragPoint.Y-((Y-FBeginDragPoint.Y)*100) div PZoom
Por fim, use a imagem apresentada acima para ampliar e exibir a imagem
Pontas:
1. Se a imagem for grande, ocorrerá um erro de estouro de memória ao usar o objeto bitmap do delphi. Nesse caso, você pode fazer as seguintes configurações:
bitImage:=TBitmap.Create; bitImage.PixelFormat:=pf24bit;
2. Se quiser que a imagem se adapte automaticamente ao tamanho da janela, consulte o seguinte código:
var p1,p2 :double;begin p1:=pw/sw; p2:=ph/sw; se p1>p2 então PZoom:=Round(p2*100) else PZoom:=Round(p1*100); 0 então PZoom:=100;fim;
Processamento de brilho de cor de pixel de imagem em escala de cinza Delphi
No processamento de imagens, a velocidade é importante. Portanto, temos que reprocessar o TBitmap para obter o TVczhBitmap. Isso ocorre porque GetPixels e SetPixels são muito lentos, então precisamos usar outro método.
unidade untBitmapProc; interface usa Gráficos, SysUtils; tipo TVczhBitmap=class(TBitmap) private Data:PByteArray; :Byte); function GetBytes(X,Y:Integer):Byte; construtor publicado protegido Create; propriedade pública Bytes[X,Y:Inteiro]:Byte read GetBytes write SetBytes; procedimento LoadFromFile(FileName:String); TVczhBitmap.GetBytePointer(X,Y:Integer):PByte começa se Line<>Y então começar Linha:=Y; procedimento ScanLine[Y]; X,Y)^:=Valor fim função TVczhBitmap.GetBytes(X,Y:Inteiro):Byte início; resultado:=GetBytePointer(X,Y)^; fim do construtor TVczhBitmap.Create; início herdado SetFormat; ; Linha:=-1; fim do procedimento TVczhBitmap.ToGray; B:Byte; começar para Y:=0 até Altura-1 fazer para X:=0 até Largura-1 começar R:=0 até 2 fazer R:=R+GetBytes(X*3+; B,Y); para B:=0 a 2 do SetBytes(X*3+B,Y,R div 3 end;
Depois disso, precisamos criar vários formulários. O primeiro é usado para exibir imagens e o segundo é usado para processar imagens. Todos os outros formulários herdam do segundo formulário e contêm os métodos de processamento reais.
Vejamos primeiro a segunda janela:
unidade untProc; interface usa Windows, Mensagens, SysUtils, Variantes, Classes, Gráficos, Controles, Formulários, Diálogos, ExtCtrls, untBitmapProc, StdCtrls, ComCtrls; tipo TfrmProcessor = class(TForm) pbBar: TPaintBox: Button1: TButton; procedimento FormCreate(Remetente: TObject); procedimento FormDestroy(Remetente: TObject); procedimento FormShow(Remetente: TObject); procedimento pbBarPaint(Remetente: TObject); ..255]de Byte;TVczhBitmap; procedimento DrawBar; implementação {$R *.dfm} usa untViewer; procedimento TfrmProcessor.DrawBar; var I:Integer; I:=1 a 255 do Bar.Canvas.LineTo(I,255-BarData[I]); TfrmProcessor.FormCreate(Sender: TObject); começar Bar:=TVczhBitmap.Create; Bar.Canvas.Brush.Style: =bsSolid; fim do procedimento TfrmProcessor.FormDestroy(Sender: TObject); fim procedimento TfrmProcessor.FormShow(Sender: TObject); .Canvas.Draw(0,0,Bar); fim do procedimento TfrmProcessor.Button1Click(Remetente: TObject); var X,Y:Integer; start para Y:=0 para Buffer.Height-1 do para X:=0 para Buffer.Width*3-1 do Played.Bytes[X,Y]:=BarData[Buffer.Bytes[ X,Y]];frmViewer.FormPaint(frmViewer);
Depois disso, faça uma janela que herda dela, ajuste BarData[] e pressione Apply para ver o resultado.
Agora comece a processar a imagem. Veja o programa de amostra para efeitos específicos.
1. Inversão de cores.
As cores das imagens em tons de cinza variam de 0 a 255, portanto, para inverter a cor, podemos subtrair o valor da cor de 255 para obter a cor invertida.
var I:Integer; start herdado para I:=0 a 255 do BarData[I]:=255-I;//Subtrai o valor da cor de 255 DrawBar;
2. Limite a gama de cores para aumentar ou diminuir o brilho
A cor é originalmente de 0~255. Se você ajustar o intervalo, por exemplo de 0 a 16, a imagem ficará significativamente mais escura. Podemos definir o valor inicial como a e o valor final como b, então o novo valor da cor New=a+(b-1)*Old/255. Isso altera o brilho sem destruir a sequência de cores original. O código é o seguinte
var I:Inteiro; início para I:=0 a 255 do BarData[I]:=(255-sbMin.Position)+Round((sbMin.Position-sbMax.Position)/255*I DrawBar; );Botão1Clique(Botão1);
O sbMin.Position e o sbMaxPosition aqui estão ambos invertidos. Portanto, use 255 para subtrair
3. Aumente a gama de cores dentro de um determinado intervalo
Se a imagem em si tiver uma gama de cores pequena, você poderá usar este método para aumentar o contraste da imagem, o que é benéfico para a análise da imagem. Métodos específicos:
Selecione um valor a como valor inicial, selecione um valor b como valor final e, em seguida, deforme de acordo com a seguinte fórmula:
|0 (X<=a)
f(X)= |255/(ba)*(Xa)
255(X>=b)
var I:Inteiro; início para I:=0 a 255 comece se I<=sbMin.Position then BarData[I]:=0 else if I>=sbMax.Position then BarData[I]:=255 else BarData[I ]:=Rodada(255/(sbMax.Position-sbMin.Position)*(I-sbMin.Position)); pbBarPaint(pbBar);Botão1Click(Botão1);
4. Converta para imagens em preto e branco
Ao usar a terceira função, você descobrirá que quando b<=a, as cores da imagem são brancas, exceto o preto. Os benefícios desta operação não podem ser exibidos diretamente. Isto só será eficaz quando se trata de processamento de imagem mais avançado, como detecção de bordas. Este exemplo pode ser transformado usando a fórmula do terceiro método, por isso não será explicado em detalhes.
5. Ajuste de brilho exponencial
Assumimos que o domínio deste gráfico é [0,1] e o intervalo de valores também é [0,1]. Então, defina a função f(x)=x^c, então a imagem de f(x) terá uma seção conforme mostrado acima. Quando usamos o mouse para operar novamente, podemos pegar um ponto P (a, b) nele e fazer F (x) passar pelo ponto P, depois C = Ln (B)/Ln (a). Com C, podemos operar com cores:
Novo = (antigo/255)^c*255 = exp (ln (antigo/255)*c) /255; Bardata [i]: = redonda (exp (I/255)*EC)*255);
Fazer isso ajusta o brilho da imagem.
Dicas para exibir efeitos especiais em gráficos Delphi
Visão geral
---- Atualmente, em muitos softwares de aprendizado e CDs de jogo, você pode ver vários
A tecnologia de exibição gráfica depende do movimento gráfico, entrelaçamento, forma de gota de chuva, persianas, empilhamento de blocos de construção e outros métodos de exibição para tornar a imagem mais animada e mais atraente para o público. Este artigo explorará como implementar várias técnicas de exibição gráfica em Delphi.
Princípios básicos
---- Em Delphi, é muito simples exibir uma imagem. e o arquivo selecionado será exibido no componente de tempo. Mas isso exibe apenas os gráficos diretamente no formulário, e não há habilidade. Para fazer com que a tela gráfica tenha um efeito único, você pode seguir as seguintes etapas:
---- Defina um componente de tempo e carregue os gráficos a serem exibidos no componente de tempo primeiro, ou seja, carregue o conteúdo gráfico do disco na memória como um cache de gráficos.
---- Crie um novo objeto de bitmap com o mesmo tamanho que os gráficos no componente de tempo.
---- Use a função de direitos autorais da tela (copie a área retangular de uma tela para a área retangular de outra tela), use técnicas e forma dinamicamente
Converta o conteúdo do arquivo em um bitmap e exiba o bitmap no formulário.
---- Método de implementação
Várias técnicas de exibição gráfica são introduzidas abaixo:
1. Efeito de punho-pux
Puxe os gráficos a serem exibidos na tela, para cima, para baixo, esquerda e direções e, ao mesmo tempo, cobre os gráficos antigos originais na tela. Puxe para a esquerda e puxe para a direita.
Princípio: Primeiro, mova a primeira linha horizontal colocada no gráfico temporário para o último no bitmap a ser exibido e depois mova as duas primeiras linhas horizontais no gráfico temporário para os dois últimos bitmaps a serem exibidos Em seguida, mova as três e quatro primeiras linhas até que todos os dados gráficos sejam movidos. Durante o processo de movimento, você pode ver que o bitmap exibido flutua de baixo para cima, alcançando um efeito de pull-up.
Algoritmo de programa:
Procedimento TForm1.Button1Click (Remesado: Tobado); : = Image1.Height; I: = 0 para Bmpheight Começam newbmp.canvas.copyct (Rect (0, Bmpheight-I, BMPWidth, Bmpheight), Image1.Canvas, Rect (0,0, BMPWidth, i)); , Newbmp);
2. Efeito vertical escalonado
Princípio: divida os gráficos a serem exibidos em duas partes. Na tela, você pode ver que os gráficos mais leves que aparecem nas extremidades superior e inferior se movem em direção ao centro da tela até ficarem completamente claros.
Algoritmo de programa:
PROCEDIMENTO TFORM1.BUTON4CLICK (Remesado: Tobject); ; i: = 0; Bmpheight-I+J-1, BMPWidth, Bmphoight-i+J)); (0, Bmpheight-J, BMPWidth, Bmpheight-J+1), Image1.Canvas, Rect (0, IJ, BMPWidth, I-J+1)); (120.100, newbmp);
3. Efeito horizontal escalonado
Princípio: O mesmo princípio que o efeito de entrega vertical, exceto que os gráficos divididos em dois grupos são movidos para a tela das extremidades esquerda e direita, respectivamente.
Algoritmo de programa:
PROCEDIMENTO TFORM1.BUTON5CLICO (Remesado: TOBJETO); ; i: = 0; i+j-1,0, bmpwidth-i+j, bmpheight)); (BMPWidth-J, 0, BMPWidth-J+1, Bmpheight), Image1.Canvas, Rect (IJ, 0, I-J+1, Bmpheight)); (120.100, newbmp);
4. Efeito da gota de chuva
Princípio: mova a última linha de varredura dos gráficos temporários para o primeiro para a última linha de varredura do bitmap visível em sequência, permitindo que essa linha de varredura deixe seu rastreamento na tela. Em seguida, a penúltima linha de varredura dos gráficos temporários é movida para a primeira para as penúltimas linhas de varredura do bitmap visível em sequência. E assim por diante para as demais linhas de varredura.
Algoritmo de programa:
PROCEDIMENTO TFORM1.BUTON3COMENTE (Remesado); ; para i: = bmpheight Down 1 faça para j: = 1 a eu começo newbmp.canvas.copyct (rect (0, j-1, bmpwidth, j), image1.canvas, rect (0, i-1, bmpwidth, i));
5. Louvres Efeito
Princípio: Divida os dados colocados nos gráficos temporários em vários grupos e, em seguida, mova -os sequencialmente do primeiro grupo para o último grupo. O tempo move a segunda linha de varredura e depois mova as linhas da terceira e quarta varredura.
Algoritmo de programa:
Procedimento TForm1.Button6Click (remetente: TObject); Altura: = Image1.Height; BMPWidth: = Image1.Width; -1, bmpwidth, xcount*j+i), image1.canvas, Rect (0, xcount*j+i-1, BMPWidth, xcount*j+i));
6. Efeito do bloco de construção
Princípio: É uma variação do efeito da gota de chuva.
Algoritmo de programa:
PROCEDIMENTO TFORM1.BUTON7CLICK (Remesado: Tobject); ; i: = bmpheight; , BMPWidth, i)); fim;
Conclusão
Todos os efeitos de exibição gráfica acima foram transmitidos no computador. Funciona muito bem.
Implementando a lupa de imagem usando Delphi
Adicione dois componentes de tempo ao formulário. Outro componente de tempo tem sua propriedade de nome definida como Image2, que exibe a imagem ampliada.
O núcleo deste exemplo é a função de alongamento.
Procedimento TForm1.Image1MouSEMove (remetente: TOBJECT; SHIFT: TSHIFTSTATE; X, Y: Inteiro); Comece a estiramento (Image2.Canvas.Handle, 0,0, Image2.Width, Image2.Height, Image1.Canvas.Handle,, Y- 20,40,40, SRCCOPY); Screen.cursors [1]: = loadcursorfromfile ('magnify.cur');
O programa chamará primeiro a função Stretchbt, usará a posição atual do mouse como ponto central, selecionará a imagem parcial no componente Image1 com um comprimento lateral de 40 e ampliará a imagem parcial ao componente Image2. Em seguida, atualize a exibição do componente Image2 chamando o método de atualização do componente Image2. Finalmente, defina o ponteiro do mouse para a nova forma.
O código do programa é o seguinte:
unidade unit1; interfaceUseswindows, mensagens, sysutils, variantes, classes, gráficos, controles, formulários, diálogos, extctrls, stdctrls; digite tform1 = classe (tform) Imagem: Timage; ; X, Y: Inteiro); FormmouseMove (remetente: TObject; Shift: tShiftState;; Shift: TSHIFTSTATE; X, Y: Inteiro); BeginstretchBlt (Image2.Canvas.Handle, 0,0, Image2.Width, Image2.Height, Image1.Canvas.Handle, X-20, Y-20,40,40, SRCCOPY); ]: = Loadcursorfromfile ('magnify.cur'); Self.cursor: = 1; end; procedimento tform1.formMousEMove (remetente: TOBJETO; turno: tShiftState; x, y: número inteiro); screen.cursors [1]: = crDefault; .
Salve o arquivo e pressione a tecla F9 para executar o programa e o programa será executado.
A ampliação de imagens é uma função essencial de um excelente software de visualização de imagem.
Espero que este artigo seja útil para a programação Delphi de todos.