如何检测带有背景网格的黑白图像中的曲线?

How to detect a curve in a B&W image with a background grid?

我正在努力从这张图片中提取曲线:

它代表我不想触及的科学数据,以避免引入错误,所以我不能只是在绘图数字化仪中手动重画线:我想自动提取曲线,然后我将其输入绘图数字化仪。

我尝试以编程方式在图像上绘制白色网格,尝试与网格完全重叠并将其删除;但不幸的是,这是对纸张的扫描sheet,因此网格并不完美,因此行间距并不总是相同的。

用于网格的代码:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
  <meta name="generator" content="PSPad editor, www.pspad.com">
  <title></title>
  <script>
        sourcename = "converted";
        originalHeight = 0;
        originalWidth = 0;


function renderImage()
{
    var canvas = document.getElementById("grid");
    var context = canvas.getContext("2d");
    var image = new Image();
    image.onload = function() {
        selectedimage = image;
        originalHeight = image.height;
        originalWidth = image.width;
        canvas.height = image.height;
        canvas.width = image.width;
        context.drawImage(image,  0, 0, canvas.width, canvas.height);
        xstep = document.getElementById("rngXstep").value*1;
        ystep = document.getElementById("rngYstep").value*1;
        xoffset = document.getElementById("rngxoffset").value*1;
        yoffset = document.getElementById("rngyoffset").value*1;
        strokewidth = document.getElementById("rngstrokewidth").value*1;
        color = document.getElementById("color").value;
        document.getElementById("xstep").value = document.getElementById("rngXstep").value*1
        document.getElementById("ystep").value = document.getElementById("rngYstep").value*1
        document.getElementById("xoffset").value = document.getElementById("rngxoffset").value*1
        document.getElementById("yoffset").value = document.getElementById("rngyoffset").value*1
        document.getElementById("strokewidth").value = document.getElementById("rngstrokewidth").value*1
        drawGrid(context,0,0,0,xoffset,yoffset,xstep,ystep,0,0,color,strokewidth);
    };
    image.src = "chart-test-2.png";
}

var drawGrid = function(context, w, h, id, xoff, yoff, xstep, ystep, xmax, ymax, color,width) {
            for (var x = 0; x <= originalWidth; x += xstep) {
                context.moveTo(1 + x + xoff, 0 + yoff);
                context.lineTo(1 + x + xoff, originalHeight + yoff);
            }


            for (var x = 0; x <= originalHeight; x += ystep) {
                context.moveTo(0, 1 + x + yoff);
                context.lineTo(originalWidth, 1 + x + yoff);
            }

            context.strokeStyle = color;
            context.lineWidth = width;
            context.stroke();
}


</script>
  </head>
  <body>
x step: <input type="text" id="xstep" name="xstep" value=4.1>
<input type="range" id="rngXstep" name = "rngXstep" value="4.1" onchange="renderImage()" step=.1><br>

y step:<input type="text" id="ystep" name="ystep" value=4.1>
<input type="range" id="rngYstep" name = "rngYstep" value="4.1" onchange="renderImage()" step=.1><br>

x offset: <input type="text" id="xoffset" name="xoffset" value=0>
<input type="range" id="rngxoffset" name = "rngxoffset" value="0" onchange="renderImage()" step=.1><br>

y offset:<input type="text" id="yoffset" name="yoffset" value=0>
<input type="range" id="rngyoffset" name = "rngyoffset" value="0" onchange="renderImage()" step=.1><br>

width: <input type="text" id="strokewidth" name="strokewidth" value=2>
<input type="range" id="rngstrokewidth" name = "rngstrokewidth" value="2" onchange="renderImage()" step=.1><br>

color: <input type="text" id="color" name="color" value="white"> (red, white, blue,...)<br>

<canvas id="grid"></canvas><br>
    <img id="chart" name="chart" src="chart-test-2.png"  ><br>
  </body>
</html>

直接将图像放入绘图数字化仪是行不通的,因为曲线具有与网格相同的颜色,而绘图数字化仪使用颜色自动检测曲线。

然后我决定尝试一种不同的方法:寻找图像中最粗的线;我可以尝试编写自己的算法,扫描每个像素并确定哪个像素有更多的黑色邻居……但我可能会重新发明轮子;我问 ImageMagick 作者他的程序是否能够做这样的事情,但他说不能。

然后我发现OpenCV实现了一些算法,比如Hough Transform,Contour detector,可能还有很多其他的;但我是 OpenCV 的新手,所以我需要一些提示,了解哪些函数最适合我的需要。

可以Hough transform detect also curved lines, or only segments? Can contour detector also detect open curves or just closed lines? Or should I use canny edge detection吗?

但另一个问题是我需要 javascript 个示例,而不是 C++ 或 Python。

但我对任何 javascript 解决方案持开放态度,OpenCV 不是唯一的选择。

经过多次实验(基于these examples)和测试,我最终得到了这个代码:

let src = cv.imread('canvasInput');
let dst = new cv.Mat();
let M = cv.Mat.ones(3, 3, cv.CV_8U);
let anchor = new cv.Point(-1, -1);

cv.dilate(src, dst, M, anchor, 1, cv.BORDER_CONSTANT, cv.morphologyDefaultBorderValue());
cv.imshow('canvasOutput', dst);
src.delete(); dst.delete(); M.delete();

可能通过连接多个进一步的过滤器可以获得更好的结果,无论如何我已经通过这种方式获得了可接受的结果。

完整源图片:

已编辑,但未修改数据:

由上面的代码处理(“扩张”):

提交给webplotdigitizer(看右边的设置,黄色区域是webplotdigitizer唯一处理过的):

webplotdigitizer 的原始处理;出现了一些杂散点,但可以很容易地手动删除它们:

已清理:

重新绘制:

注意:原图中水平和垂直比例不同:水平一个是4x w.r.t垂直一个;垂直调整大小 4 倍我得到:

将最终图像叠加在源图像上,我们可以看到它完美匹配:

当然,在同一个源代码中进行数字化会更好,但这是另一回事了...