1 //生成三种基元 矩形 十字 椭圆
2 cv::Mat my_get_morph_struct_element(cv::MorphShapes shapeType, cv::Size s)
3 {
4 CV_Assert(shapeType == cv::MORPH_RECT || shapeType == cv::MORPH_CROSS || shapeType == cv::MORPH_ELLIPSE);
5
6 cv::Mat mat = cv::Mat::zeros(s, CV_8UC1);
7 switch (shapeType)
8 {
9 case cv::MORPH_RECT:
10 {
11 mat = 1;
12 break;
13 }
14 case cv::MORPH_CROSS:
15 {
16 cv::Mat rowROI(mat, cv::Rect(0, s.height / 2, s.width, 1));
17 rowROI = 1;
18 cv::Mat colROI(mat, cv::Rect(s.width / 2, 0, 1, s.height));
19 colROI = 1;
20 break;
21 }
22 case cv::MORPH_ELLIPSE:
23 {
24 int a = s.width / 2;
25 int b = s.height / 2;
26 //椭圆 公式 (x-xc)^2 / a^2 + (y-yc)^2 / b^2 = 1
27 for (int i = 0; i < s.height; i++)
28 {
29 int dy = i - b;
30 int startx = 0;
31 int endx = 0;
32 if (std::abs(dy) <= b)
33 {
34 int dx = 0;
35 if (b > 0)
36 {
37 dx = cv::saturate_cast<int>(a * std::sqrt(1 - (1.0 * dy / b)*(1.0 * dy / b)));
38 }
39 startx =std::max(a - dx, 0);
40 endx = std::min(a + dx + 1, s.width);
41 }
42
43 uchar * p = mat.ptr<uchar>(i);
44 for (int j = startx; j < endx; j++)
45 {
46 p[j] = 1;
47 }
48 }
49 break;
50 }
51 default:
52 CV_Assert(false);
53 break;
54 }
55
56 return mat;
57 }
58
59 //测试自己生成的基元
60 void test_my_get_morph_struct_element()
61 {
62 cv::MorphShapes shape = cv::MORPH_RECT;
63 cv::Size s(7, 8);
64 cv::Mat rectSE = cv::getStructuringElement(shape, s);
65 cv::Mat myRectSE = my_get_morph_struct_element(shape, s);
66 std::cout << "rectSE:\n" << rectSE << std::endl;
67 std::cout << "myrectSE:\n" << myRectSE << std::endl;
68
69 shape = cv::MORPH_CROSS;
70 rectSE = cv::getStructuringElement(shape, s);
71 myRectSE = my_get_morph_struct_element(shape, s);
72 std::cout << "CROSSSE:\n" << rectSE << std::endl;
73 std::cout << "mCROSSSE:\n" << myRectSE << std::endl;
74
75 shape = cv::MORPH_ELLIPSE;
76 rectSE = cv::getStructuringElement(shape, s);
77 myRectSE = my_get_morph_struct_element(shape, s);
78 std::cout << "MORPH_ELLIPSE:\n" << rectSE << std::endl;
79 std::cout << "mMORPH_ELLIPSE:\n" << myRectSE << std::endl;
80 }
81
82 //侵蚀与膨胀变换:
83 //图像上的一个点,以这个点为中心(假设为(i,j)点),结构元素的中心与这个中心重合
84 //然后取出图像上被结构元素覆盖的那一小片(对于边界处,作边界扩展),如果结构元素的值
85 //为1,则从这一小片图像中对于的位置取出值,所有结构元素为1的位置都取出了对应那一
86 //小片图像中的值后,这些值中再取出最大值和最小值,对于侵蚀变换,则点(i,j)的值设置
87 //为最小值,而膨胀变换,则点(i,j)的值设置为最大值。
88
89 /*
90 *matPadded 按照结构元补充过边界后的矩阵
91 */
92 cv::Mat my_erode_dilate(const cv::Mat& matPadded, const cv::Mat& se, bool isErode)
93 {
94 CV_Assert(matPadded.type() == CV_8UC1);
95 CV_Assert(se.type() == CV_8UC1);
96
97 int rows = matPadded.rows - se.rows;
98 int cols = matPadded.cols - se.cols;
99 cv::Mat mat(rows, cols, CV_8UC1);
100 for (int i = 0; i < rows; i++)
101 {
102 uchar *p = mat.ptr<uchar>(i);
103 for (int j = 0; j < cols; j++)
104 {
105 cv::Mat roi(matPadded, cv::Rect(j, i, se.cols, se.rows));
106 std::vector<uchar> v;
107 for (int ii = 0; ii < roi.rows; ii++)
108 {
109 uchar * pp = roi.ptr<uchar>(ii);
110 const uchar * ppp = se.ptr<uchar>(ii);
111 for (int jj = 0; jj < roi.cols; jj++)
112 {
113 if (ppp[jj] == 1)
114 {
115 v.push_back(pp[jj]);
116 }
117 }
118 }
119 std::sort(v.begin(), v.end());
120 p[j] = isErode ? v[0] : v[v.size() - 1];
121 }
122 }
123
124 return mat;
125 }
126
127
128 void test_my_erode_dilate()
129 {
130 cv::Mat src = cv::imread("D:\\programfiles\\OpenCV\\opencv-4.4.0\\samples\\data\\lena.jpg", IMREAD_GRAYSCALE);
131 if (src.empty())
132 {
133 std::cout << "Failed to load img!!" << std::endl;
134 return;
135 }
136
137 //opencv自带
138 cv::MorphShapes shape = cv::MorphShapes::MORPH_ELLIPSE;
139 cv::Size seSize(7, 8);
140 cv::Mat se = cv::getStructuringElement(shape, seSize);
141 cv::Mat erodeMat;
142 cv::Mat dilateMat;
143 cv::erode(src, erodeMat, se);
144 cv::dilate(src, dilateMat, se);
145 cv::imshow("erode", erodeMat);
146 cv::imshow("dilate", dilateMat);
147
148 //自己实现的
149 //填充边界
150 int padLeft = se.cols / 2;
151 int padRight = (se.cols % 2 == 0) ? se.cols / 2 - 1 : se.cols / 2;
152 int padTop = se.rows / 2;
153 int padBot = (se.rows % 2 == 0) ? se.rows / 2 - 1 : se.rows / 2;
154 cv::Mat paddedMat;
155 cv::copyMakeBorder(src, paddedMat, padTop, padBot, padLeft, padRight, BORDER_REFLECT101);
156 cv::Mat myErodeMat = my_erode_dilate(paddedMat, se, true);
157 cv::Mat myDilateMat = my_erode_dilate(paddedMat, se, false);
158 cv::imshow("myErodeMat", myErodeMat);
159 cv::imshow("myDilateMat", myDilateMat);
160
161 waitKey(0);
162 }