如何使用形态学操作去除同灰度噪声并保留图像竖线与对角线?
解决思路
1 定向形态学筛选替换通用核
你当前使用的椭圆、大尺寸矩形核适配性太泛,是引入额外噪声的主要原因,可直接针对目标线条方向制作专属结构元:
- 垂直方向保留:使用
Size(1, N)的矩形核做形态学运算,N设置为你需要保留的垂直线条最小长度,只有高度满足要求的垂直线条会被留存,短于该长度的噪声直接被过滤 - 45°/135°对角线方向:手动构造对应方向的斜线结构元,核内仅沿目标斜线位置赋值为1,其余为0,长度同样匹配目标线条的最小长度,仅会保留和核方向一致、长度达标的对角线条,其余方向杂点直接被滤除
2 几何特征过滤替代灰度阈值筛选
因为噪声和目标灰度一致,仅靠灰度运算无法区分,可直接基于线条的几何特征做筛选:
- 先调用
HoughLinesP霍夫线变换检测出图中所有直线段 - 按斜率做过滤:斜率绝对值>5的判定为垂直线,斜率落在0.81.2或者-1.2-0.8区间的判定为对角线
- 把符合条件的线段在空白画布上重新绘制,即可完全避开灰度一致的噪声干扰,直接得到纯净的目标线条结果
3 现有逻辑的后处理优化
如果你不想改动原有运算逻辑,可在当前带噪声的输出结果上追加连通域过滤步骤:
- 调用
connectedComponentsWithStats计算所有连通域的面积、宽高比、最小外接矩形倾斜角 - 过滤掉面积过小、宽高比不符合细长线条特征、角度不在垂直/对角线范围内的连通域,剩余即为目标线条
优化后参考代码
int main() { Mat src = imread("cau3.png", IMREAD_GRAYSCALE); Mat dst; // 自定义方向结构元,长度可根据实际线条长度调整 Mat kernel_vertical = getStructuringElement(MORPH_RECT, Size(1, 25)); // 手动构造45度斜线核,长度21 Mat kernel_45 = Mat::zeros(21, 21, CV_8U); for(int i=0; i<21; i++) kernel_45.at<uchar>(i, 20-i) = 1; // 手动构造135度斜线核,长度21 Mat kernel_135 = Mat::zeros(21, 21, CV_8U); for(int i=0; i<21; i++) kernel_135.at<uchar>(i, i) = 1; Mat res_vertical, res_45, res_135; // 对每个目标方向单独做顶帽运算,直接提取对应方向的亮线条 morphologyEx(src, res_vertical, MORPH_TOPHAT, kernel_vertical); morphologyEx(src, res_45, MORPH_TOPHAT, kernel_45); morphologyEx(src, res_135, MORPH_TOPHAT, kernel_135); // 合并三个方向的结果 bitwise_or(res_vertical, res_45, dst); bitwise_or(dst, res_135, dst); // 可选:连通域过滤残留小噪声 Mat labels, stats, centroids; int num_labels = connectedComponentsWithStats(dst, labels, stats, centroids); for(int i=1; i<num_labels; i++) { // 过滤面积小于30的连通域,阈值可自行调整 if(stats.at<int>(i, CC_STAT_AREA) < 30) { for(int y=stats.at<int>(i, CC_STAT_TOP); y<stats.at<int>(i, CC_STAT_TOP)+stats.at<int>(i, CC_STAT_HEIGHT); y++) { for(int x=stats.at<int>(i, CC_STAT_LEFT); x<stats.at<int>(i, CC_STAT_LEFT)+stats.at<int>(i, CC_STAT_WIDTH); x++) { if(labels.at<int>(y,x) == i) dst.at<uchar>(y,x) = 0; } } } } imshow("result", dst); waitKey(0); return 0; }
内容的提问来源于stack exchange,提问作者Vincent T
相关产品推荐
相关产品推荐

