非连接形态滤波器
Non connecting morphological filter
经过一些简单的预处理后,我收到了分割图像的布尔掩码。
我想要 "enhance" 蒙版的边界并使它们更平滑。为此,我使用了具有相当大的圆核的 OPEN 形态过滤器,它工作得很好,直到分割对象之间的距离足够大。但是在很多样本中,对象粘在一起。是否存在一些或多或少简单的方法来平滑此类图像而不改变其形态?
不能 100% 确定您要实现的目标,但这可能是探索的途径...工具 potrace
拍摄图像并将它们转换为涉及平滑的矢量化图像。它更喜欢 PGM
格式的输入文件,所以我使用 ImageMagick 来准备它们。不管怎样,这里有一个命令和结果的例子,看看你的想法:
convert disks.png pgm:- | potrace - -s -o out.svg
我已将生成的 SVG
文件转换为 PNG
,因此我可以将其上传到 SO。
在不先应用形态学过滤器的情况下,您可以尝试检测图像的外部轮廓。现在您可以将这些外部轮廓绘制为填充轮廓,然后应用形态过滤器。这是有效的,因为现在你没有任何漏洞可以填补。这很简单。
另一种方法:
- 寻找外部轮廓
- 取轮廓点坐标的x,y。您可以将这些视为一维信号并对这些信号应用平滑滤波器
在下面的代码中,我将第二种方法应用于示例图像。
输入图片
没有任何平滑的外部轮廓
对 x 和 y 一维信号应用高斯滤波器后
C++代码
Mat im = imread("4.png", 0);
Mat cont = im.clone();
Mat original = Mat::zeros(im.rows, im.cols, CV_8UC3);
Mat smoothed = Mat::zeros(im.rows, im.cols, CV_8UC3);
// contour smoothing parameters for gaussian filter
int filterRadius = 5;
int filterSize = 2 * filterRadius + 1;
double sigma = 10;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
// find external contours and store all contour points
findContours(cont, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE, Point(0, 0));
for(size_t j = 0; j < contours.size(); j++)
{
// draw the initial contour shape
drawContours(original, contours, j, Scalar(0, 255, 0), 1);
// extract x and y coordinates of points. we'll consider these as 1-D signals
// add circular padding to 1-D signals
size_t len = contours[j].size() + 2 * filterRadius;
size_t idx = (contours[j].size() - filterRadius);
vector<float> x, y;
for (size_t i = 0; i < len; i++)
{
x.push_back(contours[j][(idx + i) % contours[j].size()].x);
y.push_back(contours[j][(idx + i) % contours[j].size()].y);
}
// filter 1-D signals
vector<float> xFilt, yFilt;
GaussianBlur(x, xFilt, Size(filterSize, filterSize), sigma, sigma);
GaussianBlur(y, yFilt, Size(filterSize, filterSize), sigma, sigma);
// build smoothed contour
vector<vector<Point> > smoothContours;
vector<Point> smooth;
for (size_t i = filterRadius; i < contours[j].size() + filterRadius; i++)
{
smooth.push_back(Point(xFilt[i], yFilt[i]));
}
smoothContours.push_back(smooth);
drawContours(smoothed, smoothContours, 0, Scalar(255, 0, 0), 1);
cout << "debug contour " << j << " : " << contours[j].size() << ", " << smooth.size() << endl;
}
经过一些简单的预处理后,我收到了分割图像的布尔掩码。
我想要 "enhance" 蒙版的边界并使它们更平滑。为此,我使用了具有相当大的圆核的 OPEN 形态过滤器,它工作得很好,直到分割对象之间的距离足够大。但是在很多样本中,对象粘在一起。是否存在一些或多或少简单的方法来平滑此类图像而不改变其形态?
不能 100% 确定您要实现的目标,但这可能是探索的途径...工具 potrace
拍摄图像并将它们转换为涉及平滑的矢量化图像。它更喜欢 PGM
格式的输入文件,所以我使用 ImageMagick 来准备它们。不管怎样,这里有一个命令和结果的例子,看看你的想法:
convert disks.png pgm:- | potrace - -s -o out.svg
我已将生成的 SVG
文件转换为 PNG
,因此我可以将其上传到 SO。
在不先应用形态学过滤器的情况下,您可以尝试检测图像的外部轮廓。现在您可以将这些外部轮廓绘制为填充轮廓,然后应用形态过滤器。这是有效的,因为现在你没有任何漏洞可以填补。这很简单。
另一种方法:
- 寻找外部轮廓
- 取轮廓点坐标的x,y。您可以将这些视为一维信号并对这些信号应用平滑滤波器
在下面的代码中,我将第二种方法应用于示例图像。
输入图片
没有任何平滑的外部轮廓
对 x 和 y 一维信号应用高斯滤波器后
C++代码
Mat im = imread("4.png", 0);
Mat cont = im.clone();
Mat original = Mat::zeros(im.rows, im.cols, CV_8UC3);
Mat smoothed = Mat::zeros(im.rows, im.cols, CV_8UC3);
// contour smoothing parameters for gaussian filter
int filterRadius = 5;
int filterSize = 2 * filterRadius + 1;
double sigma = 10;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
// find external contours and store all contour points
findContours(cont, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE, Point(0, 0));
for(size_t j = 0; j < contours.size(); j++)
{
// draw the initial contour shape
drawContours(original, contours, j, Scalar(0, 255, 0), 1);
// extract x and y coordinates of points. we'll consider these as 1-D signals
// add circular padding to 1-D signals
size_t len = contours[j].size() + 2 * filterRadius;
size_t idx = (contours[j].size() - filterRadius);
vector<float> x, y;
for (size_t i = 0; i < len; i++)
{
x.push_back(contours[j][(idx + i) % contours[j].size()].x);
y.push_back(contours[j][(idx + i) % contours[j].size()].y);
}
// filter 1-D signals
vector<float> xFilt, yFilt;
GaussianBlur(x, xFilt, Size(filterSize, filterSize), sigma, sigma);
GaussianBlur(y, yFilt, Size(filterSize, filterSize), sigma, sigma);
// build smoothed contour
vector<vector<Point> > smoothContours;
vector<Point> smooth;
for (size_t i = filterRadius; i < contours[j].size() + filterRadius; i++)
{
smooth.push_back(Point(xFilt[i], yFilt[i]));
}
smoothContours.push_back(smooth);
drawContours(smoothed, smoothContours, 0, Scalar(255, 0, 0), 1);
cout << "debug contour " << j << " : " << contours[j].size() << ", " << smooth.size() << endl;
}