Algorytm wykrywania narożników arkusza papieru na zdjęciu
Jaki jest najlepszy sposób na wykrycie narożników faktury / paragonu/kartki papieru na zdjęciu? Ma to być wykorzystane do późniejszej korekcji perspektywy, przed OCR.
Moje obecne podejście było:
RGB > Szary > wykrywanie krawędzi z progami > Rozszerzanie (1) > usuwanie małych obiektów(6) > Usuwanie obiektów granicznych > wybieranie dużych blogów na podstawie obszaru wypukłego. > [wykrywanie narożników - nie zaimplementowane]
Nie mogę się powstrzymać, ale myślę, że musi być mocniejszy "inteligentne" / statystyczne podejście do obsługi tego typu segmentacji. Nie mam zbyt wielu przykładów treningowych, ale prawdopodobnie mógłbym zebrać razem 100 zdjęć.
Szerszy kontekst:
Używam Matlaba do prototypowania i planuję zaimplementować system w OpenCV i TESSERECT-OCR. Jest to pierwszy z wielu problemów przetwarzania obrazu, które muszę rozwiązać dla tej konkretnej aplikacji. Szukam więc własnego rozwiązania i ponownego zapoznania się z przetwarzaniem obrazu algorytmy.
Oto przykładowe zdjęcie, które chciałbym, aby algorytm obsłużył: jeśli chcesz podjąć wyzwanie, duże obrazy są na http://madteckhead.com/tmp
Przypadek 1 http://madteckhead.com/tmp/IMG_0773_sml.jpg przypadek 2 http://madteckhead.com/tmp/IMG_0774_sml.jpg przypadek 3 http://madteckhead.com/tmp/IMG_0775_sml.jpg przypadek 4 http://madteckhead.com/tmp/IMG_0776_sml.jpg
W najlepszym przypadku to daje:
Case 1-canny http://madteckhead.com/tmp/IMG_0773_canny.jpg case 1-post canny http://madteckhead.com/tmp/IMG_0773_postcanny.jpg case 1-największy blog http://madteckhead.com/tmp/IMG_0773_blob.jpg
Jednak łatwo zawodzi w innych przypadkach:
Case 2-canny http://madteckhead.com/tmp/IMG_0774_canny.jpg case 2-post canny http://madteckhead.com/tmp/IMG_0774_postcanny.jpg case 2-największy blog http://madteckhead.com/tmp/IMG_0774_blob.jpg
Z góry dziękuję za wszystkie świetne pomysły! Kocham tak!
EDIT: Hough Transform Progress
P: jaki algorytm mógłby gromadzić linie hougha, aby znaleźć narożniki? Za radą odpowiedzi udało mi się użyć transformacji Hougha, wybrać linie i je filtrować. Moje obecne podejście jest raczej prymitywne. Założyłem, że faktura będzie zawsze mniejsza niż 15deg z wyrównaniem do obrazu. Kończę z rozsądnym wyniki dla wierszy, jeśli tak jest (patrz poniżej). Ale nie jestem całkowicie pewien odpowiedniego algorytmu do klastra linii (lub głosowania) ekstrapolacji dla narożników. Linie Hougha nie są ciągłe. A w hałaśliwych obrazach mogą występować równoległe linie, więc wymagana jest pewna forma lub odległość od metryk pochodzenia linii. Jakieś pomysły?
Przypadek 1 http://madteckhead.com/tmp/IMG_0773_hough.jpg przypadek 2 http://madteckhead.com/tmp/IMG_0774_hough.jpg przypadek 3 http://madteckhead.com/tmp/IMG_0775_hough.jpg przypadek 4 http://madteckhead.com/tmp/IMG_0776_hough.jpg
8 answers
Jestem przyjacielem Martina, który pracował nad tym wcześniej w tym roku. To był mój pierwszy projekt kodowania, i trochę zakończył się w pośpiechu, więc kod potrzebuje trochę errr...dekodowanie... Dam kilka wskazówek z tego, co już widziałem, a potem uporządkuję mój kod w dniu wolnym jutro.
Pierwsza wskazówka, OpenCV
i python
są niesamowite, przenieś się do nich jak najszybciej. : D
Zamiast usuwać małe przedmioty i szum, obniż ograniczniki canny, aby akceptował więcej krawędzi i następnie Znajdź największy zamknięty kontur (w OpenCV użyj {[2] } z prostymi parametrami, chyba użyłem CV_RETR_LIST
). może nadal walczyć, gdy jest na białym kartce papieru, ale zdecydowanie zapewnia najlepsze wyniki.
Dla transformaty Houghline2()
spróbuj użyć CV_HOUGH_STANDARD
W przeciwieństwie do CV_HOUGH_PROBABILISTIC
, da ona Rho i theta wartości, definiując linię we współrzędnych biegunowych, a następnie możesz grupować linie w pewnej tolerancji do nich.
Moje ugrupowanie działało jako spójrz w górę tabeli, dla każdej linii wyprowadzonej z transformacji hougha dałaby parę rho i theta. Jeśli wartości te mieściły się w granicach, powiedzmy 5% pary wartości w tabeli, zostały one odrzucone, jeśli znajdowały się poza tym 5%, Dodano nowy wpis do tabeli.
Można wtedy znacznie łatwiej wykonać analizę równoległych linii lub odległości między liniami.
Mam nadzieję, że to pomoże.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-27 17:35:54
Grupa studentów na mojej uczelni zademonstrowała niedawno aplikację na iPhone ' a (i aplikację OpenCV w Pythonie), którą napisali, aby dokładnie to zrobić. Z tego co pamietam to kroki byly cos takiego:
- Środkowy filtr, aby całkowicie usunąć tekst na papierze(był to odręczny tekst na białym papierze z dość dobrym oświetleniem i może nie działać z drukowanym tekstem, działał bardzo dobrze). Powodem było to, że znacznie ułatwia wykrywanie narożników.
- transformata Hougha dla linie
- Znajdź wierzchołki w przestrzeni Hough Transform i narysuj każdą linię na całym obrazie.
- przeanalizuj linie i usuń wszystkie, które są bardzo blisko siebie i są pod podobnym kątem(połącz linie w jedną). Jest to konieczne, ponieważ transformata Hougha nie jest idealna, ponieważ działa w dyskretnej przestrzeni próbek.
- Znajdź pary linii, które są mniej więcej równoległe i przecinają inne pary, aby zobaczyć, które linie tworzą quady.
To wydawało się, że działają dość dobrze i byli w stanie zrobić zdjęcie kawałka papieru lub książki, wykonać detekcję narożników, a następnie zmapować dokument na obrazie na płaską płaszczyznę w prawie czasie rzeczywistym (do mapowania była pojedyncza funkcja OpenCV). Nie było OCR, kiedy zobaczyłem, że działa.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-02 08:03:24
Oto co wymyśliłem po kilku eksperymentach:
import cv, cv2, numpy as np
import sys
def get_new(old):
new = np.ones(old.shape, np.uint8)
cv2.bitwise_not(new,new)
return new
if __name__ == '__main__':
orig = cv2.imread(sys.argv[1])
# these constants are carefully picked
MORPH = 9
CANNY = 84
HOUGH = 25
img = cv2.cvtColor(orig, cv2.COLOR_BGR2GRAY)
cv2.GaussianBlur(img, (3,3), 0, img)
# this is to recognize white on white
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(MORPH,MORPH))
dilated = cv2.dilate(img, kernel)
edges = cv2.Canny(dilated, 0, CANNY, apertureSize=3)
lines = cv2.HoughLinesP(edges, 1, 3.14/180, HOUGH)
for line in lines[0]:
cv2.line(edges, (line[0], line[1]), (line[2], line[3]),
(255,0,0), 2, 8)
# finding contours
contours, _ = cv2.findContours(edges.copy(), cv.CV_RETR_EXTERNAL,
cv.CV_CHAIN_APPROX_TC89_KCOS)
contours = filter(lambda cont: cv2.arcLength(cont, False) > 100, contours)
contours = filter(lambda cont: cv2.contourArea(cont) > 10000, contours)
# simplify contours down to polygons
rects = []
for cont in contours:
rect = cv2.approxPolyDP(cont, 40, True).copy().reshape(-1, 2)
rects.append(rect)
# that's basically it
cv2.drawContours(orig, rects,-1,(0,255,0),1)
# show only contours
new = get_new(img)
cv2.drawContours(new, rects,-1,(0,255,0),1)
cv2.GaussianBlur(new, (9,9), 0, new)
new = cv2.Canny(new, 0, CANNY, apertureSize=3)
cv2.namedWindow('result', cv2.WINDOW_NORMAL)
cv2.imshow('result', orig)
cv2.waitKey(0)
cv2.imshow('result', dilated)
cv2.waitKey(0)
cv2.imshow('result', edges)
cv2.waitKey(0)
cv2.imshow('result', new)
cv2.waitKey(0)
cv2.destroyAllWindows()
Nie idealne, ale przynajmniej działa dla wszystkich próbek:
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-20 02:42:09
Zamiast rozpoczynać od detekcji krawędzi można użyć detekcji narożników.
Marvin Framework dostarcza do tego celu implementację algorytmu Moravec. Jako punkt wyjścia można było znaleźć narożniki gazet. Poniżej wyjście algorytmu Moravec ' a:
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-27 19:16:58
Możesz również użyć MSER (maksymalnie stabilne ekstremalne regiony) nad operatorem Sobel result, aby znaleźć stabilne regiony obrazu. Dla każdego obszaru zwracanego przez MSER można zastosować wypukły kadłub i przybliżenie poly, aby otrzymać takie oto:
Ale ten rodzaj detekcji jest przydatny do wykrywania NA ŻYWO więcej niż jeden obraz, który nie zawsze zwraca najlepszy wynik.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-17 10:36:57
Po wykryciu krawędzi użyj transformacji Hougha. Następnie umieść te punkty w SVM (supporting vector machine) z ich etykietami, jeśli przykłady mają gładkie linie na nich, SVM nie będzie miał żadnych trudności z podziałem niezbędnych części przykładu i innych części. Moja rada na SVM, umieścić parametr jak łączność i długość. Oznacza to, że jeśli punkty są połączone i długie, prawdopodobnie będą linią odbioru. Następnie możesz wyeliminować wszystkie pozostałe punkty.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-02 22:17:31
Tutaj masz kod @ Vanuan używając C++:
cv::cvtColor(mat, mat, CV_BGR2GRAY);
cv::GaussianBlur(mat, mat, cv::Size(3,3), 0);
cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Point(9,9));
cv::Mat dilated;
cv::dilate(mat, dilated, kernel);
cv::Mat edges;
cv::Canny(dilated, edges, 84, 3);
std::vector<cv::Vec4i> lines;
lines.clear();
cv::HoughLinesP(edges, lines, 1, CV_PI/180, 25);
std::vector<cv::Vec4i>::iterator it = lines.begin();
for(; it!=lines.end(); ++it) {
cv::Vec4i l = *it;
cv::line(edges, cv::Point(l[0], l[1]), cv::Point(l[2], l[3]), cv::Scalar(255,0,0), 2, 8);
}
std::vector< std::vector<cv::Point> > contours;
cv::findContours(edges, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_TC89_KCOS);
std::vector< std::vector<cv::Point> > contoursCleaned;
for (int i=0; i < contours.size(); i++) {
if (cv::arcLength(contours[i], false) > 100)
contoursCleaned.push_back(contours[i]);
}
std::vector<std::vector<cv::Point> > contoursArea;
for (int i=0; i < contoursCleaned.size(); i++) {
if (cv::contourArea(contoursCleaned[i]) > 10000){
contoursArea.push_back(contoursCleaned[i]);
}
}
std::vector<std::vector<cv::Point> > contoursDraw (contoursCleaned.size());
for (int i=0; i < contoursArea.size(); i++){
cv::approxPolyDP(Mat(contoursArea[i]), contoursDraw[i], 40, true);
}
Mat drawing = Mat::zeros( mat.size(), CV_8UC3 );
cv::drawContours(drawing, contoursDraw, -1, cv::Scalar(0,255,0),1);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-09 21:09:42
-
Convert to lab space
-
Use kmeans segment 2 cluster
- następnie użyj konturów lub hough na jednym z klastrów (intenral)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-29 07:24:19