Questo è il mio primo programma openCV, quindi sii perdonato se sembro ignorante di alcuni concetti di base della visione artificiale.Estrazione di colonne giornaliere semirigide
UPDATE: Vedere nuovo codice/nuovo problema, in fondo, grazie alla risposta da sturkmen
Sto lavorando su "digitalizzazione" un grande insieme di immagini, come quelle attaccate, come un progetto. Tutte le immagini provengono dalla stessa fonte. L'obiettivo finale è quello di passare pezzi di testo estratti a tesseract, la libreria OCR.
(codice sorgente in basso) ho intenzione di spiegare il mio approccio attuale, e quindi dichiarare le mie domande.
Il mio approccio attuale è la seguente:
immagine Dilate
Applicare inversa soglia binario e trovare contorni
Creare un
boundingRect
da ciascun contorno, poi filtrare per minimo e dimensioni massime
questo ha funzionato ok
mio risultato finale desiderato è quello di avere uno boundingRect
intorno ogni colonna. Quindi per le foto fornite che sarebbero sette di loro.
Quindi, il problema è che le "mini sezioni" tabulate nell'immagine non vengono rilevate in modo affidabile (l'esempio migliore sarebbe quello nella colonna all'estrema destra che non ha uno boundingRect
attorno).
Posso pensare a due possibili soluzioni (in modo da non essere una domanda di tipo a risposta aperta) ma se si conosce una soluzione migliore condividerla!
1) combinare boundingRect
s che sono vicini verticali per acquisire le colonne. Contiene possibili errori del caso limite.
2) Trovare un modo diverso di manipolare l'immagine prima di trovare i contorni. Dalla mia ricerca, l'algoritmo di livellamento della lunghezza della corsa sembra promettente?
Quindi la mia domanda è: quale approccio è il migliore? Ho trascurato una soluzione migliore? Sono inesperto in questo reparto, quindi nessun suggerimento è troppo piccolo.
Grazie per la lettura!
#include "opencv2/core.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
using namespace cv;
using namespace std;
int main(int argc, char* argv[])
{
Mat image = imread(path_to_file);
Mat gray;
cvtColor(image, gray, COLOR_BGR2GRAY);
Mat fin;
double thresh = threshold(gray, fin, 160, 255, THRESH_BINARY_INV);
//size impacts dilation
Mat kernel = getStructuringElement(MORPH_CROSS, Size(2, 4));
Mat dilated;
dilate(fin, dilated, kernel, Point(-1,-1), 6);
imwrite("testbw.png",dilated);
Mat hierarchy;
vector<vector<Point> >contours;
findContours(dilated, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);
//potentially sort by x
for (const auto& c : contours)
{
// x y
//columns 850 x 5400
Rect r = boundingRect(c);
if (r.height > 3000 || r.width > 875)
continue;
if (r.height < 100 || r.width < 500)
continue;
rectangle(image, r, Scalar(255, 0, 255), 2); //made thicker
}
imwrite("test.png", image);
waitKey(0);
return 0;
}
Immagine originale:
codice aggiornato
int main(int argc, char* argv[])
{
Mat image = imread(path_to_file);
Mat gray;
cvtColor(image, gray, COLOR_BGR2GRAY);
Mat fin;
double thresh = threshold(gray, fin, 160, 255, THRESH_BINARY_INV);
Mat kernel = getStructuringElement(MORPH_CROSS, Size(2, 4));
Mat dilated;
dilate(fin, dilated, kernel, Point(-1,-1), 6);
vector<Vec4i> hierarchy;
vector<vector<Point> >contours;
findContours(dilated, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);
vector<Rect> rects;
Rect big_rect = Rect(image.cols/2,image.rows/2,1,1);
for (const auto& c : contours)
{
// x y
//columns 850 x 5400
Rect r = boundingRect(c);
if (r.height > 5500 || r.width > 875)
continue;
if (r.height < 300 || r.width < 500)
continue;
big_rect = big_rect | r; // here we will find bounding box of all Rects
rects.push_back(r); // stores rects
}
for (size_t i = 0; i < rects.size(); i++)
{
// sets y and height of all rects
//cout << rects[i].x << endl;
rects[i].y = big_rect.y;
rects[i].height = big_rect.height;
}
//groupRectangles(rects, 1); DIDN'T WORK
for (size_t i = 0; i < rects.size(); i++)
{
rectangle(image, rects[i], Scalar(255, 0, 255), 2);
}
imshow("test", image);
nuovo risultato:
nuovo problema: Ci sono molti boundingRect
s attorno a ogni colonna (probabilmente non si può dire guardando l'immagine). Questo è un problema, perché voglio fare una sotto-immagine di ogni colonna, ad es. Mat ROI = image(rects[i])
che renderebbe molto più delle 7 immagini desiderate.
Nuova domanda: Come posso combinare la moltitudine di rettangoli per colonna in uno? Ho visto OpenCV groupRectangles
, ma non funzionava.
Quello che voglio è una 'boundingRect' per colonna. Funzionerebbe anche una soluzione che catturasse in modo affidabile i quadrati tabulati. Inizialmente pensavo che sarebbe stato più semplice avere un 'boundingRect' per colonna, che avrebbe contenuto solo quella colonna. Perché da lì creerò (in questo caso 7) sotto-immagini (una per colonna) e poi le passerò a tesseract per OCR. Lavorerò al caricamento dell'immagine originale ora –
Hai bisogno di un metodo che raggruppa i rettangoli che hai adesso in 7 colonne? O qualcosa che rileva direttamente le colonne complete? – Miki
Ecco dove sono aperto ai suggerimenti, scusa se ciò non è molto utile. Quale sceglieresti? Finché riesco a catturare in modo affidabile quasi ogni parola nell'immagine, il mio obiettivo è raggiunto. Penso che se i rettangoli fossero raggruppati verticalmente (in modo da separare le colonne), allora ci sarebbero casi limite in cui fallirebbe, che menziono nella domanda. –