需要帮助实施特殊的边缘检测器
我正在从一篇研究论文中实施一种方法。 部分方法需要一个主要的边缘检测器,作者描述如下:
请注意,这不是 Canny边缘检测 - 它们不会打扰非最大抑制等事情。我当然可以用Canny边缘检测来做到这一点,但我希望按照文中所表达的内容来实现。
最后一步是我有点卡住了。
这正是作者对此所说的:
在从边缘检测过程获得二值边缘图之后,采用二值形态学操作去除孤立的边缘像素,这可能在边缘检测期间引起误报警
以下是所有事情应该看起来如何(边缘块已填充为黑色):
如果我跳过最后一步,这就是我所拥有的:
这似乎是在正确的轨道上。 所以,如果我为步骤4做了腐蚀,会发生什么情况:
我尝试过腐蚀和膨胀的组合,以获得与他们相同的结果,但不要靠近。 任何人都可以提出形态运算符的组合,这将使我获得期望的结果吗?
这里是二值化输出,以防有人想玩弄它:
如果你真的很热心,这里是源代码(C ++):
#include <cv.h>
#include <highgui.h>
#include <stdlib.h>
#include <assert.h>
using cv::Mat;
using cv::Size;
#include <stdio.h>
#define DCTSIZE 8
#define EDGE_PX 255
/*
* Display a matrix as an image on the screen.
*/
void
show_mat(char *heading, Mat const &m)
{
Mat clone = m.clone();
Mat scaled(clone.size(), CV_8UC1);
convertScaleAbs(clone, scaled);
IplImage ipl = scaled;
cvNamedWindow(heading, CV_WINDOW_AUTOSIZE);
cvShowImage(heading, &ipl);
cvWaitKey(0);
}
/*
* Get the DC components of the specified matrix as an image.
*/
Mat
get_dc(Mat const &m)
{
Size s = m.size();
assert(s.width % DCTSIZE == 0);
assert(s.height % DCTSIZE == 0);
Size dc_size = Size(s.height/DCTSIZE, s.width/DCTSIZE);
Mat dc(dc_size, CV_32FC1);
cv::resize(m, dc, dc_size, 0, 0, cv::INTER_AREA);
return dc;
}
/*
* Detect the edges:
*
* Sobel operator
* Thresholding
* Morphological operations
*/
Mat
detect_edges(Mat const &src, int T)
{
Mat sobelx = Mat(src.size(), CV_32FC1);
Mat sobely = Mat(src.size(), CV_32FC1);
Mat sobel_sum = Mat(src.size(), CV_32FC1);
cv::Sobel(src, sobelx, CV_32F, 1, 0, 3, 0.5);
cv::Sobel(src, sobely, CV_32F, 0, 1, 3, 0.5);
cv::add(cv::abs(sobelx), cv::abs(sobely), sobel_sum);
Mat binarized = src.clone();
cv::threshold(sobel_sum, binarized, T, EDGE_PX, cv::THRESH_BINARY);
cv::imwrite("binarized.png", binarized);
//
// TODO: this is the part I'm having problems with.
//
#if 0
//
// Try a 3x3 cross structuring element.
//
Mat elt(3,3, CV_8UC1);
elt.at<uchar>(0, 1) = 0;
elt.at<uchar>(1, 0) = 0;
elt.at<uchar>(1, 1) = 0;
elt.at<uchar>(1, 2) = 0;
elt.at<uchar>(2, 1) = 0;
#endif
Mat dilated = binarized.clone();
//cv::dilate(binarized, dilated, Mat());
cv::imwrite("dilated.png", dilated);
Mat eroded = dilated.clone();
cv::erode(dilated, eroded, Mat());
cv::imwrite("eroded.png", eroded);
return eroded;
}
/*
* Black out the blocks in the image that contain DC edges.
*/
void
censure_edge_blocks(Mat &orig, Mat const &edges)
{
Size s = edges.size();
for (int i = 0; i < s.height; ++i)
for (int j = 0; j < s.width; ++j)
{
if (edges.at<float>(i, j) != EDGE_PX)
continue;
int row = i*DCTSIZE;
int col = j*DCTSIZE;
for (int m = 0; m < DCTSIZE; ++m)
for (int n = 0; n < DCTSIZE; ++n)
orig.at<uchar>(row + m, col + n) = 0;
}
}
/*
* Load the image and return the first channel.
*/
Mat
load_grayscale(char *filename)
{
Mat orig = cv::imread(filename);
std::vector<Mat> channels(orig.channels());
cv::split(orig, channels);
Mat grey = channels[0];
return grey;
}
int
main(int argc, char **argv)
{
assert(argc == 3);
int bin_thres = atoi(argv[2]);
Mat orig = load_grayscale(argv[1]);
//show_mat("orig", orig);
Mat dc = get_dc(orig);
cv::imwrite("dc.png", dc);
Mat dc_edges = detect_edges(dc, bin_thres);
cv::imwrite("dc_edges.png", dc_edges);
censure_edge_blocks(orig, dc_edges);
show_mat("censured", orig);
cv::imwrite("censured.png", orig);
return 0;
}
我无法想象任何形态学操作的组合,如果你的部分结果作为输入,将会产生与假定的正确结果相同的边缘。
我注意到底层的形象是不同的; 这可能有助于你的结果如此不同。 Lena图像适用于指示结果的类型,但不适用于比较。 你有与原作者完全相同的图像吗?
作者描述的可以通过使用8way连接的连接组件分析来实现。 我不会称这种形态。
我认为你错过了其他的东西:他们的图像没有比一个像素厚的边缘。 你的。 您所引用的段落只是讨论去除孤立像素,所以必须有一个步骤您错过或实施不同。
祝你好运!
我认为你需要的是一种侵蚀或开放,即从某种意义上说是4路而不是8路。 OpenCV的默认形态内核是一个3x3的矩形( shape
= CV_SHAPE_RECT
IplConvKernel
)。 这在薄边上非常苛刻。
您可能想尝试使用shape
= CV_SHAPE_CROSS
的3x3自定义IplConvKernel
侵蚀。 如果你需要一个更精细的过滤器,你可能想尝试使用4个不同的CV_SHAPE_RECT
内核,大小为1x2,2x1,锚点分别为(0,1)和(1,0)。
上一篇: Need help implementing a special edge detector
下一篇: How to check if a checkbox in a checkbox array is checked with jquery