是否有可能找到的边缘"参差不齐"在emgucv区域?

是否有可能找到的边缘"参差不齐"在emgucv区域?

问题描述:

我有一个看起来像这样的图片:

I have an image that looks like this:

和我想要找的暗部的边缘,使这样的(红线是我所期待的):

and I want to find the edges of the dark part so like this (the red lines are what I am looking for):

我已经尝试了几种方法,没有工作过,所以我希望能有一个emgu大师那里肯帮我...

I have tried a few approaches and none have worked so I am hoping there is an emgu guru out there willing to help me...

  • 将图像转换为灰度
  • 删除噪音和反
  • 在删除任何东西是不是真明丽
  • 获取的精明和多边形

code本(我知道,我应该处理的正确的事情,但我保持了code短):

Code for this (I know that I should be disposing of things properly but I am keeping the code short):

var orig = new Image<Bgr, byte>(inFile);

var contours = orig
    .Convert<Gray, byte>()
    .PyrDown()
    .PyrUp()
    .Not()
    .InRange(new Gray(190), new Gray(255))
    .Canny(new Gray(190), new Gray(255))
    .FindContours(CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE,
                  RETR_TYPE.CV_RETR_TREE);

var output = new Image<Gray, byte>(orig.Size);    
for (; contours != null; contours = contours.HNext)
{
    var poly = contours.ApproxPoly(contours.Perimeter*0.05,
                                   contours.Storage);
    output.Draw(poly, new Gray(255), 1);
}
output.Save(outFile);

这是结果:

  • 将图像转换为灰度
  • 删除噪音和反
  • 在删除任何东西是不是真明丽
  • 获取精明再行

$ C $下这样的:

Code for this:

var orig = new Image<Bgr, byte>(inFile);

var linesegs = orig
    .Convert<Gray, byte>()
    .PyrDown()
    .PyrUp()
    .Not()
    .InRange(new Gray(190), new Gray(255))
    .Canny(new Gray(190), new Gray(255))
    .HoughLinesBinary(
        1,
        Math.PI/45.0,
        20,
        30,
        10
    )[0];

var output = new Image<Gray, byte>(orig.Size);    
foreach (var l in linesegs)
{
    output.Draw(l, new Gray(255), 1);
}
output.Save(outFile);

这是结果:

注意

我已经尝试了所有调节参数上这两种方法并添加平滑,但我永远不能得到,我需要,因为,我想简单的边缘,较暗的区域不是纯色。

I have tried adjusting all the parameters on those two approaches and adding smoothing but I can never get the simple edges that I need because, I suppose, the darker region is not a solid colour.

我也尝试过扩张和侵蚀,但我必须把这些参数是如此之高,以得到一个单一的颜色,我结束了,包括一些灰色的东西在右侧,失去精确度。

I have also tried dilating and eroding but the parameters I have to put in for those are so high to get a single colour that I end up including some of the grey stuff on the right and lose accuracy.

是的,这是可能的,这里是你如何能做到这一点:

Yes, it's possible, and here is how you could do it:

  • 更改图像的对比度,使打火机的部分消失:

  • 然后,将其转换为HSV,以在饱和通道进行阈值操作:

  • 和执行侵蚀和放大器;扩张业务,以摆脱噪音:

在这一点上,你将有你要找的结果。出于测试目的,在最后我执行包围盒的技术,以显示如何检测beggining和感兴趣的区域的末端

At this point you'll have the result you were looking for. For testing purposes, at the end I execute the bounding box technique to show how to detect the beggining and the end of the area of interest:

我没有来调整参数,使一个完美的检测时间,但我敢肯定,你自己看着办吧。这个答案提供了一个路线图,实现了!

I didn't have the time to tweak the parameters and make a perfect detection, but I'm sure you can figure it out. This answer provides a roadmap for achieving that!

这是C ++ code我想到了,我相信你有能力将其转换为C#的:

This is the C++ code I came up with, I trust you are capable of converting it to C#:

#include <cv.h>
#include <highgui.h>

int main(int argc, char* argv[])
{
    cv::Mat image = cv::imread(argv[1]);
    cv::Mat new_image = cv::Mat::zeros(image.size(), image.type());

    /* Change contrast: new_image(i,j) = alpha*image(i,j) + beta */

    double alpha = 1.8;     // [1.0-3.0]
    int beta = 100;         // [0-100]
    for (int y = 0; y < image.rows; y++)
    { 
        for (int x = 0; x < image.cols; x++)
        { 
        for (int c = 0; c < 3; c++)
        {
            new_image.at<cv::Vec3b>(y,x)[c] = 
            cv::saturate_cast<uchar>(alpha * (image.at<cv::Vec3b>(y,x)[c]) + beta);
        }
        }
    }
    cv::imshow("contrast", new_image);

    /* Convert RGB Mat into HSV color space */

    cv::Mat hsv;
    cv::cvtColor(new_image, hsv, CV_BGR2HSV);
    std::vector<cv::Mat> v;
    cv::split(hsv,v);

    // Perform threshold on the S channel of hSv    
    int thres = 15;
    cv::threshold(v[1], v[1], thres, 255, cv::THRESH_BINARY_INV);
    cv::imshow("saturation", v[1]);

    /* Erode & Dilate */

    int erosion_size = 6;   
    cv::Mat element = cv::getStructuringElement(cv::MORPH_CROSS,
                          cv::Size(2 * erosion_size + 1, 2 * erosion_size + 1), 
                          cv::Point(erosion_size, erosion_size) );
    cv::erode(v[1], v[1], element);
    cv::dilate(v[1], v[1], element);    
    cv::imshow("binary", v[1]);

    /* Bounding box */

    // Invert colors
    cv::bitwise_not(v[1], v[1]);

    // Store the set of points in the image before assembling the bounding box
    std::vector<cv::Point> points;
    cv::Mat_<uchar>::iterator it = v[1].begin<uchar>();
    cv::Mat_<uchar>::iterator end = v[1].end<uchar>();
    for (; it != end; ++it)
    {
        if (*it) points.push_back(it.pos());
    }    

    // Compute minimal bounding box
    cv::RotatedRect box = cv::minAreaRect(cv::Mat(points));

    // Draw bounding box in the original image (debug purposes)
    cv::Point2f vertices[4];
    box.points(vertices);
    for (int i = 0; i < 4; ++i)
    {
        cv::line(image, vertices[i], vertices[(i + 1) % 4], cv::Scalar(0, 255, 0), 2, CV_AA);
    }

    cv::imshow("box", image);    
    cvWaitKey(0);

    return 0;
}