For starters, we're thinking a little. I'm getting a piece of paper and a pen. Drawing different arcs, it can be observed that partially overlapping arcs can create difficulties. For example, two arcs of the same colour and a radius could form a circumference, and then it would be impossible to find their ends. If the task does not require an exact result and is an application (i.e. Enough. The exact result will also be useful, and focus on simple cases.Let's try to solve the challenge for one oak. What does the end look like we're looking for? What makes it different from the other parts of the arc? He has a background on three sides. To see these sides, a part of the image around the arc point needs to be considered. If all arcs are painted by lines of one thickness, it seems reasonable to reduce the image to such a size that its thickness is equal to one picel. My arc is painted by a line of thickness in one picsel, so the related sides are neighbouring pickles.What happens is:We're gonna use all the images looking for arc points.For each point of the arc, there's a neighbor's pickles. If the neighbor's pickles share the background in two areas, it's not the end of the oath, or we found what we were looking for.With a few arcs, the task is complicated: the points found must be combined into vapour. In your case, the fact that the arc has a limited length and is seminal can help. And I'll make it easier to paint a pair of flowers.var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = 'rgb(0, 0, 255)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.arc(60, 70, 60, -0.2 * Math.PI, 0.8 * Math.PI);
ctx.strokeStyle = '#f00';
ctx.stroke();
ctx.beginPath();
ctx.arc(100, 110, 70, -0.8 * Math.PI, -0.3 * Math.PI);
ctx.strokeStyle = '#0f0';
ctx.stroke();
ctx.beginPath();
ctx.moveTo(50, 30);
ctx.lineTo(120, 100);
ctx.strokeStyle = '#fff';
ctx.stroke();
var ArcsFinder = function() {
this.find = function(imageData, bgRgb) {
var around = [
[-1, -1],
[0, -1],
[1, -1],
[1, 0],
[1, 1],
[0, 1],
[-1, 1],
[-1, 0]
];
var endings = [];
var dots = _getDots(imageData.data, bgRgb);
for (var i = 0; i < dots.length; ++i) {
var x = dots[i] % imageData.width;
var y = Math.trunc(dots[i] / imageData.height);
var nBg =[];
for (var j = 0; j < around.length; ++j) {
var nx = x + around[j][0];
var ny = y + around[j][1];
if (
nx >= 0
&& nx < imageData.width
&& ny >= 0
&& ny < imageData.height
) {
var nd = (
dots[i]
+ (
(around[j][1] * imageData.width)
+ around[j][0]
)
) * 4;
nBg.push(_isBg(
[
imageData.data[nd],
imageData.data[nd + 1],
imageData.data[nd + 2]
],
bgRgb
));
} else {
nBg.push(true);
}
}
if (_countIntervals(nBg) === 1) {
endings.push([x, y]);
}
}
return endings;
};
function _getDots(data, bgRgb) {
var dots = [];
for (var i = 0; i < data.length - 1; i += 4) {
if ( ! _isBg([data[i], data[i + 1], data[i + 2]], bgRgb)) {
dots.push(i / 4);
}
}
return dots;
}
function _isBg(rgb, bgRgb) {
var diff = (
Math.abs(rgb[0] - bgRgb[0])
+ Math.abs(rgb[1] - bgRgb[1])
+ Math.abs(rgb[2] - bgRgb[2])
);
return diff < 255;
}
function _countIntervals(n)
{
var noise = 0;
var c = 0;
var lastN = true;
for (var i = 0; i < n.length; ++i) {
if ( ! n[i]) {
++noise;
}
if (lastN && ! n[i]) {
++c;
}
lastN = n[i];
}
if (noise >= n.length / 2) {
// если точек относящихся к дуге половина или больше,
// то это какая-то каша из дуг
return noise;
}
if ( ! n[0] && n[0] === n[n.length - 1]) {
--c;
}
return c;
}
};
var btnEl = document.getElementById('findBtn');
btnEl.addEventListener('click', function(e) {
e.prevetDefault;
var finder = new ArcsFinder();
var endings = finder.find(
ctx.getImageData(0, 0, canvas.width, canvas.height),
[0, 0, 255]
);
console.log(endings);
for (var i = 0; i < endings.length; ++i) {
var ending = endings[i];
var px = ctx.getImageData(ending[0], ending[1], 1, 1);
var data = px.data;
var rgb = 'rgb(' + data[0] + ', ' + data[1] + ', ' + data[2] + ')';
ctx.beginPath();
ctx.arc(ending[0], ending[1], 3, 0, 2 * Math.PI);
ctx.strokeStyle = rgb;
ctx.stroke();
}
btnEl.remove();
});<canvas id="canvas" width="150" height="150"></canvas>
<button id="findBtn">find endigs</button>It's a very primitive approach, and there's a big slope for optimization. Besides, I may have made mistakes somewhere. But I hope I've given direction to your thought.Mathematics aren't useful yet. But it might be useful in optimizing.