Chciałbym zrobić zdjęcia etykiet na słoiku z jedzeniem i móc je przekształcić, tak aby etykieta była płaska, a prawa i lewa strona została przeskalowana tak, aby była równa ze środkiem obrazu.
Idealnie chciałbym użyć kontrastu między etykietą a tłem, aby znaleźć krawędzie i zastosować poprawkę. W przeciwnym razie mogę poprosić użytkownika o identyfikację narożników i boków obrazu.
Szukam ogólnych technik i algorytmów, aby zrobić zdjęcie, które jest przekrzywione sferycznie (w moim przypadku cylindrycznie) i które może spłaszczyć obraz. Obecnie obraz etykiety owiniętej wokół słoika lub butelki będzie zawierał funkcje i tekst, które zmniejszają się w miarę cofania w prawo lub w lewo od obrazu. Również linie, które oznaczają krawędź etykiety, będą równoległe tylko na środku obrazu i będą przechylać się względem siebie po prawej i lewej stronie etykiety.
Po zmanipulowaniu obrazu chciałbym pozostać z niemal idealnym prostokątem, w którym tekst i cechy są jednakowo duże, tak jakbym zrobił zdjęcie etykiety, gdy nie było jej na słoiku lub butelce.
Chciałbym również, aby technika mogła automatycznie wykryć krawędzie etykiety, aby zastosować odpowiednią korekcję. W przeciwnym razie musiałbym poprosić użytkownika o wskazanie granic etykiety.
Już googlowałem i znalazłem artykuły takie jak ten: spłaszczanie zakrzywionych dokumentów , ale szukam czegoś nieco prostszego, ponieważ moje potrzeby dotyczą etykiet z prostą krzywą.
źródło
Odpowiedzi:
Podobne pytanie został poproszony o Mathematica.Stackexchange . Moja odpowiedź tam ewoluowała i ostatecznie wydłużyła się, więc podsumuję algorytm tutaj.
Abstrakcyjny
Podstawową ideą jest:
Algorytm działa tylko w przypadku obrazów, w których:
Algorytm jest jednak modułowy. Przynajmniej w zasadzie możesz napisać własne wykrywanie etykiet, które nie wymaga ciemnego tła, lub możesz napisać własną funkcję pomiaru jakości, która poradzi sobie z etykietami eliptycznymi lub ośmiokątnymi.
Wyniki
Te obrazy zostały przetworzone w pełni automatycznie, tj. Algorytm pobiera obraz źródłowy, działa przez kilka sekund, a następnie pokazuje mapowanie (po lewej) i niezniekształcony obraz (po prawej):
Kolejne obrazy zostały przetworzone przy użyciu zmodyfikowanej wersji algorytmu, w przypadku gdy użytkownik wybierze lewą i prawą ramkę słoika (nie etykietę), ponieważ krzywizny etykiety nie można oszacować na podstawie obrazu na zdjęciu przednim (tj. w pełni automatyczny algorytm zwraca obrazy, które są nieco zniekształcone):
Realizacja:
1. Znajdź etykietę
Etykieta jest jasna na ciemnym tle, więc mogę ją łatwo znaleźć za pomocą binaryzacji:
Po prostu wybieram największy podłączony komponent i zakładam, że to etykieta:
2. Znajdź granice etykiety
Następny krok: znajdź górną / dolną / lewą / prawą ramkę za pomocą prostych pochodnych masek splotu:
Jest to mała funkcja pomocnicza, która znajduje wszystkie białe piksele na jednym z tych czterech obrazów i konwertuje wskaźniki na współrzędne (
Position
zwraca indeksy, a indeksy są oparte na 1-rzędach {y, x}, gdzie y = 1 znajduje się na górze obraz. Ale wszystkie funkcje przetwarzania obrazu oczekują współrzędnych, które są oparciami 0 x {y, y}, gdzie y = 0 jest dolną częścią obrazu:3. Znajdź odwzorowanie z obrazka na współrzędne walca
Teraz mam cztery osobne listy współrzędnych górnej, dolnej, lewej i prawej krawędzi etykiety. Definiuję odwzorowanie od współrzędnych obrazu na współrzędne walca:
Jest to odwzorowanie cylindryczne, które odwzorowuje współrzędne X / Y na obrazie źródłowym na współrzędne cylindryczne. Mapowanie ma 10 stopni swobody dla wysokości / promienia / środka / perspektywy / pochylenia. Użyłem serii Taylora do przybliżenia sinusoidy łuku, ponieważ nie mogłem uzyskać optymalizacji działającej bezpośrednio z ArcSin. The
Clip
połączenia to moja doraźna próba zapobiegania liczbom złożonym podczas optymalizacji. Jest tu kompromis: z jednej strony funkcja powinna być jak najbardziej zbliżona do dokładnego odwzorowania cylindrycznego, aby zapewnić możliwie najniższe zniekształcenie. Z drugiej strony, jeśli jest to skomplikowane, znacznie trudniej jest automatycznie znaleźć optymalne wartości stopni swobody. (Zaletą robienia przetwarzania obrazu za pomocą Mathematiki jest to, że możesz bardzo łatwo bawić się takimi modelami matematycznymi, wprowadzać dodatkowe warunki dla różnych zniekształceń i używać tych samych funkcji optymalizacyjnych, aby uzyskać ostateczne wyniki. Nigdy nie byłem w stanie nic zrobić podobnie jak przy użyciu OpenCV lub Matlab. Ale nigdy nie próbowałem symbolicznego zestawu narzędzi dla Matlaba, może to czyni go bardziej użytecznym.)Następnie definiuję „funkcję błędu”, która mierzy jakość obrazu -> mapowanie współrzędnych walca. To tylko suma błędów kwadratu dla pikseli granicy:
Ta funkcja błędu mierzy „jakość” odwzorowania: najniższa, jeśli punkty na lewej ramce są odwzorowane na (0 / [cokolwiek]), piksele na górnej granicy są zmapowane na ([cokolwiek] / 0) i tak dalej .
Teraz mogę powiedzieć Mathematica, aby znalazł współczynniki, które minimalizują tę funkcję błędu. Potrafię zgadywać na temat niektórych współczynników (np. Promień i środek słoika na obrazie). Używam ich jako punktów początkowych optymalizacji:
FindMinimum
znajduje wartości 10 stopni swobody mojej funkcji mapowania, które minimalizują funkcję błędu. Połącz ogólne mapowanie z tym rozwiązaniem, a otrzymam mapowanie ze współrzędnych obrazu X / Y, które pasuje do obszaru etykiety. Mogę wizualizować to mapowanie za pomocąContourPlot
funkcji Mathematica :4. Przekształć obraz
Na koniec używam
ImageForwardTransform
funkcji Mathematiki do zniekształcania obrazu zgodnie z tym odwzorowaniem:To daje wyniki, jak pokazano powyżej.
Wersja wspomagana ręcznie
Powyższy algorytm jest w pełni automatyczny. Nie są wymagane żadne korekty. Działa dość dobrze, o ile zdjęcie jest robione z góry lub z dołu. Ale jeśli jest to strzał z przodu, promienia słoika nie można oszacować na podstawie kształtu etykiety. W takich przypadkach uzyskuję znacznie lepsze wyniki, jeśli pozwolę użytkownikowi ręcznie wprowadzić lewą / prawą granicę słoika i wyraźnie ustawić odpowiednie stopnie swobody w odwzorowaniu.
Ten kod pozwala użytkownikowi wybrać lewą / prawą ramkę:
Jest to alternatywny kod optymalizacji, w którym środek i promień są podane jawnie.
źródło