Delphi基本图像处理方法汇总

本文实例汇总了Delphi基本图像处理方法。分享给大家供大家参考。具体分析如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
//浮雕
procedure 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 to SrcBmp . Height - 1 do
  begin
   SrcRGB := SrcBmp . ScanLine[i];
   DestRGB := DestBmp . ScanLine[i];
   if (AzimuthChange >= - 180 ) and (AzimuthChange < - 135 ) then
   begin
    if i > 0 then
     SrcRGB1 := SrcBmp . ScanLine[i- 1 ]
    else
     SrcRGB1 := SrcRGB;
    Inc(SrcRGB1);
    SrcRGB2 := 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);
   end
   else if (AzimuthChange >= - 90 ) and (AzimuthChange < - 45 ) then
   begin
    if i > 0 then
     SrcRGB1 := SrcBmp . ScanLine[i- 1 ]
    else
     SrcRGB1 := SrcRGB;
    SrcRGB2 := SrcRGB1;
   end
   else if (AzimuthChange >= - 45 ) and (AzimuthChange < 0 ) then
   begin
    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;
    if (i < SrcBmp . Height - 1 ) then
     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 ]
    else
     SrcRGB1 := SrcRGB;
    SrcRGB2 := SrcRGB1;
   end
   else if (AzimuthChange >= 90 ) and (AzimuthChange < 135 ) then
   begin
    if (i < SrcBmp . Height - 1 ) then
     SrcRGB1 := SrcBmp . ScanLine[i+ 1 ]
    else
     SrcRGB1 := SrcRGB;
    SrcRGB2 := SrcRGB1;
    Inc(SrcRGB1);
   end
   else if (AzimuthChange >= 135 ) and (AzimuthChange <= 180 ) then
   begin
    if (i < SrcBmp . Height - 1 ) then
     SrcRGB2 := SrcBmp . ScanLine[i+ 1 ]
    else
     SrcRGB2 := SrcRGB;
    Inc(SrcRGB2);
    SrcRGB1 := SrcRGB;
    Inc(SrcRGB1);
   end ;
   for j := 0 to SrcBmp . Width - 1 do
   begin
    if (AzimuthChange >= - 180 ) and (AzimuthChange < - 135 ) then
    begin
     Azimuthvalue := AzimuthChange + 180 ;
     R:=SrcRGB . rgbtRed-((SrcRGB1 . rgbtRed)*Azimuthvalue div 45 )-((SrcRGB2 . rgbtRed)*( 45 -Azimuthvalue) div 45 )+ 78 ;
     G:=SrcRGB . rgbtGreen-((SrcRGB1 . rgbtGreen)*Azimuthvalue div 45 )-((SrcRGB2 . rgbtGreen)*( 45 -Azimuthvalue) div 45 )+ 78 ;
     B:=SrcRGB . rgbtBlue-((SrcRGB1 . rgbtBlue)*Azimuthvalue div 45 )-((SrcRGB2 . rgbtBlue)*( 45 -Azimuthvalue) div 45 )+ 78 ;
    end
    else if (AzimuthChange >= - 135 ) and (AzimuthChange < - 90 ) then
    begin
     Azimuthvalue := AzimuthChange + 135 ;
     R:=SrcRGB . rgbtRed-((SrcRGB1 . rgbtRed)*Azimuthvalue div 45 )-((SrcRGB2 . rgbtRed)*( 45 -Azimuthvalue) div 45 )+ 78 ;
     G:=SrcRGB . rgbtGreen-((SrcRGB1 . rgbtGreen)*Azimuthvalue div 45 )-((SrcRGB2 . rgbtGreen)*( 45 -Azimuthvalue) div 45 )+ 78 ;
     B:=SrcRGB . rgbtBlue-((SrcRGB1 . rgbtBlue)*Azimuthvalue 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 );
     Azimuthvalue := AzimuthChange + 90 ;
     R:=SrcRGB . rgbtRed-((SrcRGB1 . rgbtRed)*Azimuthvalue div 45 )-((SrcRGB2 . rgbtRed)*( 45 -Azimuthvalue) div 45 )+ 78 ;
     G:=SrcRGB . rgbtGreen-((SrcRGB1 . rgbtGreen)*Azimuthvalue div 45 )-((SrcRGB2 . rgbtGreen)*( 45 -Azimuthvalue) div 45 )+ 78 ;
     B:=SrcRGB . rgbtBlue-((SrcRGB1 . rgbtBlue)*Azimuthvalue div 45 )-((SrcRGB2 . rgbtBlue)*( 45 -Azimuthvalue) div 45 )+ 78 ;
    end
    else if (AzimuthChange >= - 45 ) and (AzimuthChange < 0 ) then
    begin
     if j= 1 then
     begin
      Inc(SrcRGB1,- 1 );
      Inc(SrcRGB2,- 1 );
     end ;
     Azimuthvalue := AzimuthChange + 45 ;
     R:=SrcRGB . rgbtRed-((SrcRGB1 . rgbtRed)*Azimuthvalue div 45 )-((SrcRGB2 . rgbtRed)*( 45 -Azimuthvalue) div 45 )+ 78 ;
     G:=SrcRGB . rgbtGreen-((SrcRGB1 . rgbtGreen)*Azimuthvalue div 45 )-((SrcRGB2 . rgbtGreen)*( 45 -Azimuthvalue) div 45 )+ 78 ;
     B:=SrcRGB . rgbtBlue-((SrcRGB1 . rgbtBlue)*Azimuthvalue div 45 )-((SrcRGB2 . rgbtBlue)*( 45 -Azimuthvalue) div 45 )+ 78 ;
    end
    else if (AzimuthChange >= 0 ) and (AzimuthChange < 45 ) then
    begin
     if j= 1 then
     begin
      Inc(SrcRGB1,- 1 );
      Inc(SrcRGB2,- 1 );
     end ;
     Azimuthvalue := AzimuthChange;
     R:=SrcRGB . rgbtRed-((SrcRGB1 . rgbtRed)*Azimuthvalue div 45 )-((SrcRGB2 . rgbtRed)*( 45 -Azimuthvalue) div 45 )+ 78 ;
     G:=SrcRGB . rgbtGreen-((SrcRGB1 . rgbtGreen)*Azimuthvalue div 45 )-((SrcRGB2 . rgbtGreen)*( 45 -Azimuthvalue) div 45 )+ 78 ;
     B:=SrcRGB . rgbtBlue-((SrcRGB1 . rgbtBlue)*Azimuthvalue 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 );
     Azimuthvalue := AzimuthChange - 45 ;
     R:=SrcRGB . rgbtRed-((SrcRGB1 . rgbtRed)*Azimuthvalue div 45 )-((SrcRGB2 . rgbtRed)*( 45 -Azimuthvalue) div 45 )+ 78 ;
     G:=SrcRGB . rgbtGreen-((SrcRGB1 . rgbtGreen)*Azimuthvalue div 45 )-((SrcRGB2 . rgbtGreen)*( 45 -Azimuthvalue) div 45 )+ 78 ;
     B:=SrcRGB . rgbtBlue-((SrcRGB1 . rgbtBlue)*Azimuthvalue div 45 )-((SrcRGB2 . rgbtBlue)*( 45 -Azimuthvalue) div 45 )+ 78 ;
    end
    else if (AzimuthChange >= 90 ) and (AzimuthChange < 135 ) then
    begin
     Azimuthvalue := AzimuthChange - 90 ;
     R:=SrcRGB . rgbtRed-((SrcRGB1 . rgbtRed)*Azimuthvalue div 45 )-((SrcRGB2 . rgbtRed)*( 45 -Azimuthvalue) div 45 )+ 78 ;
     G:=SrcRGB . rgbtGreen-((SrcRGB1 . rgbtGreen)*Azimuthvalue div 45 )-((SrcRGB2 . rgbtGreen)*( 45 -Azimuthvalue) div 45 )+ 78 ;
     B:=SrcRGB . rgbtBlue-((SrcRGB1 . rgbtBlue)*Azimuthvalue 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)*Azimuthvalue div 45 )-((SrcRGB2 . rgbtRed)*( 45 -Azimuthvalue) div 45 )+ 78 ;
     G:=SrcRGB . rgbtGreen-((SrcRGB1 . rgbtGreen)*Azimuthvalue div 45 )-((SrcRGB2 . rgbtGreen)*( 45 -Azimuthvalue) div 45 )+ 78 ;
     B:=SrcRGB . rgbtBlue-((SrcRGB1 . rgbtBlue)*Azimuthvalue div 45 )-((SrcRGB2 . rgbtBlue)*( 45 -Azimuthvalue) div 45 )+ 78 ;
    end ;
    R:=Min(R, 255 );
    R:=Max(R, 0 );
    G:=Min(G, 255 );
    G:=Max(G, 0 );
    B:=Min(B, 255 );
    B:=Max(B, 0 );
    Gray := (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 ) and (AzimuthChange<- 135 )) or ((AzimuthChange>= 90 ) and (AzimuthChange<= 180 ))) then
    begin
     Inc(SrcRGB1);
    end ;
    if (j= 135 ) and (AzimuthChange< 180 )) or ((AzimuthChange>=- 180 ) and (AzimuthChange<=- 90 ))) then
    begin
     Inc(SrcRGB2);
    end ;
    Inc(SrcRGB);
    Inc(DestRGB);
   end ;
  end ;
end ;
procedure Emboss(Bmp:TBitmap;AzimuthChange: integer ;ElevationChange: integer ;WeightChange: integer );overload;
var
  DestBmp:TBitmap;
begin
  DestBmp:=TBitmap . Create;
  DestBmp . Assign(Bmp);
  Emboss(Bmp,DestBmp,AzimuthChange,ElevationChange,WeightChange);
  Bmp . Assign(DestBmp);
end ;
//反色
procedure 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 do
   begin
    PRGB^.rgbtRed := not PRGB^.rgbtRed ;
    PRGB^.rgbtGreen := not PRGB^.rgbtGreen;
    PRGB^.rgbtBlue := not PRGB^.rgbtBlue;
    Inc(PRGB);
   end ;
  end ;
end ;
//曝光
procedure 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;
    Inc(PRGB);
   end ;
  end ;
end ;
//模糊
procedure Blur(SrcBmp:TBitmap);
var
  i, j: Integer ;
  SrcRGB:pRGBTriple;
  SrcNextRGB:pRGBTriple;
  SrcPreRGB:pRGBTriple;
  Value: Integer ;
  procedure IncRGB;
  begin
   Inc(SrcPreRGB);
   Inc(SrcRGB);
   Inc(SrcNextRGB);
  end ;
  procedure DecRGB;
  begin
   Inc(SrcPreRGB,- 1 );
   Inc(SrcRGB,- 1 );
   Inc(SrcNextRGB,- 1 );
  end ;
begin
  SrcBmp . PixelFormat:=pf24Bit;
  for i := 0 to SrcBmp . Height - 1 do
  begin
   if i > 0 then
    SrcPreRGB:=SrcBmp . ScanLine[i- 1 ]
   else
    SrcPreRGB := SrcBmp . ScanLine[i];
   SrcRGB := SrcBmp . ScanLine[i];
   if 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;
    Value:=SrcPreRGB . rgbtRed+SrcRGB . rgbtRed+SrcNextRGB . rgbtRed;
    if j > 0 then IncRGB;
    Value:=Value+SrcPreRGB . rgbtRed+SrcRGB . rgbtRed+SrcNextRGB . rgbtRed;
    if j < SrcBmp . Width - 1 then IncRGB;
    Value:=(Value+SrcPreRGB . rgbtRed+SrcRGB . rgbtRed+SrcNextRGB . rgbtRed) div 9 ;
    DecRGB;
    SrcRGB . rgbtRed:=value;
    if j > 0 then DecRGB;
    Value:=SrcPreRGB . rgbtGreen+SrcRGB . rgbtGreen+SrcNextRGB . rgbtGreen;
    if j > 0 then IncRGB;
    Value:=Value+SrcPreRGB . rgbtGreen+SrcRGB . rgbtGreen+SrcNextRGB . rgbtGreen;
    if j < SrcBmp . Width - 1 then IncRGB;
    Value:=(Value+SrcPreRGB . rgbtGreen+SrcRGB . rgbtGreen+SrcNextRGB . rgbtGreen) div 9 ;
    DecRGB;
    SrcRGB . rgbtGreen:=value;
    if j > 0 then DecRGB;
    Value:=SrcPreRGB . rgbtBlue+SrcRGB . rgbtBlue+SrcNextRGB . rgbtBlue;
    if j > 0 then IncRGB;
    Value:=Value+SrcPreRGB . rgbtBlue+SrcRGB . rgbtBlue+SrcNextRGB . rgbtBlue;
    if j < SrcBmp . Width - 1 then IncRGB;
    Value:=(Value+SrcPreRGB . rgbtBlue+SrcRGB . rgbtBlue+SrcNextRGB . rgbtBlue) div 9 ;
    DecRGB;
    SrcRGB . rgbtBlue:=value;
    IncRGB;
   end ;
  end ;
end ;
//锐化
procedure Sharpen(SrcBmp:TBitmap);
var
  i, j: integer ;
  SrcRGB: pRGBTriple;
  SrcPreRGB: pRGBTriple;
  Value: integer ;
begin
  SrcBmp . PixelFormat:=pf24Bit;
  for i := 0 to SrcBmp . Height - 1 do
  begin
   SrcRGB := SrcBmp . ScanLine[i];
   if i > 0 then
    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);
    Value:=SrcRGB . rgbtRed+(SrcRGB . rgbtRed-SrcPreRGB . rgbtRed) div 2 ;
    Value:=Max( 0 ,Value);
    Value:=Min( 255 ,Value);
    SrcRGB . rgbtRed:=value;
    Value:=SrcRGB . rgbtGreen+(SrcRGB . rgbtGreen-SrcPreRGB . rgbtGreen) div 2 ;
    Value:=Max( 0 ,Value);
    Value:=Min( 255 ,Value);
    SrcRGB . rgbtGreen:=value;
    Value:=SrcRGB . rgbtBlue+(SrcRGB . rgbtBlue-SrcPreRGB . rgbtBlue) div 2 ;
    Value:=Max( 0 ,Value);
    Value:=Min( 255 ,Value);
    SrcRGB . rgbtBlue:=value;
    Inc(SrcRGB);
    Inc(SrcPreRGB);
   end ;
  end ;
end ;
  [图像的旋转和翻转]
以下代码用ScanLine配合指针移动实现,用于 24 位色!
//旋转90度
procedure Rotate90( const Bitmap:TBitmap);
var
  i,j: Integer ;
  rowIn,rowOut:pRGBTriple;
  Bmp:TBitmap;
  Width,Height: Integer ;
begin
  Bmp:=TBitmap . Create;
  Bmp . Width := Bitmap . Height;
  Bmp . Height := Bitmap . Width;
  Bmp . PixelFormat := 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[i];
    Inc(rowOut,Height - j);
    rowOut^ := rowIn^;
    Inc(rowIn);
   end ;
  end ;
  Bitmap . Assign(Bmp);
end ;
//旋转180度
procedure Rotate180( const Bitmap:TBitmap);
var
  i,j: Integer ;
  rowIn,rowOut:pRGBTriple;
  Bmp:TBitmap;
  Width,Height: Integer ;
begin
  Bmp:=TBitmap . Create;
  Bmp . Width := Bitmap . Width;
  Bmp . Height := Bitmap . Height;
  Bmp . PixelFormat := 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[Height - j];
    Inc(rowOut,Width - i);
    rowOut^ := rowIn^;
    Inc(rowIn);
   end ;
  end ;
  Bitmap . Assign(Bmp);
end ;
//旋转270度
procedure Rotate270( const Bitmap:TBitmap);
var
  i,j: Integer ;
  rowIn,rowOut:pRGBTriple;
  Bmp:TBitmap;
  Width,Height: Integer ;
begin
  Bmp:=TBitmap . Create;
  Bmp . Width := Bitmap . Height;
  Bmp . Height := Bitmap . Width;
  Bmp . PixelFormat := 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[Width - i];
    Inc(rowOut,j);
    rowOut^ := rowIn^;
    Inc(rowIn);
   end ;
  end ;
  Bitmap . Assign(Bmp);
end ;
//任意角度
function RotateBitmap(Bitmap:TBitmap;Angle: Integer ;BackColor:TColor):TBitmap;
var
  i,j,iOriginal,jOriginal,CosPoint,SinPoint : integer ;
  RowOriginal,RowRotated : pRGBTriple;
  SinTheta,CosTheta : Extended ;
  AngleAdd : integer ;
begin
  Result:=TBitmap . Create;
  Result . PixelFormat := pf24bit;
  Result . Canvas . Brush . Color:=BackColor;
  Angle:=Angle Mod 360 ;
  if Angle< 0 then Angle:= 360 - Abs (Angle);
  if Angle= 0 then
   Result . Assign(Bitmap)
  else if Angle= 90 then
  begin
   Result . Assign(Bitmap);
   Rotate90(Result); //如果是旋转90度,直接调用上面的代码
  end
  else if (Angle> 90 ) and (Angle< 180 ) then
  begin
   AngleAdd:= 90 ;
   Angle:=Angle-AngleAdd;
  end
  else if Angle= 180 then
  begin
   Result . Assign(Bitmap);
   Rotate180(Result); //如果是旋转180度,直接调用上面的过程
  end
  else if (Angle> 180 ) and (Angle< 270 ) then
  begin
   AngleAdd:= 180 ;
   Angle:=Angle-AngleAdd;
  end
  else if Angle= 270 then
  begin
   Result . Assign(Bitmap);
   Rotate270(Result); //如果是旋转270度,直接调用上面的过程
  end
  else if (Angle> 270 ) and (Angle< 360 ) then
  begin
   AngleAdd:= 270 ;
   Angle:=Angle-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));
   Result . Height := 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));
  end ;
  CosTheta:= Abs (CosTheta);
  SinTheta:= Abs (SinTheta);
  if (AngleAdd= 0 ) or (AngleAdd= 180 ) then
  begin
   CosPoint:=Round(Bitmap . Height*CosTheta);
   SinPoint:=Round(Bitmap . Height*SinTheta);
  end
  else
  begin
   SinPoint:=Round(Bitmap . Width*CosTheta);
   CosPoint:=Round(Bitmap . Width*SinTheta);
  end ;
  for j := 0 to 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 ;
      iOriginal := Round((i+ 1 )*CosTheta-(CosPoint-j- 1 )*SinTheta)- 1 ;
     end ;
     90 :
     begin
      iOriginal := Round((j+ 1 )*SinTheta-(i+ 1 -SinPoint)*CosTheta)- 1 ;
      jOriginal := Bitmap . Height-Round((i+ 1 )*SinTheta-(CosPoint-j- 1 )*CosTheta);
     end ;
     180 :
     begin
      jOriginal := Bitmap . Height-Round((j+ 1 )*CosTheta-(i+ 1 -SinPoint)*SinTheta);
      iOriginal := Bitmap . Width-Round((i+ 1 )*CosTheta-(CosPoint-j- 1 )*SinTheta);
     end ;
     270 :
     begin
      iOriginal := Bitmap . Width-Round((j+ 1 )*SinTheta-(i+ 1 -SinPoint)*CosTheta);
      jOriginal := Round((i+ 1 )*SinTheta-(CosPoint-j- 1 )*CosTheta)- 1 ;
     end ;
    end ;
    if (iOriginal >= 0 ) and (iOriginal <= Bitmap . Width- 1 ) and
      (jOriginal >= 0 ) and (jOriginal <= Bitmap . Height- 1 )
    then
    begin
     RowOriginal := Bitmap . Scanline[jOriginal];
     Inc(RowOriginal,iOriginal);
     RowRotated^ := RowOriginal^;
     Inc(RowRotated);
    end
    else
    begin
     Inc(RowRotated);
    end ;
   end ;
  end ;
  end ;
end ;
//水平翻转
procedure FlipHorz( const Bitmap:TBitmap);
var
  i,j: Integer ;
  rowIn,rowOut:pRGBTriple;
  Bmp:TBitmap;
  Width,Height: Integer ;
begin
  Bmp:=TBitmap . Create;
  Bmp . Width := Bitmap . Width;
  Bmp . Height := Bitmap . Height;
  Bmp . PixelFormat := 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];
    Inc(rowOut,Width - i);
    rowOut^ := rowIn^;
    Inc(rowIn);
   end ;
  end ;
  Bitmap . Assign(Bmp);
end ;
//垂直翻转
procedure FlipVert( const Bitmap:TBitmap);
var
  i,j: Integer ;
  rowIn,rowOut:pRGBTriple;
  Bmp:TBitmap;
  Width,Height: Integer ;
begin
  Bmp:=TBitmap . Create;
  Bmp . Width := Bitmap . Height;
  Bmp . Height := Bitmap . Width;
  Bmp . PixelFormat := 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[Height - j];
    Inc(rowOut,i);
    rowOut^ := rowIn^;
    Inc(rowIn);
   end ;
  end ;
  Bitmap . Assign(Bmp);
end ;
[亮度、对比度、饱和度的调整]
以下代码用ScanLine配合指针移动实现!
function Min(a, b: integer ): 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 ;
//亮度调整
procedure BrightnessChange( 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];
   for j := 0 to SrcBmp . Width - 1 do
   begin
    if ValueChange > 0 then
    begin
     DestRGB . rgbtRed := Min( 255 , SrcRGB . rgbtRed + ValueChange);
     DestRGB . rgbtGreen := Min( 255 , SrcRGB . rgbtGreen + ValueChange);
     DestRGB . rgbtBlue := Min( 255 , SrcRGB . rgbtBlue + ValueChange);
    end else begin
     DestRGB . rgbtRed := Max( 0 , SrcRGB . rgbtRed + ValueChange);
     DestRGB . rgbtGreen := Max( 0 , SrcRGB . rgbtGreen + ValueChange);
     DestRGB . rgbtBlue := Max( 0 , SrcRGB . rgbtBlue + ValueChange);
    end ;
    Inc(SrcRGB);
    Inc(DestRGB);
   end ;
  end ;
end ;
//对比度调整
procedure 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];
   for j := 0 to SrcBmp . Width - 1 do
   begin
    if ValueChange>= 0 then
    begin
    if SrcRGB . rgbtRed >= 128 then
     DestRGB . rgbtRed := Min( 255 , SrcRGB . rgbtRed + ValueChange)
    else
     DestRGB . rgbtRed := Max( 0 , SrcRGB . rgbtRed - ValueChange);
    if 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)
    else
     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 . rgbtGreen - ValueChange);
    if SrcRGB . rgbtBlue >= 128 then
     DestRGB . rgbtBlue := Max( 128 , SrcRGB . rgbtBlue + ValueChange)
    else
     DestRGB . rgbtBlue := Min( 128 , SrcRGB . rgbtBlue - ValueChange);
    end ;
    Inc(SrcRGB);
    Inc(DestRGB);
   end ;
  end ;
end ;
//饱和度调整
procedure SaturationChange( const SrcBmp,DestBmp:TBitmap;ValueChange: integer );
var
  Grays: array [ 0..767 ] of Integer ;
  Alpha: array [ 0..255 ] of Word ;
  Gray, x, y: Integer ;
  SrcRGB,DestRGB: pRGBTriple;
  i: Byte ;
begin
ValueChange:=ValueChange+ 255 ;
for i := 0 to 255 do
  Alpha[i] := (i * ValueChange) Shr 8 ;
x := 0 ;
for i := 0 to 255 do
begin
  Gray := i - Alpha[i];
  Grays[x] := Gray;
  Inc(x);
  Grays[x] := Gray;
  Inc(x);
  Grays[x] := Gray;
  Inc(x);
end ;
for y := 0 to SrcBmp . Height - 1 do
begin
  SrcRGB := SrcBmp . ScanLine[Y];
  DestRGB := DestBmp . ScanLine[Y];
  for x := 0 to SrcBmp . Width - 1 do
  begin
   Gray := 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 then
    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(SrcRGB);
   Inc(DestRGB);
  end ;
end ;
end ;
//RGB调整
procedure RGBChange(SrcBmp,DestBmp:TBitmap;RedChange,GreenChange,BlueChange: integer );
var
  SrcRGB, DestRGB: pRGBTriple;
  i,j: integer ;
begin
  for i := 0 to SrcBmp . Height- 1 do
  begin
   SrcRGB := SrcBmp . ScanLine[i];
   DestRGB :=DestBmp . ScanLine[i];
   for j := 0 to SrcBmp . Width - 1 do
   begin
    if RedChange> 0 then
     DestRGB . rgbtRed := Min( 255 , SrcRGB . rgbtRed + RedChange)
    else
     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(SrcRGB);
    Inc(DestRGB);
   end ;
  end ;
end ;
[颜色调整]
//RGB<=>BGR
procedure RGB2BGR( const Bitmap:TBitmap);
var
  X: Integer ;
  Y: Integer ;
  PRGB: pRGBTriple;
  Color: Byte ;
begin
  for Y := 0 to (Bitmap . Height - 1 ) do
  begin
   for X := 0 to (Bitmap . Width - 1 ) do
   begin
    Color := PRGB^.rgbtRed;
    PRGB^.rgbtRed := PRGB^.rgbtBlue;
    PRGB^.rgbtBlue := Color;
    Inc(PRGB);
   end ;
   end
  end ;
end ;
//灰度化(加权)
procedure Grayscale( const Bitmap:TBitmap);
var
  X: Integer ;
  Y: Integer ;
  PRGB: pRGBTriple;
  Gray: 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 * Red + 151 * Green + 28 * Blue) shr 8 ;
    PRGB^.rgbtRed:=Gray;
    PRGB^.rgbtGreen:=Gray;
    PRGB^.rgbtBlue:=Gray;
    Inc(PRGB);
   end ;
  end ;
end ;

理论篇:

关键词:

绘图区-即窗口显示图像的区域,亦可为全屏幕(在全屏幕下绘图的效果比一般窗口下好)
中心点-即要绘图区显示的中心点在原始图像的坐标(声明:这个概念特别重要)

先说说图像的放大,要放大一张图片,我们一般的做法是直接放大图像,但本文介绍的方法仅放大我们能够看到的部分,放大分两种情况,一种是放大后比绘图区还要小,这种情况没什么好说,当然是显示全部的图像;第二种是放大后的图像比绘图区大,这才是我们今天要讨论的重点话题,这种情况下我们先要确定图像放大后的大小,然后根据“中心点”计算在原始图像的位置和大小,最后把截取的图像放大到绘图区。

再说说图像的漫游,当显示的图像超过绘图区时,我们需要对图像进行漫游,以便看到全部的图像。原理是:当鼠标在绘图区进行单击时,这时开始漫游,先记录鼠标的单击位置,然后检测鼠标的移动,根据鼠标和上次的位移计算出“中心点”(需要将屏幕坐标转换为原始图像坐标),根据在上面放大的原理到原始图像中取出要显示的部分,放大显示到绘图区。

算法实现篇:

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)
开始计算:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
aw=Round(PZoom*sw/ 100 );
ah=Round(PZoom*sh/ 100 );
p1=aw/pw
p2=ah/ph
// 注:Round 用于取整,如其他语言的Int(),Fix()等
if p1> 1 then w=Round(sw/p1) else w=sw
if p2> 1 then h=Round(sh/p2) else h=sh
// 注:shr 为右移运算符,可以使用“>>1”、“div 2”、“/2”或“Round(w/2)”代替
x=a-w shr 1
y=b-h shr 1
// 注:div 为整除运算符
ptx=(w*PZoom) div 100
pty=(h*PZoom) div 100
// 以下计算在绘图区显示的图像大小和位置

变量

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
   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);
   vh:=Round(Pencent*pty);
   // 计算出图片的位置
   vx:=(pw-vw) div 2 ;
   vy:=(ph-vh) div 2 ;
// ------------------------------------

好了,两个重要的任务完成(x,y),(w,h),(vx,vy),(vw,vh)已经全部计算得出,下面的工作就是显示了,我们选择 Windows API 进行操作
变量

?
1
2
3
4
5
6
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);

最后绘制到显示的区域即可:
例如:

?
1
BitBlt(GetDC( 0 ),vx,vy,vx+vw,xy+vh,dDC, 0 , 0 ,SRCCOPY);

2.图像漫游

先定义三个全局变量:

?
1
2
3
4
FBeginDragPoint  :TPoint;     // 记录鼠标开始拖动的位置
FBeginDragSBPoint :TPoint;     // 记录“中心点”位置
FBeginDrag    : boolean ;    // 是否已经开始“拖动”
a,b        : integer ;    // “中心点”位置

在鼠标左键点击时,记录鼠标的位置和“中心点”的位置,同时设置 FBeginDrag 为真
当鼠标右键弹起时,设置 FBeginDrag 为假
鼠标移动时,判断 FBeginDrag ,如果为假不进行处理,如果为真进行下面处理:
假设 X,Y 为鼠标当前的位置

?
1
2
a=FBeginDragPoint . X-((X-FBeginDragPoint . X)* 100 ) div PZoom
b=FBeginDragPoint . Y-((Y-FBeginDragPoint . Y)* 100 ) div PZoom

最后使用上面介绍的图像放大显示出图像

技巧篇:

1.如果图像较大,使用 delphi 的 位图对象会出现内存溢出错误,这时可以进行如下设置:

?
1
2
3
bitImage:=TBitmap . Create;
bitImage . PixelFormat:=pf24bit;
bitImage . ReleaseHandle;

2.如果要让图像自动适应窗口的大小,参考以下代码:

?
1
2
3
4
5
6
7
8
9
var
   p1,p2    : double ;
begin
   p1:=pw/sw;
   p2:=ph/sw;
   if p1>p2 then PZoom:=Round(p2* 100 )
   else     PZoom:=Round(p1* 100 );
   if PZoom= 0 then PZoom:= 100 ;
end ;

Delphi灰度图像像素颜色亮度处理

在图像处理中,速度是很重要的。因此,我们得重新处理一下TBitmap,得到TVczhBitmap。这只是因为GetPixels和SetPixels的速度太慢,换一个方法而已。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
unit untBitmapProc;
interface
uses Graphics, SysUtils;
type
TVczhBitmap= class (TBitmap)
private
Data:PByteArray;
Line: Integer ;
procedure SetFormat;
function GetBytePointer(X,Y: Integer ):PByte;
procedure SetBytes(X,Y: Integer ;Value: Byte );
function GetBytes(X,Y: Integer ): Byte ;
protected
published
constructor Create;
public
property Bytes[X,Y: Integer ]: Byte read GetBytes write SetBytes;
procedure LoadFromFile(FileName: String );
procedure ToGray;
end ;
implementation
procedure TVczhBitmap . SetFormat;
begin
HandleType:=bmDIB;
PixelFormat:=pf24bit;
end ;
function TVczhBitmap . GetBytePointer(X,Y: Integer ):PByte;
begin
if Line<>Y then
begin
Line:=Y;
Data:=ScanLine[Y];
end ;
Longint (result):= Longint (Data)+X;
end ;
procedure TVczhBitmap . SetBytes(X,Y: Integer ;Value: Byte );
begin
GetBytePointer(X,Y)^:=Value;
end ;
function TVczhBitmap . GetBytes(X,Y: Integer ): Byte ;
begin
result:=GetBytePointer(X,Y)^;
end ;
constructor TVczhBitmap . Create;
begin
inherited Create;
SetFormat;
Line:=- 1 ;
end ;
procedure TVczhBitmap . LoadFromFile(FileName: String );
begin
inherited LoadFromFile(FileName);
SetFormat;
Line:=- 1 ;
end ;
procedure TVczhBitmap . ToGray;
var X,Y,R: Integer ;
B: Byte ;
begin
for Y:= 0 to Height- 1 do
for X:= 0 to Width- 1 do
begin
R:= 0 ;
for B:= 0 to 2 do
R:=R+GetBytes(X* 3 +B,Y);
for B:= 0 to 2 do
SetBytes(X* 3 +B,Y,R div 3 );
end ;
end ;
end .

此后,我们需要建立几个窗体。第一个用来显示图片,第二个用来处理图片,其他的窗体都继承自第二个窗体,包含实际的处理方法。

先看第二个窗口:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
unit untProc;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, untBitmapProc, StdCtrls, ComCtrls;
type
TfrmProcessor = class (TForm)
pbBar: TPaintBox;
gpProc: TGroupBox;
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure pbBarPaint(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
BarData: array [ 0..255 ] of Byte ;
Bar:TVczhBitmap;
procedure DrawBar;
end ;
var
frmProcessor: TfrmProcessor;
implementation
{$R *.dfm}
uses untViewer;
procedure TfrmProcessor . DrawBar;
var I: Integer ;
begin
Bar . Canvas . FillRect(Bar . Canvas . ClipRect);
Bar . Canvas . MoveTo( 0 , 255 -BarData[ 0 ]);
for I:= 1 to 255 do
Bar . Canvas . LineTo(I, 255 -BarData[I]);
end ;
procedure TfrmProcessor . FormCreate(Sender: TObject);
begin
Bar:=TVczhBitmap . Create;
Bar . Width:= 256 ;
Bar . Height:= 256 ;
Bar . Canvas . Brush . Color:=clWhite;
Bar . Canvas . Brush . Style:=bsSolid;
end ;
procedure TfrmProcessor . FormDestroy(Sender: TObject);
begin
Bar . Free;
end ;
procedure TfrmProcessor . FormShow(Sender: TObject);
var I: Integer ;
begin
for I:= 0 to 255 do
BarData[I]:=I;
DrawBar;
end ;
procedure TfrmProcessor . pbBarPaint(Sender: TObject);
begin
pbBar . Canvas . Draw( 0 , 0 ,Bar);
end ;
procedure 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);
end ;
end .

之后,做一个窗口继承自它,则调整BarData[]后,按Apply即可看到结果。

现在开始将图像处理。具体效果见示例程序。
  
一、颜色反转。

灰度图像的颜色都是从0~255,所以,为了使颜色反转,我们可以用255减去该颜色值以得到反转后的颜色。

?
1
2
3
4
5
6
7
8
var I: Integer ;
begin
inherited ;
for I:= 0 to 255 do
BarData[I]:= 255 -I; //用255减去该颜色值
DrawBar;
pbBarPaint(pbBar);
end ;

二、缩小颜色范围以增强或减弱亮度

颜色本来是从0~255的。如果调节它的范围,例如从0~16,则会是图像明显变暗。我们可以把起始值设为a,把终止值设为b,则新的颜色值New=a+(b-1)*Old/255。这样做的话可以改变亮度,并且不会破坏原先颜色的顺序。代码如下

?
1
2
3
4
5
6
7
8
var I: Integer ;
begin
for I:= 0 to 255 do
BarData[I]:=( 255 -sbMin . Position)+Round((sbMin . Position-sbMax . Position)/ 255 *I);
DrawBar;
pbBarPaint(pbBar);
Button1Click(Button1);
end ;

这里的sbMin.Position和sbMaxPosition都是反转过的。所以使用时要用255去减
  
三、增加某个范围内的颜色范围

如果图像本身的颜色范围很小的画,你可以通过这种方法来加大图像的对比度,有利于对图像的分析。具体做法:

选取一个值a做为起始值,选取一个值b做为终止值,然后按以下公式变形:
  | 0 (X<=a)
  f(X)= | 255/(b-a)*(X-a)
  | 255(X>=b)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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));
end ;
DrawBar;
pbBarPaint(pbBar);
Button1Click(Button1);
end ;

四、变为黑白图片

在使用第三个功能的时候,你会发现当b<=a时,图像上的颜色除了黑色就是白色。这样操作的好处是不能直接显示出来的。这只要到了比较高级的图像处理如边缘检测等,才有作用。本例可以拿第三种方法的公式再变形,因此不作详细阐述。
  
五、指数级亮度调整

我们假设这个图的定义域是[0,1],值域也是[0,1]。那么,定义函数f(x)=x^c,则f(x)的图像有一段如上图。我们再用鼠标操作时,可以在上面取一点P(a,b),然后使f(x)通过点P,则c=ln(b)/ln(a)。有了c之后,我们就可以对颜色进行操作了:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
New=(Old/ 255 )^c* 255 =exp(ln(old/ 255 )*c)* 255
var ea,eb,ec: Extended ;
I: Integer ;
begin
ea:=A/ 255 ;
eb:=B/ 255 ;
ec:=Ln(eb)/Ln(ea);
for I:= 1 to 255 do
BarData[I]:=Round(Exp(Ln((I/ 255 ))*ec)* 255 );
DrawBar;
pbBarPaint(pbBar);
Button1Click(Button1);
end ;

这样做可以调节图像的亮度。

Delphi图形显示特效的技巧

概述

----目前在许多学习软件、游戏光盘中,经常会看到各种

图形显示技巧,凭着图形的移动、交错、雨滴状、百页窗、积木堆叠等显现方式,使画面变得更为生动活泼,更 能吸引观众。本文将探讨如何在delphi中实现各种图形显示技巧。

基本原理

----在delphi中,实现一副图象的显示是非常简单的,只要在form中定义一个timage组件,设置其picture属性,然后选 择任何有效的.ico、.bmp、.emf或.wmf文件,进行load,所选文 件就显示在timage组件中了。但这只是直接将图形显示在窗体中,毫无技巧可言。为了使图形显示具有别具一格的效果,可以按下列步骤实现:

----定义一个timage组件,把要显示的图形先装入到timage组件中,也就是说,把图形内容从磁盘载入内存中, 做为图形缓存。

----创建一新的位图对象,其尺寸跟timage组件中的图形一样。

----利用画布(canvas)的copyrect功能(将一个画布的矩形区域拷贝到另一个画布的矩形区域),使用技巧,动态形

成位图文件内容,然后在窗体中显示位图。

----实现方法

下面介绍各种图形显示技巧:

1.推拉效果

将要显示的图形由上、下、左、右方向拉进屏幕内显示,同时将屏幕上原来的旧图盖掉,此种效果可分为四种,上拉、下拉、左拉、右拉,但原理都差不多,以上拉 效果为例。

原理:首先将放在暂存图形的第一条水平线,搬移至要显示的位图的最后一条,接着再将暂存图形的前两条水平线,依序搬移至要显示位图的最后两条水平线,然后搬移前三条、前四条叄?直到全部图形数据搬完为止。在搬移的过程中即可看到显示的位图由下而上浮起,而达到上拉的效果。

程序算法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
procedure tform1 . button1click(sender: tobject);
var
newbmp: tbitmap;
i,bmpheight,bmpwidth: integer ;
begin
newbmp:= tbitmap . create;
newbmp . width:=image1 . width;
newbmp . height:=image1 . height;
bmpheight:=image1 . height;
bmpwidth:=image1 . width;
for i:= 0 to bmpheight do
begin
newbmp . canvas . copyrect(rect
( 0 ,bmpheight-i,bmpwidth,bmpheight),
image1 . canvas,
rect( 0 , 0 ,bmpwidth,i));
form1 . canvas . draw( 120 , 100 ,newbmp);
end ;
newbmp . free;
end ;

2.垂直交错效果

原理:将要显示的图形拆成两部分,奇数条扫描线由上往下搬移,偶数条扫描线的部分则由下往上搬移,而且两者同时进行。从屏幕上便可看到分别由上下两端出现的较淡图形向屏幕中央移动,直到完全清楚为止。

程序算法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
procedure tform1 . button4click(sender: tobject);
var
newbmp:tbitmap;
i,j,bmpheight,bmpwidth: integer ;
begin
newbmp:= tbitmap . create;
newbmp . width:=image1 . width;
newbmp . height:=image1 . height;
bmpheight:=image1 . height;
bmpwidth:=image1 . width;
i:= 0 ;
while i< =bmpheight do
begin
j:=i;
while j > 0 do
begin
newbmp . canvas . copyrect(rect( 0 ,j- 1 ,bmpwidth,j),
image1 . canvas,
rect( 0 ,bmpheight-i+j- 1 ,bmpwidth,bmpheight-i+j));
newbmp . canvas . copyrect(rect
( 0 ,bmpheight-j,bmpwidth,bmpheight-j+ 1 ),
image1 . canvas,
rect( 0 ,i-j,bmpwidth,i-j+ 1 ));
j:=j- 2 ;
end ;
form1 . canvas . draw( 120 , 100 ,newbmp);
i:=i+ 2 ;
end ;
newbmp . free;
end ;

3.水平交错效果

原理:同垂直交错效果原理一样,只是将分成两组后的图形分别由左右两端移进屏幕。

程序算法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
procedure tform1 . button5click(sender: tobject);
var
newbmp:tbitmap;
i,j,bmpheight,bmpwidth: integer ;
begin
newbmp:= tbitmap . create;
newbmp . width:=image1 . width;
newbmp . height:=image1 . height;
bmpheight:=image1 . height;
bmpwidth:=image1 . width;
i:= 0 ;
while i< =bmpwidth do
begin
j:=i;
while j > 0 do
begin
newbmp . canvas . copyrect(rect(j- 1 , 0 ,j,bmpheight),
image1 . canvas,
rect(bmpwidth-i+j- 1 , 0 ,bmpwidth-i+j,bmpheight));
newbmp . canvas . copyrect(rect
(bmpwidth-j, 0 ,bmpwidth-j+ 1 ,bmpheight),
image1 . canvas,
rect(i-j, 0 ,i-j+ 1 ,bmpheight));
j:=j- 2 ;
end ;
form1 . canvas . draw( 120 , 100 ,newbmp);
i:=i+ 2 ;
end ;
newbmp . free;
end ;

4.雨滴效果

原理:将暂存图形的最后一条扫描线,依序搬移到可视位图的第一条到最后一条扫描线,让此条扫描线在屏幕上留下它的轨迹。接着再把暂存图形的倒数第二条扫描线,依序搬移到可视位图的第一条到倒数第二条扫描线。其余的扫描线依此类推。

程序算法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
procedure tform1 . button3click(sender: tobject);
var
newbmp:tbitmap;
i,j,bmpheight,bmpwidth: integer ;
begin
newbmp:= tbitmap . create;
newbmp . width:=image1 . width;
newbmp . height:=image1 . height;
bmpheight:=image1 . height;
bmpwidth:=image1 . width;
for i:=bmpheight downto 1 do
for j:= 1 to i do
begin
newbmp . canvas . copyrect(rect( 0 ,j- 1 ,bmpwidth,j),
image1 . canvas,
rect( 0 ,i- 1 ,bmpwidth,i));
form1 . canvas . draw( 120 , 100 ,newbmp);
end ;
newbmp . free;
end ;

5.百叶窗效果

原理:将放在暂存图形的数据分成若干组,然后依次从第一组到最后一组搬移,第一次每组各搬移第一条扫描线到可视位图的相应位置,第二次搬移第二条扫描线,接着搬移第三条、第四条扫描线.

程序算法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
procedure tform1 . button6click(sender: tobject);
var
newbmp:tbitmap;
i,j,bmpheight,bmpwidth: integer ;
xgroup,xcount: integer ;
begin
newbmp:= tbitmap . create;
newbmp . width:=image1 . width;
newbmp . height:=image1 . height;
bmpheight:=image1 . height;
bmpwidth:=image1 . width;
xgroup:= 16 ;
xcount:=bmpheight div xgroup;
for i:= 0 to xcount do
for j:= 0 to xgroup do
begin
newbmp . canvas . copyrect(rect
( 0 ,xcount*j+i- 1 ,bmpwidth,xcount*j+i),
image1 . canvas,
rect( 0 ,xcount*j+i- 1 ,bmpwidth,xcount*j+i));
form1 . canvas . draw( 120 , 100 ,newbmp);
end ;
newbmp . free;
end ;

6.积木效果

原理:是雨滴效果的一种变化,不同之处在于,积木效果每次搬移的是一块图形,而不只是一根扫描线。

程序算法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
procedure tform1 . button7click(sender: tobject);
var
newbmp:tbitmap;
i,j,bmpheight,bmpwidth: integer ;
begin
newbmp:= tbitmap . create;
newbmp . width:=image1 . width;
newbmp . height:=image1 . height;
bmpheight:=image1 . height;
bmpwidth:=image1 . width;
i:=bmpheight;
while i> 0 do
begin
for j:= 10 to i do
begin
newbmp . canvas . copyrect(rect( 0 ,j- 10 ,bmpwidth,j),
image1 . canvas,
rect( 0 ,i- 10 ,bmpwidth,i));
form1 . canvas . draw( 120 , 100 ,newbmp);
end ;
i:=i- 10 ;
end ;
newbmp . free;
end ;

结束语

上述图形显示效果均已上机通过。使用效果很好。
用Delphi实现图像放大镜

向窗体上添加两个TImage组件,其中一个TImage组件的Name属性设置为Image1,它充当原图片显示的载体。另一个TImage组件的Name属性设置为Image2,它可以显示放大后的图像。

本例的核心是StretchBlt函数,利用StretchBlt函数实现局部图像放大,响应代码如下:

?
1
2
3
4
5
6
7
8
procedure TForm1 . Image1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer );
begin
 StretchBlt(Image2 . Canvas . Handle, 0 , 0 ,Image2 . Width,Image2 . Height,
 Image1 . Canvas . Handle, X- 20 ,Y- 20 , 40 , 40 ,SRCCOPY);
 Image2 . Refresh;
 Screen . Cursors[ 1 ]:=LoadCursorFromFile( 'MAGNIFY.CUR' );
 Self . Cursor:= 1 ;
end ;

程序首先会调用StretchBlt函数,以鼠标当前位置作为中心点,以边长为40选中Image1组件上的局部图像,并放大此局部图像到Image2组件上。然后通过调用Image2组件的Refresh方法以刷新Image2组件的显示。最后设置鼠标指针为新的形状。

程序代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls;
type
 TForm1 = class (TForm)
 Image1: TImage;
 Image2: TImage;
  procedure Image1MouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer );
  procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer );
private
  { Private declarations }
public
  { Public declarations }
end ;
var
 Form1: TForm1;
  implementation
  {$R *.dfm}
  procedure TForm1 . Image1MouseMove(Sender:TObject;Shift:TShiftState;X,Y: Integer );
  begin
StretchBlt(Image2 . Canvas . Handle, 0 , 0 ,Image2 . Width,Image2 . Height,Image1 . Canvas . Handle, X- 20 ,Y- 20 , 40 , 40 ,SRCCOPY);
  Image2 . Refresh;
  Screen . Cursors[ 1 ]:=LoadCursorFromFile( 'MAGNIFY.CUR' );
  Self . Cursor:= 1 ;
end ;
procedure TForm1 . FormMouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer );
begin
 Screen . Cursors[ 1 ]:=crDefault;
 Self . Cursor:= 1 ;
end ;
end .

保存文件,然后按F9键运行程序,程序运行。
放大图像是一个优秀的看图软件必备的功能,本实例提供了一种非常简便易行的方法,不但代码数量少,而且执行效率高。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值