(原創) 如何使用C++/CLI对图片做Grayscale Dilation? (.NET) (C/C++) (C++/CLI) (GDI+) (Image Processing)
这是我第一次用C++/CLI真正写出一个有用的程序,主要是因为想用STL Generic Algorithm,又想用GDI+,只好放弃C#改用C++/CLI啦。
1
#include "stdafx.h"
2
#include <vector>
3
#include <algorithm>
4
5
using namespace System::Drawing;
6
using namespace System::Drawing::Imaging;
7
8
typedef std::pair<int, int> MyPoint;
9
typedef std::vector<MyPoint> MyPointVec;
10
typedef int GrayLevel;
11
12
// Make kernel by radius
13
MyPointVec makeKernel(const int&);
14
// Process dilation
15
Bitmap^ dilation(Bitmap^, const MyPointVec%);
16
// Get max gray level by kernel
17
GrayLevel getMaxByKernel(Bitmap^, const MyPointVec%, const MyPoint%);
18
// Get gray level from Color object
19
GrayLevel getGrayLevelFromColor(Color^);
20
21
int main() {
22
// Read image from lena.jpg
23
Bitmap^ image = gcnew Bitmap("lena.jpg");
24
const int radius = 2;
25
// Make kernel by radius
26
MyPointVec kernel = makeKernel(radius);
27
// New dilated image
28
Bitmap^ newImage = dilation(image, kernel);
29
// Save new dilated image to disk
30
newImage->Save("GrayscaleDilatedLena.jpg");
31
32
return 0;
33
}
34
35
// Make kernel by radius
36
MyPointVec makeKernel(const int& radius) {
37
MyPointVec kernel;
38
39
if (radius == 0) {
40
kernel.push_back(std::make_pair(0,0));
41
}
42
else if (radius == 1) {
43
// *
44
// ***
45
// *
46
kernel.push_back(std::make_pair(0,0));
47
kernel.push_back(std::make_pair(1,0));
48
kernel.push_back(std::make_pair(0,1));
49
kernel.push_back(std::make_pair(-1,0));
50
kernel.push_back(std::make_pair(0,-1));
51
}
52
else {
53
kernel.push_back(std::make_pair(-1,2));
54
kernel.push_back(std::make_pair(0,2));
55
kernel.push_back(std::make_pair(1,2));
56
57
kernel.push_back(std::make_pair(-2,1));
58
kernel.push_back(std::make_pair(-1,1));
59
kernel.push_back(std::make_pair(0,1));
60
kernel.push_back(std::make_pair(1,1));
61
kernel.push_back(std::make_pair(2,1));
62
63
kernel.push_back(std::make_pair(-2,0));
64
kernel.push_back(std::make_pair(-1,0));
65
kernel.push_back(std::make_pair(0,0));
66
kernel.push_back(std::make_pair(1,0));
67
kernel.push_back(std::make_pair(2,0));
68
69
kernel.push_back(std::make_pair(-2,-1));
70
kernel.push_back(std::make_pair(-1,-1));
71
kernel.push_back(std::make_pair(0,-1));
72
kernel.push_back(std::make_pair(1,-1));
73
kernel.push_back(std::make_pair(2,-1));
74
75
kernel.push_back(std::make_pair(-1,-2));
76
kernel.push_back(std::make_pair(0,-2));
77
kernel.push_back(std::make_pair(1,-2));
78
}
79
80
return kernel;
81
}
82
83
// Process dilation
84
Bitmap^ dilation(Bitmap^ image, const MyPointVec% kernel) {
85
// New dilated image
86
Bitmap^ newImage = gcnew Bitmap(image->Width, image->Height);
87
for(int x = 0; x != image->Width; ++x) {
88
for(int y = 0; y != image->Height; ++y) {
89
// Get max gray level by kernel
90
GrayLevel gray = getMaxByKernel(image, kernel, std::make_pair(x,y));
91
// Set max gray level to new dilated image
92
newImage->SetPixel(x, y, Color::FromArgb(gray, gray, gray));
93
}
94
}
95
96
return newImage;
97
}
98
99
// Get max gray level by kernel
100
GrayLevel getMaxByKernel(Bitmap^ image, const MyPointVec% kernel, const MyPoint% point) {
101
typedef std::vector<GrayLevel> NeighborColor;
102
NeighborColor neighborColor;
103
104
// C++/CLI's new for each syntax
105
for each (MyPoint kpoint in kernel) {
106
int x = point.first + kpoint.first;
107
int y = point.second + kpoint.second;
108
if (x >= 0 && x < image->Width) {
109
if (y >= 0 && y < image->Height) {
110
GrayLevel gray = getGrayLevelFromColor(image->GetPixel(x, y));
111
// push_back new gray level to vector
112
neighborColor.push_back(gray);
113
}
114
}
115
}
116
117
// Use STL max_element() algorithm to get max gray level
118
NeighborColor::iterator maxIter = max_element(neighborColor.begin(), neighborColor.end());
119
120
return *maxIter;
121
}
122
123
// Get gray level from Color object
124
GrayLevel getGrayLevelFromColor(Color^ color) {
125
return (color->R + color->G + color->B) /3;
126
}

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

原图
执行结果
由于第一次真枪实弹的用C++/CLI,所以很多还不是很懂,如C++/CLI新的Handle ^,似乎不能用const和reference,且C++/CLI也将reference从&改成%,不过这的地方倒是改的很好,ISO C++在Address of和Reference都用&,我刚学时,也觉得很混淆,改了之后清楚多了。105行用到了for each,这是C++/CLI的新语法,总算从VB和C#学到这个漂亮的语法了!!,118行用到了max_element()这个algorithm,这也是我主要要用STL的原因,当然自己写也不难,不过既然Library有提供漂亮的algorithm,为什么不用呢?STL是我爱上C++的最主要原因。
See Also
如何使用C++/CLI对图片做Grayscale Erosion?
如何使用C++/CLI对图片做Grayscale Opening?
如何使用C++/CLI对图片做Grayscale Closing?
(原創) 如何實現Real Time對Binary Image做Dilation? (SOC) (Verilog) (Image Processing) (DE2-70) (TRDB-D5M) (TRDB-LTM)