从一张纸上的工具图片中,我被要求找到它们的轮廓轮廓以对其进行矢量化。
我是计算机视觉相关问题的初学者,我唯一想到的就是OpenCV和边缘检测。
结果比我想象的要好,这仍然非常不可靠,特别是如果源图片不是“完美”的。
我拍了两张他们给我的扳手的照片。
在玩opencv bindings for node之后,我明白了:
然后,我尝试了不那么好的画面:
这完全是不可饶恕的。 我可以通过改变Canny thresold来获得更好的东西,但必须自动化(假设图片相对正确)。
所以我有几个问题:
approxPolyDP
的乘数,但不会损失好的部件。approxPolyDP
进行多边形简化。这是个好主意吗?这是我测试的来源:
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');
});
答案 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}}方法之一。