merlinzjl

导航

Opencv形态学变换 膨胀腐蚀

  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 }

 

posted on 2021-01-31 22:09  merlinzjl  阅读(102)  评论(0编辑  收藏  举报