Morgan Touverey Quilling
Morgan Touverey Quilling

Reputation: 4333

Extract an object on a sheet of paper

From pictures of tools on a sheet of paper, I'm asked to find their outline contour to vectorize them.

I'm a total beginner in computer-vision-related problems and the only thing I thought about was OpenCV and edge detection.

The result is better than what I've imagined, this is still very unreliable, especially if the source picture isn't "perfect".

I took 2 photographies of a wrench they gave me.

After playing around with opencv bindings for node, I get this:

good wrench contour

Then, I've tried with the less-good picture:

enter image description here

That's totally inexploitable. I can get something a little better by changing the Canny thresold, but that must be automatized (given that the picture is relatively correct).

So I've got a few questions:

here is the source for my tests:

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');
});

Upvotes: 4

Views: 954

Answers (2)

CanyonCat
CanyonCat

Reputation: 339

You might also try running your images through an adaptive threshold first. This type of binarization is fairly adept at segmenting foreground and background in cases like this, even with inconsistent lighting/shadows (which seems to be the issue in your second example above). Adathresh will require some parameter fine-tuning, but once the entire tool is segmented from the background, Canny edge detection should produce more consistent results.

As for the roughness in your contours, you could try setting your findContours mode to one of the CV_CHAIN_APPROX methods described here.

Upvotes: 1

Shawn Mathew
Shawn Mathew

Reputation: 2337

You'll need to add some pre-processing to clean up the image. Because you have a large variation in intensities in the image because of shadow, poor lighting, high shine on tools, etc you should equalize the image. This will help you get a better response in the regions that are currently poorly lit or have high shine.

Here's an opencv tutorial on Histogram equalization in C++: http://docs.opencv.org/2.4/doc/tutorials/imgproc/histograms/histogram_equalization/histogram_equalization.html

Hope this helps

EDIT: You can have an automatic threshold based on some loss function(?). For eg: If you know that the tool will be completely captured in the frame, you know that you should get a high value at every column from x = 10 to x = 800(say). You could then keep reducing the threshold until you get a high value at every column from x = 10 to x = 800. This is a very naive way of doing it, but its an interesting experiment, I think, since you are generating the images yourself and have control over object placement.

Upvotes: 1

Related Questions