在一张纸上提取对象

时间:2017-06-28 15:24:02

标签: opencv image-processing computer-vision

从一张纸上的工具图片中,我被要求找到它们的轮廓轮廓以对其进行矢量化。

我是计算机视觉相关问题的初学者,我唯一想到的就是OpenCV和边缘检测。

结果比我想象的要好,这仍然非常不可靠,特别是如果源图片不是“完美”的。

我拍了两张他们给我的扳手的照片。

在玩opencv bindings for node之后,我明白了:

good wrench contour

然后,我尝试了不那么好的画面:

enter image description here

这完全是不可饶恕的。 我可以通过改变Canny thresold来获得更好的东西,但必须自动化(假设图片相对正确)。

所以我有几个问题:

  • 我采取了正确的方法吗? GrabCut更适合这个吗? Grabcut和Canny边缘检测的组合?我仍然需要最后的顶点,但我觉得GrabCut也做了我想要的。
  • 边界粗糙且有一些错误。我可以增加approxPolyDP的乘数,但不会损失好的部件。
  • 与上述相关,我正在考虑整合Savitzky-Golay算法来平滑轮廓,而不是使用approxPolyDP进行多边形简化。这是个好主意吗?
  • 通常,外边框的线必须形成一个简单的可切割块。在OpenCL中有没有办法避免那条线做不可能的事情,比如传递自己? - 或者,简单地说,检测问题?当然,这些配置是不可能的,但在检测失败时会发生(如第二张图片中所示)。
  • 我正在寻找一种自动Canny thresold计算的方法,因为我必须为每个图像手动调整它。你有一个很好的例子吗?
  • 我注意到在边缘检测之前将图像转换为灰度有时会使结果恶化,有时会使图像变得更好。我应该选择哪一个? (工具可以是任何颜色btw!)

这是我测试的来源:

const cv = require('opencv');

const lowThresh = 90;
const highThresh = 90;
const nIters = 1;

const GRAY   = [120, 120, 120];
const WHITE = [255, 255, 255];

cv.readImage('./files/viv1.jpg', function(err, im) {
  if (err) throw err;

  width = im.width()
  height = im.height()
  if (width < 1 || height < 1) throw new Error('Image has no size');

  const out = new cv.Matrix(height, width);
  im.convertGrayscale();
  im_canny = im.copy();
  im_canny.canny(lowThresh, highThresh);
  im_canny.dilate(nIters);

  contours = im_canny.findContours();

  let maxArea = 0;
  let biggestContour;

  for (i = 0; i < contours.size(); i++) {
    const area = contours.area(i);
    if (area > maxArea) {
      maxArea = area;
      biggestContour = i;
    }

    out.drawContour(contours, i, GRAY);
  }

  const arcLength = contours.arcLength(biggestContour, true);
  contours.approxPolyDP(biggestContour, 0.001 * arcLength, true);

  out.drawContour(contours, biggestContour, WHITE, 5);

  out.save('./tmp/out.png');
  console.log('Image saved to ./tmp/out.png');
});

2 个答案:

答案 0 :(得分:1)

您需要添加一些预处理来清理图像。因为阴影,光线不足,工具高光等等,图像的强度变化很大,所以应该均衡图像。这将有助于您在目前光线不足或光泽度高的地区获得更好的响应。

这是一个关于C ++中直方图均衡的opencv教程:http://docs.opencv.org/2.4/doc/tutorials/imgproc/histograms/histogram_equalization/histogram_equalization.html

希望这有帮助

编辑: 您可以根据某些损失函数(?)设置自动阈值。例如:如果您知道该工具将在框架中完全捕获,您知道您应该在x = 10到x = 800(比如)的每一列都获得高值。然后,您可以继续降低阈值,直到从x = 10到x = 800的每一列都获得高值。这是一种非常天真的方式,但我认为这是一个有趣的实验,因为您正在生成图像你自己并控制对象放置。

答案 1 :(得分:1)

您也可以尝试先通过adaptive threshold运行图片。在这种情况下,这种类型的二值化非常适合分割前景和背景,即使光线/阴影不一致(这似乎是上面第二个例子中的问题)。 Adathresh将需要一些参数微调,但是一旦整个工具从背景中分割出来,Canny边缘检测应该会产生更一致的结果。

对于轮廓中的粗糙度,您可以尝试将findContours模式设置为CV_CHAIN_APPROX所述的{{1}}方法之一。