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 }