この記事の例では、Delphi の基本的な画像処理方法をまとめています。皆さんの参考に共有してください。具体的な分析は次のとおりです。
//エンボスプロシージャ Emboss(SrcBmp,DestBmp:TBitmap;AzimuthChange:integer);overload;var i, j, Gray, Azimuthvalue, R, G, B: integer; SrcRGB, SrcRGB1, SrcRGB2, DestRGB: pRGBTriple;begin for i: = 0 から SrcBmp.Height - 1 で SrcRGB が始まります := SrcBmp.ScanLine[i]; DestRGB := DestBmp.ScanLine[i]; if (AzimuthChange >= -180) and (AzimuthChange < -135) if i > 0 then SrcRGB1 := SrcBmp.ScanLine[i-1]それ以外の場合は SrcRGB1 := SrcRGB1); := SrcRGB; Inc(SrcRGB2); end else if (AzimuthChange >= -135) and (AzimuthChange < -90) then begin if i > 0 then SrcRGB1 := SrcBmp.ScanLine[i-1] else SrcRGB1 := SrcRGB; SrcRGB2 := SrcRGB1; Inc(SrcRGB2); (AzimuthChange >= -90) および (AzimuthChange < -45) then begin if i > 0 then SrcRGB1 := SrcBmp.ScanLine[i-1] else SrcRGB1 := SrcRGB; SrcRGB2 := SrcRGB1; end else if (AzimuthChange >= -45) および (AzimuthChange < 0) その後 SrcRGB1 を開始します := SrcRGB; if i > 0 then SrcRGB2 := SrcBmp.ScanLine[i-1] else SrcRGB2 := SrcRGB; end else if (AzimuthChange >= 0) and (AzimuthChange < 45) then begin SrcRGB2 := SrcRGB; SrcBmp.Height - 1) その後 SrcRGB1 := SrcBmp.ScanLine[i+1] else SrcRGB1 := SrcRGB; end else if (AzimuthChange >= 45) and (AzimuthChange < 90) then begin if (i < SrcBmp.Height - 1) then SrcRGB1 := SrcBmp.ScanLine[i +1] それ以外の場合 SrcRGB1 := SrcRGB2 := SrcRGB1; end else if (AzimuthChange >= 90) and (AzimuthChange < 135) then begin if (i < SrcBmp.Height - 1) then SrcRGB1 := SrcRGB2 := SrcRGB1; Inc(SrcRGB1); 終了 if (AzimuthChange >= 135) および (AzimuthChange <= 180) の場合、 (i < SrcBmp.Height - 1) then SrcRGB2 := SrcBmp.ScanLine[i+1] else SrcRGB2 := SrcRGB; SrcRGB1 : = SrcRGB; Inc(SrcRGB1); の場合0 ~ SrcBmp.Width - 1 は、(AzimuthChange >= -180) かつ (AzimuthChange < -135) の場合に開始されます。その後、Azimuthvalue := AzimuthChange + 180; R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed)*Azimuthvalue div) 45)-((SrcRGB2.rgbtRed)*(45-方位角値) div 45)+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen)*方位角値 div 45)-((SrcRGB2.rgbtGreen)*(45-方位角値)div 45)+78; B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue)*方位値 div 45)-((SrcRGB2.rgbtBlue)*(45-方位値) div 45)+78; end else if (AzimuthChange >= -135) および (AzimuthChange) < -90) その後、方位角値を開始します:=方位変化 + 135; R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed)*方位値 div 45)-((SrcRGB2.rgbtRed)*(45-方位値) div 45)+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen)*方位値 div 45)-((SrcRGB2.rgbtGreen)*(45-方位値) div 45)+78; B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue) *方位値 div 45)-((SrcRGB2.rgbtBlue)*(45-Azimuthvalue) div 45)+78; end else if (AzimuthChange >= -90) and (AzimuthChange < -45) then begin if j=1 then Inc(SrcRGB1,- 1); 方位値 := 方位変化 + 90; R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed)*方位値 div 45)-((SrcRGB2.rgbtRed)*(45-方位値) div 45)+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen) *方位値 div 45)-((SrcRGB2.rgbtGreen)*(45-方位角値) div 45)+78; B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue)*方位角値 div 45)-((SrcRGB2.rgbtBlue)*(45-方位値) div 45)+78; if (AzimuthChange >= -45) and (AzimuthChange < 0) then begin if j=1 then begin Inc(SrcRGB2,-1); end; SrcRGB.rgbtRed-((SrcRGB1.rgbtRed)*方位角値 div 45)-((SrcRGB2.rgbtRed)*(45-方位角値) div 45)+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen)*方位角値 div 45)-((SrcRGB2.rgbtGreen)*(45-方位角値)div 45)+78; B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue)*方位角値 div 45)-((SrcRGB2.rgbtBlue)*(45-方位角値) div 45)+78; end else if (AzimuthChange >= 0) and (AzimuthChange < 45) j=1 の場合に開始します。 Inc(SrcRGB1,-1); Inc(SrcRGB2,-1); 方位値 := 方位変化 R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed)*方位値 div 45) 45-方位角値)div 45)+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen)*方位値 div 45)-((SrcRGB2.rgbtGreen)*(45-方位値) div 45)+78; B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue) *方位値 div 45)-((SrcRGB2.rgbtBlue)*(45-Azimuthvalue) div 45)+78; end else if (AzimuthChange >= 45) and (AzimuthChange < 90) then begin if j=1 then Inc(SrcRGB2,-1) ; 方位値 := 方位変化 - 45; R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed)*方位値 div 45)-((SrcRGB2.rgbtRed)*(45-方位値) div 45)+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen) *方位値 div 45)-((SrcRGB2.rgbtGreen)*(45-方位角値) div 45)+78; B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue)*方位角値 div 45)-((SrcRGB2.rgbtBlue)*(45-方位値) div 45)+78; (AzimuthChange >= 90) かつ (AzimuthChange < 135) の場合、Azimuthvalue := AzimuthChange - 90; R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed)*Azimuthvalue div 45)-((SrcRGB2.rgbtRed)*(45) -方位値) div 45)+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen)*方位角値 div 45)-((SrcRGB2.rgbtGreen)*(45-方位角値) div 45)+78; B:=SrcRGB.rgbtBlue-( (SrcRGB1.rgbtBlue)*方位角の値div 45)-((SrcRGB2.rgbtBlue)*(45-Azimuthvalue) div 45)+78; end else if (AzimuthChange >= 135) and (AzimuthChange <= 180) then begin Azimuthvalue := AzimuthChange - 135; R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed)*方位値 div 45)-((SrcRGB2.rgbtRed)*(45-方位値) div 45)+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen) *方位値 div 45)-((SrcRGB2.rgbtGreen)*(45-方位角値) div 45)+78; B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue)*方位角値 div 45)-((SrcRGB2.rgbtBlue)*(45-方位値) div 45)+78; R:= 最小(R,255); G:= 最小(G,255); B:=Max(B,0); グレー:= (R shr 2) + (R shr 4) + (G shr 1) + (G shr 4) + (B shr 3); DestRGB.rgbtRed:=Gray; DestRGB.rgbtGreen:=Gray; DestRGB.rgbtBlue:=Gray; if (j=-180) および (AzimuthChange<-135)) または ((AzimuthChange>=90) および (AzimuthChange<=180) ))) 次に、Inc(SrcRGB1) を開始します。 (j=135) および (AzimuthChange<180)) または ((AzimuthChange>=-180) および (AzimuthChange<=-90))) then begin Inc(SrcRGB2) end;終了; 終了; 手順Emboss(Bmp:TBitmap;AzimuthChange:integer;ElevationChange:integer;WeightChange:integer);overload;var DestBmp:TBitmap;begin DestBmp:=TBitmap.Create; DestBmp.Assign(Bmp); 、体重変更); Bmp.Assign(DestBmp);end;//逆手順 Negative(Bmp:TBitmap);var i, j: Integer; PRGB: pRGBTriple;begin Bmp.PixelFormat:=pf24Bit; for i := 0 to Bmp.Height - 1 do begin PRGB := Bmp.ScanLine[i]; for j := 0 to Bmp.Width - 1 begin PRGB^.rgbtRed :=not PRGB^.rgbtGreen :=not PRGB^.rgbtBlue end;end;露光手順 Exposure(Bmp:TBitmap);var i, j: integer; PRGB: pRGBTriple;begin Bmp.PixelFormat:=pf24Bit; for i := 0 to Bmp.Height - 1 do begin PRGB := Bmp.ScanLine[i]; for j := 0 to Bmp.Width - 1 do begin if PRGB^.rgbtRed<128 then PRGB^.rgbtRed :=not PRGB^.rgbtRed ; if PRGB^.rgbtGreen<128 then PRGB^.rgbtGreen :=not PRGB^.rgbtGreen; if PRGB^.rgbtBlue<128 then PRGB^.rgbtBlue :=not PRGB^.rgbtBlue; end;end;//blur プロシージャ Blur( SrcBmp:TBitmap);var i, j:Integer; SrcNextRGB:pRGBTriple; 値:IncRGB; Inc(SrcNextRGB); 終了; SrcBmp.PixelFormat:=pf24Bit; for i := 0 to SrcBmp.Height - 1 if i > 0 then SrcPreRGB:=SrcBmp.ScanLine[i-1] else SrcPreRGB := SrcBmp.ScanLine[i]; SrcBmp.ScanLine[i]; i < SrcBmp.Height - 1 の場合then SrcNextRGB:=SrcBmp.ScanLine[i+1] else SrcNextRGB:=SrcBmp.ScanLine[i]; for j := 0 to SrcBmp.Width - 1 do begin if j > 0 then DecRGB; .rgbtRed+SrcNextRGB.rgbtRed; if j > 0 の場合、IncRGB; 値:=Value+SrcPreRGB.rgbtRed+SrcRGB.rgbtRed+SrcNextRGB.rgbtRed; j < SrcBmp.Width - 1 の場合、IncRGB; 値:=(Value+SrcPreRGB.rgbtRed+SrcRGB.rgbtRed+SrcNextRGB.rgbtRed)ディビジョン9; DecRGB; SrcRGB.rgbtRed:=value; j > 0 の場合 DecRGB; j > 0 の場合 Value:=SrcRGB.rgbtGreen+SrcNextRGB;値:=Value+SrcPreRGB.rgbtGreen+SrcRGB.rgbtGreen+SrcNextRGB.rgbtGreen; j < SrcBmp.Width - 1 の場合、IncRGB; 値:=(Value+SrcRGB.rgbtGreen+SrcNextRGB.rgbtGreen) div 9; ; SrcRGB.rgbtGreen:=value; j>0 の場合、Value:=SrcPreRGB.rgbtBlue+SrcRGB.rgbtBlue+SrcNextRGB.rgbtBlue; j>0 の場合、Value:=Value+SrcRGB.rgbtBlue+SrcNextRGB .rgbtBlue; j < の場合SrcBmp.Width - 1 then IncRGB; Value:=(Value+SrcPreRGB.rgbtBlue+SrcNextRGB.rgbtBlue) div 9; end;end; Sharpen(SrcBmp:TBitmap);var i, j:整数; SrcRGB: pRGBTriple; SrcPreRGB: pRGBTriple; 値: integer;begin SrcBmp.PixelFormat:=pf24Bit; for i := 0 to SrcBmp.Height - 1 if i > 0 SrcPreRGB:=SrcBmp.ScanLine[i-1] else SrcPreRGB:=SrcBmp.ScanLine[i]; for j := 0 to SrcBmp.Width - 1 do begin if j = 1 then Dec(SrcPreRGB); rgbtRed+(SrcRGB.rgbtRed-SrcPreRGB.rgbtRed) div 2; 値:= 最小(255,値); 値:=SrcRGB.rgbtGreen+(SrcRGB.rgbtGreen-SrcPreRGB.rgbtGreen) 値:=最大(0,値); 値:=最小(255,値); SrcRGB.rgbtGreen:=値; 値:=SrcRGB.rgbtBlue-SrcPreRGB.rgbtBlue) 値:=最大(0,値);値; Inc(SrcPreRGB); 終了; [画像の回転と反転] 次のコードは、24 ビット カラー用にポインタの移動を伴う ScanLine を使用して実装されています。 //90 度回転する手続き Rotate90(const Bitmap:TBitmap);var i,j:Integer; rowIn,Height:Integer;begin Bmp:=TBitmap.Create;ビットマップ.高さ := ビットマップ.ピクセル形式 := pf24bit; width:=Bitmap.Width-1; height:=Bitmap.Height-1; for j := 0 to begin rowIn := Bitmap.ScanLine[j]; for i := 0 to width do begin rowOut : = Bmp.ScanLine[i]; 行アウト^ := 行イン^; Bitmap.Assign(Bmp);end;//180 度回転プロシージャ Rotate180(const Bitmap:TBitmap);var i,j:Integer; rowIn,rowOut:pRGBTriple; Bmp:TBitmap; TBitmap.Create; Bmp.Width := ビットマップ.Height := Bitmap.Height; Bmp.PixelFormat := pf24bit; Height:=Bitmap.Height-1; for j := Bitmap.ScanLine[j]; := 0 から幅が始まります rowOut := Bmp.ScanLine[Height - j] Inc(rowOut,Width - i); rowOut^ := rowIn^; end Bitmap.Assign(Bmp);end; // 270 度回転する手続き Rotate270(const Bitmap:TBitmap); var i,j:Integer; pRGBTriple; Bmp:TBitmap; 幅、高さ:整数; Bmp:=TBitmap.Create; := Bitmap.Height := Bitmap.Width; Bmp.PixelFormat := pf24bit; j := 高さの開始:= Bitmap.ScanLine[j]; for i := 0 ~ width do begin rowOut := Bmp.ScanLine[Width - i]; Inc(rowOut,j); rowOut^ := rowInc(rowIn); //任意の角度関数 RotateBitmap: TBitmap;Angle:Integer;BackColor:TColor):TBitmap;var i,j,iOriginal,jOriginal,CosPoint,SinPoint:整数; RowOriginal、RowRotated : pRGBTriple; AngleAdd : integer;begin Result.PixelFormat := pf24bit; Angle:=Angle Mod 360 ; 角度<0の場合Angle:=360-Abs(Angle); if Angle=0 then Result.Assign(Bitmap) else if Angle=90 then begin Result.Assign(Result); // 90 度回転した場合は、上記のコードは直接終了します。そうでない場合、(Angle>90) および (Angle<180) の場合、AngleAdd:=90 が開始されます。 Angle:=Angle-AngleAdd; end else if Angle=180 then begin Result.Assign(Bitmap); //180 度回転した場合は、上記の処理を直接呼び出しますend if (Angle>180) and ( Angle<270) 開始 AngleAdd:=180; Angle:=Angle-AngleAdd end else if Angle=270 then begin; Result.Assign(Bitmap); // 270 度回転した場合は、上記の処理を直接呼び出します。 end else if (Angle>270) and (Angle<360) then begin AngleAdd:=270;角度 -AngleAdd; end else AngleAdd:=0; if (Angle>0) and (Angle<90) then begin SinCos((Angle) + AngleAdd) * Pi / 180, SinTheta, CosTheta); if (SinTheta * CosTheta) < 0 then begin Result.Width := Round(Abs(Bitmap.Width * CosTheta - Bitmap.Height * SinTheta)); = Round(Abs(Bitmap.Width * SinTheta - Bitmap.Height * CosTheta)); end else begin Result.Width := Round(Abs(Bitmap.Width * CosTheta + Bitmap.Height * SinTheta)); Result.Height := Round(Abs(Bitmap.Width * SinTheta + Bitmap.Height * CosTheta)); ; CosTheta:=Abs(CosTheta); (AngleAdd=0) または (AngleAdd=180) then begin CosPoint:=Round(Bitmap.Height*CosTheta); else begin SinPoint:=Round(Bitmap.Width*CosTheta); ); CosPoint:=Round(Bitmap.Width*SinTheta); for j := 0 Result.Height-1 do begin RowRotated := Result.Scanline[j]; for i := 0 to Result.Width-1 do begin Case AngleAdd of 0: begin jOriginal := Round((j+1)*CosTheta-( i+1-SinPoint)*SinTheta)-1; Round((i+1)*CosTheta-(CosPoint-j-1)*SinTheta)-1; 90: begin iOriginal := Round((j+1)*SinTheta-(i+1-SinPoint)*CosTheta )-1; jOriginal := Bitmap.Height-Round((i+1)*SinTheta-(CosPoint-j-1)*CosTheta);終了; 180: 開始 jOriginal := Bitmap.Height-Round((j+1)*CosTheta-(i+1-SinPoint)*SinTheta); iOriginal := Bitmap.Width-Round((i+1)*CosTheta- (CosPoint-j-1)*SinTheta); 270: 開始 iOriginal := Bitmap.Width-Round((j+1)*SinTheta-(i+1-SinPoint)*CosTheta); jOriginal := Round((i+1)*SinTheta-(CosPoint-j-1)*CosTheta)-1 ; 終了; if (iOriginal >= 0) および (iOriginal <= Bitmap.Width-1) および (jOriginal >= 0) (jOriginal <= Bitmap.Height-1) then begin RowOriginal := Bitmap.Scanline Inc(RowOriginal,iOriginal); end else begin Inc(RowRotated); ; end; end;end;//水平反転プロシージャ FlipHorz(const Bitmap:TBitmap); i,j:Integer; rowIn,rowOut:pRGBTriple; Bmp:TBitmap.Create; Bmp:= ビットマップ.幅 := ビットマップ。ピクセルフォーマット:= pf24bit 幅:= ビットマップ.幅-1; Height:=Bitmap.Height-1; for j := 0 to Height do begin rowIn := Bitmap.ScanLine[j]; for i := 0 to width do begin rowOut := Bmp.ScanLine Inc(rowOut) ,Width - i); rowOut^ := rowIn^; Bitmap.Assign(Bmp);//垂直反転プロシージャFlipVert(const Bitmap:TBitmap);var i,j:Integer;rowIn,rowOut:pRGBTriple;幅,高さ:整数;begin Bmp:=TBitmap.Width := Bitmap.Height;高さ := ビットマップ.幅 := pf24bit; width:=Bitmap.Width-1; Height:=Bitmap.Height-1; for j := 0 to Height do begin rowIn := Bitmap.ScanLine[j]; for i := 0 to width do begin rowOut := Bmp .ScanLine[高さ - j]; rowOut^ := rowIn^; Bitmap.Assign(Bmp);end;【明るさ、コントラスト、彩度の調整】 以下のコードはポインタ移動付きのScanLineを使って実装しています! function Min(a, b: integer): 整数;begin if a < b then result := a else result := b;end;function Max(a, b: integer): integer;begin if a > b then result : = a else result := b;end;//明るさ調整手順 BrightnessChange(const SrcBmp,DestBmp:TBitmap;ValueChange:integer);var i, j: integer; SrcRGB、DestRGB: pRGBTriple; 開始 for i := 0 ~ SrcBmp.Height - 1 開始 SrcRGB := SrcBmp.ScanLine[i]; := DestBmp.ScanLine[i] for j := 0 ~ SrcBmp.Width - 1 ValueChange > 0 の場合に開始し、DestRGB.rgbtRed を開始します := Min(255, SrcRGB.rgbtRed + ValueChange); DestRGB.rgbtGreen := Min(255, SrcRGB.rgbtBlue + ValueChange); DestRGB.rgbtBlue := Min(255, SrcRGB.rgbtBlue + ValueChange); =最大(0, SrcRGB.rgbtRed + ValueChange); DestRGB.rgbtGreen := Max(0, SrcRGB.rgbtBlue + ValueChange); ; end; end;end;//コントラスト調整手順ContrastChange(const SrcBmp,DestBmp:TBitmap;ValueChange:integer);var i, j: integer; SrcRGB, DestRGB: pRGBTriple;begin for i := 0 to SrcBmp.Height - 1 do begin SrcRGB := SrcBmp.ScanLine[i] ; DestRGB := DestBmp.ScanLine[i]; := 0 ~ SrcBmp.Width - 1 ValueChange>=0 の場合に開始し、SrcRGB.rgbtRed >= 128 の場合に開始し、DestRGB.rgbtRed := Min(255, SrcRGB.rgbtRed + ValueChange) else DestRGB.rgbtRed := Max(0 、SrcRGB.rgbtRed - ValueChange); SrcRGB.rgbtGreen >= 128 then DestRGB.rgbtGreen := Min(255, SrcRGB.rgbtGreen + ValueChange) else DestRGB.rgbtGreen := Max(0, SrcRGB.rgbtGreen - ValueChange) if SrcRGB.rgbtBlue >= 128 then DestRGB.rgbtBlue := Min(255, SrcRGB.rgbtBlue + ValueChange) else DestRGB.rgbtBlue := Max(0, SrcRGB.rgbtBlue - ValueChange); end else begin if SrcRGB.rgbtRed >= 128 then DestRGB.rgbtRed := Max(128, SrcRGB.rgbtRed) + ValueChange) その他DestRGB.rgbtRed := Min(128, SrcRGB.rgbtRed - ValueChange); if SrcRGB.rgbtGreen >= 128 then DestRGB.rgbtGreen := Max(128, SrcRGB.rgbtGreen + ValueChange) else DestRGB.rgbtGreen := Min(128, SrcRGB .rgbt緑 - ValueChange); if SrcRGB.rgbtBlue >= 128 then DestRGB.rgbtBlue := Max(128, SrcRGB.rgbtBlue + ValueChange) else DestRGB.rgbtBlue := Min(128, SrcRGB.rgbtBlue - ValueChange); Inc(DestRGB); end;end;//彩度調整手順 SaturationChange(const SrcBmp,DestBmp:TBitmap;ValueChange:integer);var Grays: array[0..767] of Integer; Alpha: array[0..255] of Word Gray , x、y: 整数; SrcRGB、DestRGB: pRGBTriple; Byte;beginValueChange:=ValueChange+255;for i := 0 ~ 255 do Alpha[i] := (i * ValueChange) Shr 8;x := 0;for i := 0 ~ 255 dobegin Gray := i - Alpha [i]; グレー[x] := グレー; グレー[x] := グレー; Inc(x);end; for y := 0 to SrcBmp.Height - 1 dobegin SrcRGB := SrcBmp.ScanLine[Y]; for x := 0 to SrcBmp.Width - 1グレーを開始します := Grays[SrcRGB.rgbtRed + SrcRGB.rgbtGreen + SrcRGB.rgbtBlue]; if Gray + Alpha[SrcRGB.rgbtRed]>0 then DestRGB.rgbtRed := Min(255,Gray + Alpha[SrcRGB.rgbtRed]) else DestRGB.rgbtRed := 0 if Gray + Alpha[SrcRGB. rgbtGreen]>0 の場合 DestRGB.rgbtGreen := Min(255,Gray + Alpha[SrcRGB.rgbtGreen]) else DestRGB.rgbtGreen := 0; if Gray + Alpha[SrcRGB.rgbtBlue]>0 then DestRGB.rgbtBlue := Min(255,Gray + Alpha[SrcRGB.rgbtBlue]) ) else DestRGB.rgbtBlue := 0; Inc(DestRGB); end;end; end;//RGB 調整手順 RGBChange(SrcBmp,DestBmp:TBitmap;RedChange,GreenChange,BlueChange:integer);var SrcRGB, DestRGB: pRGBTriple;begin for i : = 0 から SrcBmp.Height-1 で SrcRGB が始まります := SrcBmp.ScanLine[i]; DestRGB :=DestBmp.ScanLine[i]; for j := 0 to SrcBmp.Width - RedChange> 0 then DestRGB.rgbtRed := Min(255, SrcRGB.rgbtRed + RedChange)それ以外の場合 DestRGB.rgbtRed := Max(0, SrcRGB.rgbtRed + RedChange); if GreenChange> 0 then DestRGB.rgbtGreen := Min(255, SrcRGB.rgbtGreen + GreenChange) else DestRGB.rgbtGreen := Max(0, SrcRGB.rgbtGreen + GreenChange); if BlueChange> 0 then DestRGB .rgbtBlue := Min(255, SrcRGB.rgbtBlue + BlueChange) else DestRGB.rgbtBlue := Max(0, SrcRGB.rgbtBlue + BlueChange) Inc(DestRGB); [色調整]//RGB<=>BGRprocedure RGB2BGR(const ビットマップ:TBitmap);var X: 整数 Y: 整数; pRGBTriple; カラー: バイト;Y の開始 := 0 から (Bitmap.Height - 1) の開始 X := 0 から (Bitmap.Width - 1) の開始 カラー := PRGB^.rgbtRed : = PRGB^.rgbtBlue; PRGB^.rgbtBlue := カラー終了; end;end;//グレースケール (重み付け) プロシージャ Grayscale(const Bitmap:TBitmap);var X: 整数; Y: 整数; PRGB: pRGBTriple; グレー: Byte;begin for Y := 0 to (Bitmap.Height - 1) do begin PRGB := Bitmap.ScanLine[Y]; for X := 0 to (Bitmap.Width - 1) do begin Gray := (77 * 赤 + 151 * 緑 + 28 * 青) shr 8; PRGB^.rgbtGreen:=Gray; end; ;
理論:
キーワード:
描画領域 - つまり、ウィンドウが画像を表示する領域で、全画面にすることもできます (描画効果は一般のウィンドウよりも全画面の方が優れています)。
中心点 - 元のイメージの描画領域に表示される中心点の座標 (免責事項: この概念は特に重要です)
まず画像を拡大する場合、画像を直接拡大するのが一般的ですが、この記事で紹介する方法では、拡大する場合は 2 通りあります。拡大すると描画領域よりも大きくなりますが、この状態では何も表示されません。画像; 2 番目は、拡大された画像が描画領域よりも大きいということです。これが今日説明する重要なトピックです。まず、拡大された画像のサイズを決定し、次に、そのサイズを計算する必要があります。 「中心点」の位置と大きさに基づいて元の画像を描画し、最後にキャプチャした画像を描画領域に拡大します。
画像のローミングについて話しましょう。表示された画像が描画領域を超える場合、画像全体を表示するために画像をローミングする必要があります。原理は、描画領域内でマウスをクリックするとローミングを開始し、まずマウスのクリック位置を記録し、次にマウスの動きを検出して、マウスと最後の変位に基づいて「中心点」を計算します(画面座標を元の画像座標に変換し、上記の拡大の原理に従って元の画像から表示したい部分を取り出し、描画エリアに拡大して表示します。
アルゴリズムの実装:
1. 画像の拡大
変数の定義:
PZoom: 拡大率 (整数: 100 を使用した場合は 100%、必要に応じて 100 を 10000 以上に変更できますが、浮動小数点数は推奨しません)
a、b: 中心点
w、h: キャプチャする元の画像の幅と高さ
x、y: インターセプトする位置 (左上隅)
sw,sh: 元の画像の幅と高さ
p1、p2:倍率
aw,ah: 拡大画像のサイズ
pw,ph: 描画領域サイズ
vx,vy: 作図領域に表示される位置(左上隅)
vw、vh: 作図領域に表示されるサイズ
ptx、pty: 一時変数
既知の変数: PZoom、(a、b)、(sw、sh)、(p1、p2)、(aw、ah)、(pw、ph)
計算する変数: (x,y)、(w,h)、(vx,vy)、(vw,vh)
計算を開始します:
aw=Round(PZoom*sw/100);ah=Round(PZoom*sh/100);p1=aw/pwp2=ah/ph// 注: Round は、Int()、Fix などの丸めに使用されます。言語 ()etc if p1>1 then w=Round(sw/p1) else w=swif p2>1 then h=Round(sh/p2) else h=sh// 注: shr は右シフト演算子です。x=aw shr 1y=bh の代わりに、「>>1」、「div 2」、「/2」、または「Round(w/2)」を使用できます。 shr 1 // 注: div は整数の除算演算子です ptx=(w*PZoom) div 100pty=(h*PZoom) div 100//以下は描画領域に表示される画像のサイズと位置を計算します。
変数
Pencent:double; // ズーム率 wx:double; // ワイド ズーム率 hx:double; // ズーム率 wx:=pw/ptx hx:=ph/pty if wx>hx then Pencent: =hx else Pencent:=wx; // 画像の最終サイズを取得します vw:=Round(Pencent*ptx); //画像の位置を計算する vx:=(pw-vw) div 2; vy:=(ph-vh) div 2;// -------------------- - ---------------
さて、2 つの重要なタスクが完了しました (x, y)、(w, h)、(vx, vy)、(vw, vh) が計算されました。次の操作を実行するために Windows API を選択します。
変数
sDC は元のピクチャのデバイス ハンドル (DC) です。 tDC は一時的なデバイス ハンドル dDC であり、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);
最後に、表示された領域に描画します。
例えば:
BitBlt(GetDC(0),vx,vy,vx+vw,xy+vh,dDC,0,0,SRCCOPY);
2.画像ローミング
まず、3 つのグローバル変数を定義します。
FBeginDragPoint :TPoint; // マウスがドラッグを開始した位置を記録します FBeginDragSBPoint :TPoint; // 「中心点」の位置を記録します FBeginDrag :boolean // 「ドラッグ」a、b が開始されたかどうか: integer; " 位置
マウスの左ボタンがクリックされたときに、マウスの位置と「中心点」の位置を記録し、FBeginDrag を true に設定します。
マウスの右ボタンがポップアップしたら、FBeginDrag を false に設定します。
マウスが移動した場合、FBeginDrag が false であると判定され、true の場合は次の処理が行われます。
X と Y がマウスの現在位置であると仮定します。
a=FBeginDragPoint.X-((X-FBeginDragPoint.X)*100) div PZoomb=FBeginDragPoint.Y-((Y-FBeginDragPoint.Y)*100) div PZoom
最後に、上で紹介した画像を使って拡大表示してみましょう
ヒント:
1. 画像が大きい場合、delphi のビットマップ オブジェクトを使用するとメモリ オーバーフロー エラーが発生します。この場合、次の設定を行うことができます。
bitImage:=TBitmap.Create; bitImage.PixelFormat:=pf24bit;
2. 画像をウィンドウのサイズに自動的に合わせたい場合は、次のコードを参照してください。
var p1,p2 :double;begin p1:=pw/sw; p2:=ph/sw; if p1>p2 then PZoom:=Round(p2*100) else PZoom:=Round(p1*100); 0 の場合は PZoom:=100;end;
Delphi グレースケール画像のピクセルの色の明るさの処理
画像処理はスピードが重要です。したがって、TVczhBitmap を取得するには、TBitmap を再処理する必要があります。これは、GetPixels と SetPixels が遅すぎるためです。別の方法を使用してください。
ユニット untBitmapProc; インターフェイスは Graphics、SysUtils を使用します; タイプ TVczhBitmap=class(TBitmap); プロシージャ SetBytePointer(X,Y:Integer):PByte; :Byte); 関数 GetBytes(X,Y:Integer):Byte; public property Bytes[X,Y:Integer]:Byte ReadBytes write SetBytes; プロシージャ LoadFromFile(FileName:String) プロシージャ ToGray; begin HandleType:=bmDIB; TVczhBitmap.GetBytePointer(X,Y:Integer):PByte if Line<>Y then; begin Line:=ScanLine[Y]; end; Longint(result):=Longint(Data)+X; begin GetBytePointer() X,Y)^:=値終了;関数TVczhBitmap.GetBytes(X,Y:Integer):バイト; result:=GetBytePointer(X,Y)^; コンストラクター TVczhBitmap.Create を開始します。 ; 行:=-1; プロシージャ TVczhBitmap.ToGray; B:Byte; Y:=0 から高さ-1 で開始 X:=0 から幅-1 で開始 R:=0 で開始; B:=0 から 2 で R:=R+GetBytes(X*3+) B,Y); B:=0 ~ 2 の場合は SetBytes(X*3+B,Y,R div 3) を終了します。
この後、いくつかのフォームを作成する必要があります。最初のフォームは画像を表示するために使用され、2 番目のフォームは画像を処理するために使用されます。他のすべてのフォームは 2 番目のフォームを継承し、実際の処理メソッドを含みます。
まず 2 番目のウィンドウを見てみましょう。
ユニット untProc; インターフェイスは Windows、メッセージ、SysUtils、バリアント、クラス、グラフィックス、コントロール、フォーム、ダイアログ、ExtCtrls、untBitmapProc、StdCtrls、ComCtrls を使用します。プロシージャ FormCreate(送信者: TObject); プロシージャ FormShow(Sender: TObject); プロシージャ Button1Click(Sender: TObject); ..255] バイト; var frmProcessor: TfrmProcessor;実装 {$R *.dfm} は untViewer を使用します; var I:Integer; begin Bar.Canvas.FillRect(Bar.Canvas.ClipRect); I:=1 ~ 255 do Bar.Canvas.LineTo(I,255-BarData[I]); TfrmProcessor.FormCreate(Sender: TObject); Bar.Width:=256; Bar.Canvas.Brush.Style: =bsSolid; 終了; プロシージャ TfrmProcessor.FormDestroy(送信者: TObject);終了; プロシージャ TfrmProcessor.FormShow(Sender: TObject); var I:Integer; do BarData[I]:=I; プロシージャ TfrmProcessor.pbBarPaint(Sender: TObject); .Canvas.Draw(0,0,Bar); プロシージャ TfrmProcessor.Button1Click(Sender: TObject); var X,Y:Integer; begin for Y:=0 to Buffer.Height-1 do for X:=0 to Buffer.Width*3-1 do Played.Bytes[X,Y]:=BarData[Buffer.Bytes[ X,Y]]; frmViewer.FormPaint(frmViewer) 終了;
その後、それを継承するウィンドウを作成し、BarData[] を調整して [Apply] を押して結果を確認します。
画像の処理を開始します。具体的な効果についてはサンプルプログラムをご覧ください。
1. 色の反転。
グレースケール イメージの色の範囲は 0 ~ 255 であるため、色を反転するには、255 から色の値を減算して反転した色を取得します。
var I:Integer; for I:=0 to 255 do BarData[I]:=255-I;// 255 から色の値を減算します pbBarPaint(pbBar);
2. 色の範囲を狭めて明るさを強めたり弱めたりします
カラーは本来0~255です。たとえば 0 から 16 まで範囲を調整すると、画像は大幅に暗くなります。開始値を a、終了値を b に設定し、新しい色の値 New=a+(b-1)*Old/255 を設定できます。これを行うと、元のカラーシーケンスを破壊することなく明るさが変更されます。コードは次のとおりです
var I:Integer; I の開始:=0 ~ 255 do BarData[I]:=(255-sbMin.Position)+Round((sbMin.Position-sbMax.Position)/255*I); ); Button1Click(ボタン1);
ここでの sbMin.Position と sbMaxPosition は両方とも反転されています。したがって、減算するには 255 を使用します。
3. 特定の範囲内で色の範囲を増やす
画像自体の色の範囲が狭い場合、この方法を使用して画像のコントラストを高めることができ、画像の分析に役立ちます。具体的な方法:
開始値として値 a を選択し、終了値として値 b を選択し、次の式に従って変形します。
| 0 (X<=a)
f(X)= | 255/(ba)*(Xa)
| 255(X>=b)
var I:Integer; begin for I:=0 to 255 do begin if I<=sbMin.Position then BarData[I]:=0 else if I>=sbMax.Position then BarData[I]:=255 else BarData[I ]:=Round(255/(sbMax.Position-sbMin.Position)*(I-sbMin.Position)); pbBarPaint(pbBar); Button1Click(Button1);
4.白黒写真に変換する
3 番目の関数を使用すると、b<=a の場合、画像上の色は黒を除いて白であることがわかります。この操作の利点を直接示すことはできません。これは、エッジ検出などのより高度な画像処理の場合にのみ有効です。この例は、3 番目の方法の公式を使用して変換できるため、詳細は説明しません。
5. 指数関数的な明るさ調整
このグラフの定義域は [0,1] であり、値の範囲も [0,1] であると仮定します。次に、関数 f(x)=x^c を定義すると、f(x) の画像は上に示すようなセクションを持ちます。マウスを使用して再び動作する場合、ポイントP(a、b)を使用してから、f(x)をポイントpを通過させ、c = ln(b)/ln(a)に通過できます。 Cを使用すると、色で動作できます。
new =(old/255)^c*255 = exp(old/255)*255 var ea、ec:exted ea:= b /255; Bardata [i] = exp((i/255))*255);
これを行うと、画像の明るさが調整されます。
Delphiグラフィックスに特殊効果を表示するためのヒント
概要
----現在、多くの学習ソフトウェアとゲームのCDで、さまざまなものを見ることができます
グラフィックディスプレイテクノロジーは、ムーブメント、インターレース、レインドロップシェイプ、ブラインド、ビルディングブロックスタッキング、その他のグラフィックスのディスプレイ方法に依存して、写真をより活気に満ちた魅力的にします。この記事では、Delphiにさまざまなグラフィックディスプレイテクニックを実装する方法について説明します。
基本原則
---- Delphiでは、画像を表示するのは非常に簡単です。その形式のティマージコンポーネントを設定し、有効な.ico、.bmp、.emfまたは.wmfファイル、ロード、ロード、選択したファイルは、タイムコンポーネントに表示されます。しかし、これはグラフィックを形式で直接表示するだけで、スキルはまったくありません。グラフィックディスプレイをユニークな効果にするために、次の手順に従うことができます。
----タイムコンポーネントを定義し、グラフィックスをティマージコンポーネントに表示します。つまり、グラフィックコンテンツをディスクからメモリにグラフィカルキャッシュとしてロードします。
----新しいグラフオブジェクトを作成すると、サイズはタイムコンポーネントの図と同じです。
----キャンバスの株式関数を使用します(あるキャンバスの長方形の領域を別のキャンバスの長方形の領域にコピーします)、スキル、ダイナミックな形状、ダイナミックな形状、ダイナミックな形状を使用します
グラフの内容が作成され、ビットマップがウィンドウに表示されます。
----実装方法
以下は、さまざまなグラフィックスの表示スキルを紹介します。
1。プッシュ効果
表示されるグラフは、上部、左、および正しい方向から画面に引き込まれます上記のプル効果も同様です。
原則:最初に、一時的なグラフィックの最初の水平線を置き、最後のグラフィックに移動してから、一時的なグラフィックの最初の2つの水平線を最後の2つに移動して、ビットマップを表示します。次に、すべてのグラフィックデータが移動されるまで、最初の3つと最初の4つを移動します。移動の過程で、表示されているビットマップフロートが下から上に浮かんでいることを確認して、引き上げる効果を実現できます。
プログラムアルゴリズム:
手順TFORM.SENDER:TOBMP:bmpwidth:= tbitmap.create; Image1.height; i:= 0からnewbmp.canvas.copyrect(rect(0、bmpheight-i、bmpwidth、bmpheight)、image1.canvas、rect(0,0、bmpwidth、i)); ); newbmp.free;
2。垂直のずらして効果
原則:グラフィックを2つの部分に表示するように要求します。奇数のスキャンラインは上から下に移動し、均一なスキャンラインの部分は下から上に移動し、2つは同時に実行されます。画面からは、上端と下端から表示される軽いグラフィックが、完全に透明になるまで画面の中央に移動されることがわかります。
プログラムアルゴリズム:
手順TFORM.VUTER:tbitmap:bmpwidth:= tbitmap.create; := image1.height; i:= 0; +j-1、bmpwidth、bmpheight-i+j); (0、bmpheight-j、bmpwidth、bmpheight-j+1)、image1.canvas(0、ij、bmpwidth、i-j+1); 、newbmp);
3。水平方向のずらされた効果
原理:垂直インターレース効果の原理と同様に、2つのグループに分割されたグラフィックは、左端と右端から画面に移動します。
プログラムアルゴリズム:
手順TFORM.VIRCTMAP:j、bmpwidth:= tbitmap.create; := image1.height; i:= 0; i+j-1,0、bmpwidth-i+j、bmpheight); (bmpwidth-j、0、bmpwidth-j+1、bmpheight)、canvas、rect(ij、i-j+1、bmpheight); 、newbmp);
4。雨の落下効果
原則:一時的なグラフィックの最後のスキャンラインは、視覚マップの最初の記事に最後のスキャンラインに順番に移動されるため、このスキャンラインは画面上にその軌跡を残します。次に、一時的なグラフィックスのカウントダウンの2番目のスキャンラインが、最初に最後から2番目のスキャンラインに移動して、最初に最後から2番目のグラフに移動します。残りのスキャンラインは、これに従ってプッシュされます。
プログラムアルゴリズム:
手順TFORM.SENDER:TOBMP:bmpwidth:= tbitmap.create; := image1.height; i:= bmpheight to 1 to j:= 1 to begin newbmp.canvas.copyrct(rect(0、j-1、bmpwidth、j)、image1.canvas、rect(0、i-1、bmpwidth、 bmpwidth、form1.draw(120,100、newbmp.
5。ルーバーウィンドウの効果
原則:一時的なグラフィックに配置されるデータは、いくつかのグループに分割され、最初のグループから最初のグループが最初のスキャンラインを目に見える図の対応する位置に最初に移動します。 、2回目のスキャンラインを移動してから、3番目と4番目のスキャンラインを移動します。
プログラムアルゴリズム:
手順TFORMS6CLICK(TOBMP) Image1.height; bmpwidth:= image1。 、xcount*j+i)、image1.canvas、 rect(xcount*j+i-1、xcount*j+i);
6.ビルディングブロック効果
原則:雨滴の効果の変化です。
プログラムアルゴリズム:
手順TFORM.SENDER:TOBMP:bmpwidth:integer:= image1.width; := image1.height; i:= bmpheight; 、bmpwidth、form.draw(120,100、終わり;
結論
上記のグラフィックディスプレイ効果は、マシンで渡されました。効果はとても良いです。
Delphiを使用して、画像の拡大ガラスを実現します
ウィンドウに2つのタイムコンポーネントを追加します。別のタイムコンポーネントの名前プロパティは、拡大した画像を表示できるImage2に設定されています。
この例のコアは、stretenblt関数を使用してローカル画像の拡大を実現します。
手順tform1.image1mousemove(sender:tobject:tashiftstate; x、y:integer); screen.cursors [1]:= loadcursorfromfile( 'magnify.cur');
このプログラムは、最初にストレッチブラット関数を呼び出し、マウスの現在の位置を中心点として使用し、40のサイド長を持つImage1コンポーネント上のローカル画像を選択し、このローカル画像をImage2コンポーネントに増幅します。次に、Image2コンポーネントの更新方法を呼び出して、Image2コンポーネントの表示を更新します。最後に、マウスポインターを新しい形状に設定します。
プログラムコードは次のとおりです。
ユニットユニット1; :整数); formmousemove(tobject; shift:tashiftstate; x、y:integer); tobject; beginstretchblt(image2.canvas.handle、0,0、image2.height、image1.canvas.handle、x-20、40,40、srccopy [1]:= loadcursorfromfile; ( 'magnify.cur'); self.cursor:= 1。
ファイルを保存し、F9キーを押してプログラムを実行し、プログラムを実行します。
アプリケーション画像は、画像ソフトウェアを見るための優れた機能です。
この記事が皆さんの Delphi プログラミングに役立つことを願っています。