OpenCV java как разделить слитные контуры

110
26 апреля 2021, 01:20

У меня есть проект по распознаванию чисел.

Я хочу выделить каждую цифру, но есть близко находящиеся числа, которые я хочу разделить. Как можно разделить такие числа?

Answer 1

В данном случае должна помочь морфологическая операция opening - комбинация эрозии и дилатации. Первый этап удалит отдельные точки и тонкие мостики, второй восстановит общие очертания в несколько сглаженном виде без этих деталей.

Конечно, при этом какие-то фигуры могут рассыпаться на части (например, из за дефектов в правой пятёрке). Нужно смотреть, поможет ли предварительный closing для уничтожения дефектов, или приведёт к неубиваемым мостикам-спайкам.

Вообще для таких изображений анализируют объекты и строят решётку - цифры же определённого размера и положение их не случайно, в таком случае разделение производится по границам ячеек/ограничивающих прямоугольников.

Answer 2

Я не знаю как называется этот способ, он основан на построении гистограммы изображения, и поиске локальных минимумов, но сначала нужно найти и залить все замкнутые области.

let img = new Image(); 
img.crossOrigin = 'anonymous'; 
img.src = 'https://i.imgur.com/EqAIRNx.png'; 
 
let srcCtx = src.getContext('2d'), 
    gistCtx = gist.getContext('2d'); 
 
img.onload = function() { 
  src.width = gist.width = img.width; 
  src.height = gist.height = img.height; 
  srcCtx.drawImage(img, 0, 0); 
  let imgData = srcCtx.getImageData(0, 0, img.width, img.height) 
  let gistData = Array(img.width).fill(0); 
  for(var x = 0; x<img.width; x++)  
    for(var y = 0; y<img.height; y++)  
      gistData[x] += imgData.data[(y*img.width + x)*4]>10 ? 1 : 0; 
  gistData.forEach((e,i) => line(gistCtx, i, e)) 
  gistCtx.strokeStyle = srcCtx.strokeStyle = 'red'; 
  extrem(gistData, 12).min 
    .map(e => Math.floor(e[0]/2 + e[1]/2)) 
    .forEach((e, i) => { 
      line(gistCtx, e, img.height) 
      line(srcCtx, e, img.height) 
    }) 
} 
 
function line(ctx, x, h) { 
    ctx.beginPath();  
    ctx.moveTo(x, img.height); 
    ctx.lineTo(x, img.height - h); 
    ctx.stroke(); 
} 
 
function extrem(y, eps) { 
    let s,M,m,j, i=0, min=[], max=[], 
        greater = a => a >= M - eps, 
        lesser = a => a <= m + eps; 
    for (; i < y.length; i++) { 
        if (s && M - eps <= y[i])  
          M = Math.max(M, y[i]) 
        else if (!s && m + eps >= y[i])  
          m = Math.min(m, y[i])  
        else if (s)  
          m = iter(max, greater)      
        else  
          M = iter(min, lesser)    
    } 
    return {min, max}; 
     
    function iter(arr, cond) { 
      j = i - 1; 
      while (cond(y[j])) j--; 
      arr.push([j, i]); 
      s = !s; 
      return y[i]; 
    } 
}
<img src="https://i.imgur.com/EqAIRNx.png" style="margin-bottom:40px"> 
<div style="display:inline-block"> 
<canvas id="src"></canvas><br> 
<canvas id="gist"></canvas> 
</div>

PS: похоже что при помощи нахождения минимумов построчно и вращении исходного изображения можно еще найти на сколько нужно повернуть картинку, чтобы текст встал четко по горизонтали.

READ ALSO
Числительные строкой в Android

Числительные строкой в Android

Мне нужно вывести числительное в виде строки в android (первый, второй, третий, четвертый и тд), а обьектов может быть безграничное количество...

71
Начало работы с MQ java

Начало работы с MQ java

Есть сервер, который реализует в себе MQ Пытаюсь подключиться к нему, используя jms, но видимо что-то в настройке упустилВыдает ошибку:

90