Popularny post Gieneq Napisano Sierpień 19, 2018 Popularny post Udostępnij Napisano Sierpień 19, 2018 (edytowany) Pomyślałem, że skoro i tak powstaje projekt to szkoda by coś o nim nie napisać dla potomnych. Pracuję nad przyrządem, który ma zautomatyzować pewną dziedzinę poligrafii, w której istotne jest policzenia pola powierzchni plamy na kartce. Zadanie banalne ale potrzebny jest sposób na zrobienie tego szybciej i możliwie dokładniej. Potrzebne są też pewne dodatki, chociażby archiwizacja tego co się mierzy i wysyłanie na serwer/zapis na pendriva czy wysłanie mailem. Pierwsze o czym pomyślałem to aplikacja na Androida z OpenCV i ww. bajerami, ale okazało się to trochę nietrafione. Port OpenCV na Androida jest koszmarnie wolny zaś telefon zbyt mało precyzyjny by można było zrobić zdjęcie z dobrym oświetleniem, bez potrzeby kompensacji perspektywy. 😑 Dla tego porzuciłem to co najbardziej oczywiste i wziąłem się za Raspberry Pi. Ostatecznie "aparatura" składa się z: Raspberry Pi 3, kamery PiCamera z obiektywem, wyświetlacza GPIO/TFT, pierścienia LED ze zmatowionymi soczewkami, belki z przyciskami (po co skoro jest wyświetlacz?). Konstrukcja może wygląda niezgrabnie (jest to jedynie prototyp, który może doczeka się nowej odsłony) ale jest funkcjonalny. Zdjęcia robione są zawsze w tej samej pozycji (prostopadle z tą samą odległością od powierzchni i dobrym focusem). Orientacja wyświetlacza pokrywa się z tym co widzi kamera przez co łatwiej nakierować przyrząd. Przy pomocy przycisków wybierane są nastawy chociażby współczynnik gamma, czy rozmycie poprawiające wykrywanie krawędzi. Dla czego używam fizycznych przełączników? Do wyświetlania GUI używam biblioteki PyGame o czym za chwilę. Ma swoje plusy - własny framebuffer dzięki któremu jestem w stanie wyświetlać cokolwiek na ekraniku GPIO. Ale niestety biblioteka nie radzi sobie w obsługą myszy czy dotyku pokazując zawsze 2 skrajne wartości. Skoro mowa o oprogramowaniu. Skorzystałem tu z rewelacyjnego poradnika jak zainstalować OpenCV . Tu polecam zaopatrzyć się w garść cierpliwości i sporo czasu bo kompilacja trochę trwa... Kolejny etap to zorganizowanie biblioteki PyGame i instalacja Samby. Do pisania skryptów użyłem sposobu, który opisywałem niedawno na blogu – VNC do podglądu ekranu i odpalania skryptu, WinSCP + PyCharm do edycji skryptu zaś do pobierania zapisanych obrazów używam serwera plików Samba, gdzie po każdym użyciu pojawia mi się nowy folder z pomiarami na uprzednio zmapowanym dysku sieciowym (zgodnie z zapowiedzią pojawi się w kursie RPi projekty)! Jak wygląda algorytm przetwarzania? Tu przetestowałem różne metody, niektóre naprawdę absurdalne. Jak wiadomo wygrała ta najprostsza... W programie wyróżniam 2 etapy: podgląd i dokładna analiza. Podczas podglądu pobrana klatka nagrania jest przycinana i zmniejszana aby przetwarzanie było szybsze. Dokonywane jest wstępne przetwarzanie: korekcja gamma w celu wyeksponowania delikatnych różnic, rozmycie filtrem medianowym, progowanie (binaryzacja) metodą Otsu (bazującą na rozdzieleniu histogramu), zamknięcie – jedna z operacji morfologicznych, nałożenie na oryginalny obraz i wyświetlenie. Gdy dotknięty zostanie ekran zachowywana jest ostatnia klatka i odpalany jest podobny algorytm tylko w większej rozdzielczości. Wyniki są zapisywane do nowego katalogu o narastającym indeksie zaś na ekranie widocznych jest oryginalny obraz z nałożonym wyznaczonym obszarem i listą z wynikami pomiaru. Na czym polega metoda progowania Otsu? W skrócie bazuje na automatycznym wyliczaniu progu na bazie rozdzielenia histogramu. Zainteresowanych odsyłam do dokumentacji (to nie żart, jest świetnie opisana! 😊 ) Wspomniałem o innych metodach. Jedną z nich był mój faworyt - segmentacja przez rozrost. Niestety pomimo oczywistych zalet (dostosowanie się do różnych poziomów jasności) nie radziła sobie, gdy obraz miał większą ziarnistość. Pomijając, że rekurencyjny charakter sprawiał, że algorytm wykonywał się ponad 30 sekund. 😪 Drugim pomysłem bardzo eksperymentalnym było zastosowanie ukrytych modeli markowa w roli narzędzia, które będzie można dostosować do analizowanego obrazu. Kompletnie pomijając czas wykonania. Algorytm co prawda potrafił się dostosować do stochastycznej charakterystyki obrazu, to jednak nie jest to obszar w którym powinien być używany – świadczy o tym znikoma liczba prac na ten temat. Ostatnia kwestia to jak zamienić liczbę pikseli na mm2? Tu niezbędna jest jakaś wartość referencyjna. W jednym z artykułów autor posłużył się monetą którą kładł obok mierzonych przedmiotów. Ma to jednak swoją wadę! Gdy obiekt znajduje się "daleko" od ogniskowej obiektywu zostaje zniekształcony przez dystorsję układu optycznego, zwłaszcza w szerokokątnym aparatach. W aparaturze za wartość referencyjną przyjmuje znaną średnicę otworu statywu (tak... rury kanalizacyjnej 😎 ). Jest ona znana i stała. Na wstępie algorytmu wyznaczana jest średnica w pikselach przy pomocy metody wykrywania krawędzi Canyego. Znajdowane są 4 ekstrema – 4 różowe punkty na ww. ilustracji i liczona jest średnia z uzyskanych 2 średnic. Jaka jest dokładność? Cóż, nie jest to ukończony projekt dla tego niedługo umieszczę kontynuację, ale puki co dokładność wynosi +- 3%. Edytowano Sierpień 20, 2018 przez Gieneq 4 Cytuj Link do komentarza Share on other sites More sharing options...
Popularny post deshipu Sierpień 19, 2018 Popularny post Udostępnij Sierpień 19, 2018 (edytowany) Bardzo fajnie widzieć coś, co ma zastosowanie praktyczne. Dziwią mnie tylko twoje problemy z PyGame i myszką. Używam tej biblioteki od lat, zarówno na dużych komputerach jak i na raspberry pi i nigdy problemów z myszką nie miałem. Jesteś pewien, że wina leży po stronie biblioteki, a nie sprzętu albo sterowników do niego? Edytowano Sierpień 19, 2018 przez deshipu 2 1 Cytuj Link do komentarza Share on other sites More sharing options...
Gieneq Sierpień 19, 2018 Autor tematu Udostępnij Sierpień 19, 2018 Zainspirowałeś mnie żeby to sprawdzić – faktycznie działa! Problem był w funkcji, która wyłącza wyświetlanie kursora myszy. W VNC wciąż pojawia się mały punkt i zdarzenie dotyku jest dalej obsługiwane ale nie zmienia to faktu że pozycja nie jest aktualizowana. Po zakomentowaniu od razu działa, dzięki 😁 import pygame from pygame.locals import * import time import sys widthTFT = 480 heightTFT = 320 pygame.init() screenSize = [widthTFT, heightTFT] screen = pygame.display.set_mode(screenSize, pygame.FULLSCREEN) # pygame.mouse.set_visible(False) screen.fill([255, 255, 255]) print('width, height ({0}, {1})'.format(widthTFT, heightTFT)) print('press ESC to exit.') while True: for event in pygame.event.get(): if event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: sys.exit() if event.type == pygame.MOUSEBUTTONDOWN: pos = pygame.mouse.get_pos() rel = pygame.mouse.get_rel() print "Click: {0}, rel: {1}.".format(pos, rel) time.sleep(0.25) pygame.display.flip() 1 Cytuj Link do komentarza Share on other sites More sharing options...
Popularny post Gieneq Wrzesień 21, 2018 Autor tematu Popularny post Udostępnij Wrzesień 21, 2018 Aktualizacja projektu - prawdopodobnie jest to też jego zakończenie. Idąc dalej z projektem stwierdziłem, że ogromne opóźnienie metody rozrostu pikseli nie jest akceptowalne. Dodatkowo podejście takie zawęża tolerancje obszarów o zróżnicowanej jasności - maksymalna możliwa tolerancja wynika z progu włączenia metody rozrostu. Jak to często bywa rozwiązania popularne są po prostu lepsze niż te bardziej niekonwencjonalne. Zastępując metodę rozrostu pikseli oklepanym wykrywaniem krawędzi Canyego i funkcją OpenCV (tu nie powiem jak się nazywa bo w dokumentacji jest odnośnik do jakiejś pracy na ten temat) uzyskałem działanie w czasie rzeczywistym. Zaskakująco podejście to działa równie dobrze ale było trochę mało precyzyjne dla niskich kontrastów, dla tego je udoskonaliłem. Metoda progowania Otsu wykorzystująca fakt występowania bimodalności (2 nałożone rozkłady normalne - "2 szczyty") histogramu wylicza próg automatycznie - jest to jednak nietrafiony pomysł gdy do charakterystyki obrazu włącza się niezwiązane obszary chociażby statyw ujęty w kadrze. Można zamaskować część zdjęcia albo wyliczyć własną wartość progu - w tym celu zawężam nieco obszar roboczy (drugi okrąg na ekranie) i w jego miejscu w 4 punktach próbuję jasność tła. Także ze środka ekranu (plama) próbkuje jasność pikseli. Z tych 2 wartości (widocznych w dolnym lewym narożniku ekranu) obliczam wartość progu dopasowanego wyłącznie do mierzonej plamy. Stosując kilka testowych znaczników udało mi się zejść do tolerancji odcieni szarości o zawartości 20% K. Dzięki wskazówce dot. PyGame napisałem ładniejszy GUI, w którym można dostroić parametry, wykonać zapis (pojawi się na chwilę dymek ze ścieżką zapisu), zamknąć system. Aplikację wzbogaciłem o możliwości Samby – pomiary są zapisywane w narastająco indeksowanych katalogach i udostępniane w postaci miejsca sieciowego SMB. Pliki można otworzyć tworząc miejsce sieciowe na Windowsie czy używając dowolnej aplikacji SMB. W tym miejscu aparatura się kończy bo spełnia wymagania specyfikacji ale jako, że jest to część pracy powiedzmy "badawczej" to zabrałem się za dalsze eksperymenty - 2 przypadki: pole powierzchni ze zdjęcia wykonanego w przestrzeni, pole powierzchni ze zdjęcia zagiętej powierzchni. Pierwszy problem jest dobrze znany i z pomocą przychodzi transformacja perspektywiczna - polega na przekształceniu jednego układu odniesienia w drugi przy pomocy macierzy transformacji. W wyniku linie proste pozostają proste w wynikowym obrazie (szczególnym przypadkiem jest przekształcenie afiniczne, w którym linie pozostają też równoległe). Ciekawe jest że ta na pozór skomplikowana operacja jest do policzenia na kartce! Wystarczy rozwiązać układ 8 równań z 8 niewiadomymi 😋 Współczynniki g, h są równe 0 dla przekształcenia afinicznego i decydują o charakterystycznym zagięciu perspektywy. Jak łatwo się domyśleć potrzeba 4 punktów do wykonania tej operacji i tyle też przyjmuje funckja OpenCV tworząca macierz mapującą 4 punkty wejściowe na wyjściowe. Za punkty docelowe wybierając narożniki prostokąta dokonuje się rozprostowana (ang. rectifying). Sytuacja ta jest o tyle dobra, że piksele są widoczne "top-down" i mają identyczne wagi podczas obliczeń. Aby policzyć pole powierzchni stosuję opisanąwcześniej metodę. Jaka jest dokładność tej metody? Myślałem że będzie słabo, ale po to są badania żeby coś udowodnić. Okazuje się, że dokładność jest dużo większa! Ale gdzie w tym wszystkich wartość referencyjna? Tu można szukać różnych sposobów ale skorzystałem z najprostszego - znana wielkość kwadratowej kartki - dzięki niej transformacja to banał, a rozprostowany obraz posiada równie banalny współczynnik proporcjonalności. W tym miejscu zaciekawiło mnie jak to jest z dystorsją (radialną) soczewki i jak radzi sobie z tym OpenCV. W moim przypadku wpływ dystorsji jest pomijalny, ale w wielu przypadkach jest on widoczny i łatwo sobie z nim poradzić stosując model Browna. Nieskończony szereg można ograniczyć i w OpenCV kończy się chyba na 3 współczynniku. Parametry można dobrać eksperymentalnie albo przy pomocy znanego wzoru szachownicy wydrukowanej na kartce dokonać kalibracji kamery. W ten sposób w przyszłych zdjęciach nie będzie widocznego wpływu dystorsji - chyba że jest ona bardzo duża. Drugi przypadek to zakrzywiona powierzchnia kartki. Tu okazało się że temat ten nie jest tak popularny jak poprzedni i znalazłem o nim wzmianki jedynie w 3 pracach na temat OCR 🤨 Zagadnienie to znalazło miejsce w OCR ponieważ czasem zastępuje się toporny skaner zdjęciem książki wykonanej aparatem – potrzeba jest jakoś skompensować krzywiznę wniesioną przez gruby grzbiet okładki książki. Na wstępnym etapie przetwarzania linie tekstu są pomocne w estymacji funkcji w jaką układa się kartka. W moim przypadku nie ma takiej informacji i doszedłem do 2 słusznych wniosków: bardzo ambitny wniosek – nie da się tego zrobić 😅, nawet jak się da to nie policzę wartości rzeczywistej. Wpadłem jednak na pomysł przybliżony - tak jak całkę przybliża się sumą tak gładką funkcję opisującą brzeg kartki zamieniłem na kilka odcinków. Zamiast liczyć całą powierzchnię, naniosłem na kartkę podziałkę (co 10 mm), podzieliłem obszar i policzyłem sumę tych podobszarów. Dzięki przekształceniu zachowującemu odcinki nie ma błędów wynikających z pocięcia plamy - pomimo widocznych skoków po złożeniu! Podziałka nie jest też bez przyczyny, nie znając krzywej opisującej brzeg kartki nie jestem w stanie stwierdzić jakie jest nachylenie kartki w danym miejscu i jaki powinien być współczynnik proporcjonalności. Dysponując podziału wyraźnie widzę gdzie kartka się zagina i mogę obliczyć inny współczynnik proporcjonalności dla każdego obszaru. Niestety punkty podziałki nie były wyznaczone automatycznie - to tylko doświadczenie, ale jak widać w obrazie wyjściowym podziałka jest stała - oznacza to poprawne przekształcenie. Znowu wątpliwość, czy jest to jakkolwiek wiarygodny wynik? Jak najbardziej, błąd poniżej 1%! Czy jest to praktyczny przypadek? To już inna kwestia, ale wstępnie mogę powiedzieć, że tak 😁 4 Cytuj Link do komentarza Share on other sites More sharing options...
Polecacz 101 Zarejestruj się lub zaloguj, aby ukryć tę reklamę. Zarejestruj się lub zaloguj, aby ukryć tę reklamę. Produkcja i montaż PCB - wybierz sprawdzone PCBWay! • Darmowe płytki dla studentów i projektów non-profit • Tylko 5$ za 10 prototypów PCB w 24 godziny • Usługa projektowania PCB na zlecenie • Montaż PCB od 30$ + bezpłatna dostawa i szablony • Darmowe narzędzie do podglądu plików Gerber Zobacz również » Film z fabryki PCBWay
Pomocna odpowiedź
Dołącz do dyskusji, napisz odpowiedź!
Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!