Porównywanie plików graficznych

0

Planuję zrobić pewien programik, tylko nie wiem jak zrobić jedną rzecz. Otóż muszę porównać dwa pliki graficzne. Program robi zrzut ekranu (obraz np 1000px na 500px) i szuka na nim obrazu mniejszego (np. 40px na 10px), a po znalezieniu klika na współrzędne pkt o 15px wyżej niż współrzędne miejsca gdzie znalazł mniejszy obraz na większym. Bardzo proszę o pomoc.

0

Sądząc po ilości odpowiedzi widzę, że może być z tym problem, więc może chociaż ktoś wie jak sprawdzać kolor pikseli na ekranie. Np piksel (90, 100) jest biały to robi coś a jak zielony to coś innego.

0

Po zrzucie ekranu dostajesz BufferedImage, poczytaj dokumentację http://docs.oracle.com/javase/7/docs/api/java/awt/image/BufferedImage.html (metoda getRGB).

0

Widziałem rozwiązania pierwotnego problemu (wyszukiwanie mniejszego obrazu w większym) dość łatwo implementowane w OpenCV. Skoro teraz OpenCV ma bindini do Javy to możesz spróbować pod tym kątem poszukać.

0

Może to też być szukanie małego obrazu na ekranie, niekoniecznie na większym obrazie.

0

'Na ekranie' niczego nie znajdziesz, musisz zrobić printscreena, a wtedy to już nie jest ekran tylko de facto duży obrazek.

0

Dzięki wielkie za propozycje rozwiązania problemu, ale jakoś nie mogę do tego dojść

0

Kurcze, mi to zajęło nie całe 5 minut http://stackoverflow.com/a/17516753
Jeżeli chcesz kompleksowego rozwiązania które będzie screenshoty robić, znajdywać obrazki i klikać to możesz też na Sikuli popatrzeć.

0

Przecież robienie screenshotów jest trywialne. Metoda createScreenCapture w klasie Robot.

0

Mówię o szukaniu obrazka mniejszego na większym, screeny umiem ;)

0

Ten mniejszy w większym to musi się dokładnie zgadzać (identyczne składowe RGB), czy też dopuszczalne są pewne różnice? Tak czy owak możesz porównywać punkt po punkcie każdy podprostokąt większego obrazka mający odpowiedni rozmiar z małym obrazkiem.

0

Dobra już wiem, bardzo dziękuję, jak będą jakieś problemy z programem to jeszcze się Was poradzę.

0

Tło obrazka się zmienia :/

0

OpenCv i fraza w google "find smaller image in bigger image" ewentualnie "find feature in image". Na pewno znajdziesz jakiegoś gotowca, na którym możesz się oprzeć.

0

Mam taki kod:

import org.opencv.core.Core;
import org.opencv.core.Core.MinMaxLocResult;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.highgui.Highgui;
import org.opencv.imgproc.Imgproc;

class MatchingDemo {
    public void run(String inFile, String templateFile, String outFile, int match_method) {
        System.out.println("\nRunning Template Matching");

        Mat img = Highgui.imread(inFile);
        Mat templ = Highgui.imread(templateFile);

        // / Create the result matrix
        int result_cols = img.cols() - templ.cols() + 1;
        int result_rows = img.rows() - templ.rows() + 1;
        Mat result = new Mat(result_rows, result_cols, CvType.CV_32FC1);

        // / Do the Matching and Normalize
        Imgproc.matchTemplate(img, templ, result, match_method);
        Core.normalize(result, result, 0, 1, Core.NORM_MINMAX, -1, new Mat());

        // / Localizing the best match with minMaxLoc
        MinMaxLocResult mmr = Core.minMaxLoc(result);

        Point matchLoc;
        if (match_method == Imgproc.TM_SQDIFF || match_method == Imgproc.TM_SQDIFF_NORMED) {
            matchLoc = mmr.minLoc;
        } else {
            matchLoc = mmr.maxLoc;
        }

        // / Show me what you got
        Core.rectangle(img, matchLoc, new Point(matchLoc.x + templ.cols(),
                matchLoc.y + templ.rows()), new Scalar(0, 255, 0));

        // Save the visualized detection.
        System.out.println("Writing "+ outFile);
        Highgui.imwrite(outFile, img);

    }
}

public class TemplateMatching {
	public static void main(String[] args) {
        new MatchingDemo().run("lena.png", "template.png", "templatematch.png", Imgproc.TM_CCOEFF);
    }
}

tylko nie wiem czemu nie działa, błąd:

Exception in thread "main" java.lang.UnsatisfiedLinkError: org.opencv.highgui.Highgui.imread_1(Ljava/lang/String;)J
	at org.opencv.highgui.Highgui.imread_1(Native Method)
	at org.opencv.highgui.Highgui.imread(Highgui.java:359)
	at bot.MatchingDemo.run(Bot.java:16)
	at bot.Bot.main(Bot.java:51)

wszystko stąd: http://stackoverflow.com/questions/17001083/opencv-template-matching-example-in-android/17516753#17516753

0

Tam w błędzie zamiast Bot.java jest TemplateMatching.java

0

Tak naprawdę, to wcale nie chcesz porównywać plików graficznych, a obrazy, które są w nich zawarte. Plik graficzny zawiera nagłówek i dodatkowe informacje, które wcale nie muszą Cię interesować, albo są wręcz zbędne. Tak więc najpierw musisz pokonać problem wczytania do pamięci obrazów (mapy bitowej) z tych plików, żeby w ogóle mówić o szukaniu jednych obrazów w innych. Na szczęście w przypadku typowych plików Java robi to za Ciebie.

Najprostsza metoda wyszukiwania to porównywanie pikseli prostokąta wycinka. Działa jeżeli szukany obraz jest co do bita/piksela zgodny z obrazem większym. To znaczy w przypadku gdy szukany obrazek jest faktycznie wycinkiem oryginalnego obrazu. Wtedy iterujesz przez kolejne współrzędne x oraz y szukając dopasowania piksela np. lewego górnego rogu, a następnie pozostałych pikseli dla potwierdzenia lub odrzucenia znalezienia wycinka. Jako optymalizację można najpierw porównywać wartości pikseli wszystkich rogów oraz ewentualnie wybranego piksela ze środka (sprawdzenie 4-5 pikseli jest dość tanie, a pozwala szybko wykluczyć).
Kwestia rozłożenia iteracji - najpierw wierszami lub kolumnami, albo skanowanie najpierw co którąś linię pikseli - jest kwestią optymalizacji i dominującej zawartości obrazów. Na przykład jeżeli jest bardziej prawdopodobne znalezienie wycinka w środku obrazu, a nie na jego brzegach, to najpierw zaczyna się skanowanie od środka obrazu (np. podziel każdą współrzędną obrazu na 4 i zacznij przeszukiwanie od 2. i 3. ćwiartki). Ważne że trzeba przeskanować w taki sposób, aby matematycznie wykluczyć możliwość pominięcia.

W praktyce wyszukiwanie elementów obrazów nie jest nigdy tak proste ponieważ choćby użycie kompresji powoduje niewielkie zaburzenie chrominacji lub luminacji. W efekcie wycinki przestają być zgodne co do pikseli i wycinek nie zostanie znaleziony. Mimo iż człowiek bez problemu go zauważy. Żeby to pominąć można użyć dwóch sposobów:

Pierwszy polega na osłabianiu jakości pikseli. Na przykład przez zmniejszenie dokładności porównywania pikseli. Najprościej mówiąc każda składowa piksela RGB posiada przeznaczoną pewną ilość bitów na składową - typowo 8, 6, 5 lub 4 bitów zależnie od tego czy kolor piksela zakodowany jest w 32, 24, 16 czy 12 bitach. Można łatwo zmniejszyć jakość i tym samym dokładność porównywania przez przekodowanie każdego piksela obrazu i wycinka do celowo zmniejszonej jakości - np. po 4 bity na składową, co daje 12 bitów RGB. Przekodowanie jest dość proste ponieważ każda składowa, to po prostu liczba 0-255 (8-bitów), którą można proporcjonalnie zmniejszyć do zakresu 0-15 (4-bity). Wtedy tak zredukowany piksel wycinka można już porównywać z podobnie zredukowanym pikselem obrazu. Metoda ta załatwia problem nie tylko artefaktów, ale również różnej jakości obrazów ponieważ dolną granicą dokładności jest redukcja do zakresu 0-1, czyli 1-bit na składową, a cały piksel sprowadza się wtedy do 3 bitów. W ten sposób można znaleźć wycinki "prawdopodobne", które będą trudne do szybkiego wyszukania nawet przez człowieka.

Drugą, alternatywną metodą - która jest jednak obliczeniowo bardziej wymagająca - jest konwersja wszystkich pikseli obrazu (oraz wycinka) do modelu HSL. Następnie porównywanie nie całych pikseli, lecz wyłącznie składowych barwy (hue) oraz nasycenia barwy (saturation) pomijając jasność (lightness). Można też do określenia zgodności użyć dobranych arbitralnie wag barwy, nasycenia i jasności, dzięki czemu można znaleźć kolorowy wycinek na zdjęciu w sepii, monochromatyczny wycinek na zdjęciu kolorowym lub wycinki będące napisami, albo jakąś uproszczoną grafiką. Ewentualnie można użyć zupełnie innej kombinacji aby wyszukać celowo ukryte przed człowiekiem wycinki obrazu (można na przykład użyć samej luminacji do wyszukiwania w teście podobnym jak ten na daltonizm). Możliwości kombinowania w wyszukiwaniu obrazów są całkiem spore.

Co do Twojego ostatniego elementu zadania - jeżeli znajdziesz współrzędne na przykład lewego górnego wycinka w obrazie, to określenie współrzędnej do kliknięcia jest zwykłym dodawaniem lub odejmowaniem współrzędnej pionowej np. lewego górnego rogu lub środka górnej krawędzi znalezionego wycinka.

ps. Jakoś nie zauważyłem, że wątek ma już dwie strony. To co napisałem jest mniej więcej "automagicznie" robione w tym kodzie, który już masz.

1 użytkowników online, w tym zalogowanych: 0, gości: 1