Opencv 提取一张纸上的对象
从一张纸上工具的图片中,我被要求找到它们的轮廓线,以便对它们进行矢量化 我是计算机视觉相关问题的初学者,我唯一想到的就是OpenCV和边缘检测 结果比我想象的要好,这仍然是非常不可靠的,特别是如果源图片不是“完美的” 我拍了两张他们给我的扳手的照片 玩过之后,我发现: 然后,我尝试使用不太好的图片: 那是完全不可开发的。 我可以通过改变Canny thresold得到一些更好的东西,但这必须是自动化的(因为图片相对正确) 所以我有几个问题:Opencv 提取一张纸上的对象,opencv,image-processing,computer-vision,Opencv,Image Processing,Computer Vision,从一张纸上工具的图片中,我被要求找到它们的轮廓线,以便对它们进行矢量化 我是计算机视觉相关问题的初学者,我唯一想到的就是OpenCV和边缘检测 结果比我想象的要好,这仍然是非常不可靠的,特别是如果源图片不是“完美的” 我拍了两张他们给我的扳手的照片 玩过之后,我发现: 然后,我尝试使用不太好的图片: 那是完全不可开发的。 我可以通过改变Canny thresold得到一些更好的东西,但这必须是自动化的(因为图片相对正确) 所以我有几个问题: 我是否采取了正确的方法?格拉布切更适合这个吗?G
- 我是否采取了正确的方法?格拉布切更适合这个吗?Grabcut和Canny边缘检测的组合?我仍然需要在最后的顶点,但我觉得GrabCut也做了我想要的
- 边界很粗糙,有一定的误差。我可以增加
的乘法器,但不会损失好零件的精度approxPolyDP
- 与上述观点相关,我正在考虑集成Savitzky-Golay算法来平滑轮廓,而不是使用
进行多边形简化。这是个好主意吗approxPolyDP
- 通常,外边界线必须形成一个简单的可切割块。在OpenCL中有没有一种方法可以避免这一行去做不可能的事情,比如传递自己或者,简单地说,检测问题?当然,这些配置是不可能的,但在检测失败时会发生(如第二张图片中所示)
- 我正在寻找一种方法来进行自动Canny thresold计算,因为我必须为每个图像手动调整它。你有一个很好的例子吗
- 我注意到在边缘检测之前将图像转换为灰度有时会恶化结果,有时会使其更好。我应该选择哪一个?(顺便说一句,工具可以是任何颜色!)
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');
});
const cv=require('opencv');
常数低阈值=90;
常数highThresh=90;
常数=1;
常数灰=[120120120];
常量白色=[255,255,255];
cv.readImage('./files/viv1.jpg',函数(err,im){
如果(错误)抛出错误;
宽度=im.width()
高度=仪表高度()
如果(宽度<1 | |高度<1)抛出新错误(“图像没有大小”);
const out=新的cv.矩阵(高度、宽度);
im.grayscale();
im_canny=im.copy();
我精明,精明(低thresh,高thresh);
扩张(硝石);
等高线=im_canny.findContours();
设maxArea=0;
让我们来看看你的轮廓;
对于(i=0;i最大面积){
最大面积=面积;
最大轮廓=i;
}
out.drawContour(轮廓,i,灰色);
}
const arcLength=等高线.arcLength(最大等高线,真);
等高线。近似多边形(最大等高线,0.001*弧长,真);
out.drawContour(轮廓,最大轮廓,白色,5);
out.save('./tmp/out.png');
log('Image saved to./tmp/out.png');
});
您需要添加一些预处理来清理图像。由于阴影、照明不良、工具上的高亮度等原因,图像中的强度变化很大,因此应均衡图像。这将有助于您在当前光线不足或光线较高的区域获得更好的响应
下面是一个关于C++中直方图均衡化的opencv教程:
希望这有帮助
编辑:
你可以有一个基于损失函数(?)的自动阈值。例如:如果您知道该工具将完全捕获到框架中,那么您知道应该在x=10到x=800(比如)的每一列中获得一个高值。然后,您可以继续降低阈值,直到在每个列上获得一个从x=10到x=800的高值。这是一种非常幼稚的方法,但我认为这是一个有趣的实验,因为您自己生成图像,并且可以控制对象的放置。您也可以尝试通过第一次运行图像。在这种情况下,这种类型的二值化非常擅长分割前景和背景,即使在不一致的照明/阴影(这似乎是上面第二个示例中的问题)下也是如此。Adathresh需要一些参数微调,但一旦整个工具从背景中分割出来,Canny边缘检测应该会产生更一致的结果
至于轮廓的粗糙度,您可以尝试将
findContours
模式设置为所述的CV\u CHAIN\u近似方法之一 非均匀背景的检测算法removal@AnderBiguri你说的是格拉布切吗?我越来越认为这可能是答案。我想我将使用基于Canny的解决方案来确定GrabCut的对象边界。然后应用GrabCut,这也将允许用户在需要时进行纠正(使用遮罩)。然后从GrabCut的输出中再次检测边缘(因为背景将被移除,所以它将非常有效,就像我在谷歌上拍摄绕道图像一样)。看起来可行。为了确定物体的大小,我想我会使用阿鲁科标记。这个系统是如何工作的(流程方面)?为什么我要问机器视觉系统,在你的图像中。。。嗯,看起来不太理想。第一张照片相当不错,虽然你仍然在中间看到圆形渐变明亮。第二个很可怕。如果你能解决这个问题(假设它是可行的),你很可能会为自己省下很多工作或可能的失败。是的,第二张图片是自愿的,用来测试最坏的情况。但最终,用户将收到一张纸作为背景和说明,所以这可能不会像这样糟糕。我只是想要一个系统,将尽可能坚实,因为用户将采取这些图片在家里等,那里的光线条件