2

我正在开发一个项目,使用 OpenCV 3.3 处理如下图所示的大理石板图像。

大理石板图像

可以在https://1drv.ms/f/s!AjoScZ1lKToFheM6wmamv45R7zHwaQ上找到更多我正在处理的具有不同大理石纹理和尺寸的样本

要求是:

  1. 将大理石板与背景分开并移除背景(填充白色),以便只显示板。
  2. 计算平板的面积(相机到大理石平板的距离和镜头的参数已知)

我使用的策略是:1)找到大理石板的轮廓,2)删除不在轮廓内的部分,3)获取轮廓的面积大小,4)计算其物理面积。

板坯的轮廓如下图红色所示(这是手工完成的)。

板轮廓

我尝试了几种方法在图像中找到板的轮廓,但由于背景复杂,大理石纹理丰富,未能达到令人满意的效果。

我正在使用的处理逻辑是:将图像转换为灰色并对其进行模糊处理并使用Canny查找边缘,然后使用findContours查找轮廓,代码如下:

Mat img = imread('test2.jpg', 1);
Mat gray, edge;
cvtColor(img, gray, COLOR_BGR2GRAY);
blur(gray, gray, Size(3, 3));

Canny(gray, edge, 50, 200, 3);

vector<vector<Point> > contours;
vector<Vec4i> lines;
findContours(edge, contours, RETR_LIST, CHAIN_APPROX_SIMPLE);

cout << "Number of contours detected: " << contours.size() << endl;

vector<Vec4i> hierarchy;

for (int i = 0; i < contours.size(); i++)
{
    drawContours(img, contours, i, Scalar(0, 0, 255), 1, 8, hierarchy, 0, Point());
}

imshow("Output", img);

我尝试为数十种组合调整模糊和 Canny 参数,但仍然失败。我还尝试使用 HoughLinesP 找到具有几组不同参数的板的边缘,但也没有这样做。

我是计算机视觉的新手,我现在的问题是:

  1. 我是否正在寻找错误的方法或策略来找到平板轮廓?有没有更好的算法或组合?还是我需要专注于调整 Canny/findContours/HoughLinesP 算法的参数?
  2. 由于背景复杂,这种图像真的很难处理吗?

我愿意接受任何可以帮助我完成目标的建议。先感谢您。

4

1 回答 1

3

您可以考虑的技术

  1. 模板匹配,您可能需要为不同的大理石准备很多模板(光照条件,旋转等)
  2. 训练一个分类器+区域建议,只有在其他解决方案失败时才采用这个解决方案(这个解决方案可能是最健壮的一个,但也是实现起来最冗长的一个)

由于您只有 10~20 种大理石板,我认为解决方案 1 是一个好的开始。

  1. 手动找出大理石的4个角点,做透视变换

    pair<Mat, vector<Point2f>> get_target_marble(Mat const &input, vector<Point2f> const &src_pts)
    {
    using namespace cv;
    using namespace std;
    
    Point2f const tl = src_pts[0];
    Point2f const tr = src_pts[1];
    Point2f const br = src_pts[2];
    Point2f const bl = src_pts[3];
    
    auto const euclidean_dist = [](Point const &a, Point const &b)
    {
        return std::sqrt(std::pow(a.x-b.x, 2) + std::pow(a.y - b.y, 2));
    };
    int const max_width = static_cast<int>(std::max(euclidean_dist(br, bl), euclidean_dist(tr, tl)));
    int const max_height = static_cast<int>(std::max(euclidean_dist(tr, br), euclidean_dist(tl, bl)));
    
    vector<Point2f> const src{tl, tr, br, bl};
    vector<Point2f> dst{Point(0,0), Point(max_width -1,0), Point(max_width-1,max_height-1), Point(0,max_height-1)};
    Mat const hmat = getPerspectiveTransform(src, dst);
    Mat target;
    warpPerspective(input, target, hmat, {max_width, max_height});
    
    return std::make_pair(std::move(target), std::move(dst));
    

    }

在此处输入图像描述

  1. 找出查询图像(大理石板)和训练图像(图像可能包含大理石板)之间的单应矩阵

    Mat find_homography(Mat const &train, Mat const &query)
    {
    Ptr<AKAZE> akaze = AKAZE::create();
    vector<KeyPoint> query_kpts, train_kpts;
    cv::Mat query_desc, train_desc;
    akaze->detectAndCompute(train, cv::noArray(), query_kpts, query_desc);
    akaze->detectAndCompute(query, cv::noArray(), train_kpts, train_desc);
    
    BFMatcher matcher(NORM_HAMMING);
    vector<vector<DMatch>> nn_matches;
    //top 2 matches because we need to apply David Lowe's ratio test
    matcher.knnMatch(train_desc, query_desc, nn_matches, 2);
    
    vector<KeyPoint> matches1, matches2;
    for(auto const &m : nn_matches){
        float const dist1 = m[0].distance;
        float const dist2 = m[1].distance;
        if(dist1 < 0.7 * dist2){
            matches1.emplace_back(train_kpts[m[0].queryIdx]);
            matches2.emplace_back(query_kpts[m[0].trainIdx]);
        }
    }
    
    if(matches1.size() > 4){
        std::vector<cv::Point2f> points1, points2;
        for(size_t i = 0; i != matches1.size(); ++i){
            points1.emplace_back(matches1[i].pt);
            points2.emplace_back(matches2[i].pt);
        }
        return cv::findHomography(points1, points2, cv::RANSAC, 5.0);
    }
    
    return {};
    

    }

在此处输入图像描述

  1. 将 4 行查询图像映射到目标图像

    vector<Point2f> query_points;
    vector<Point> qpts;
    perspectiveTransform(dst, query_points, hmat);
    for(auto const &pt : query_points){
        cout<<pt<<endl;
        qpts.emplace_back(pt);
    }
    
    polylines(input, qpts, true, {255,0,0}, 2);
    

在此处输入图像描述

您需要为此解决方案准备 10 到 20 张图像,更喜欢存在大多数匹配点的图像来定位您的大理石板。如果性能是一个问题,请降低图像的分辨率,您不需要大图像来获得结果。

完整的代码放在github 上

ps : 我不知道你的项目细节,如果只有10~20种大理石板+所有的都有很好的特征可以跟踪,你不需要3个月来解决它(但你可以告诉你的老板/您需要 3 个月的客户 :),有时更好的性能只会带来更多的家务,但不会带来更多的钱)。

于 2017-10-02T06:45:43.003 回答