2012-10-02 24 views
6

Szukałem wszędzie, ale wydaje się, że nie ma standardu (widziałem), jak można by sprawdzić, czy obraz jest pusty. W języku C#Sprawdzanie, czy obraz jest pusty w C#

Mam sposób robienia tego, ale chciałbym wiedzieć, jaki jest prawidłowy sposób sprawdzania, czy obraz jest pusty, aby wszyscy mogli również wiedzieć w przyszłości.

Nie mam zamiaru kopiować wkleić kilka kodu, jeśli chcesz, to będzie dla mnie przyjemnością, ale najpierw chcę wyjaśnić, jak sprawdzam, czy obraz jest pusty.

Bierzesz obraz .jpg, Pobierz jego szerokość. Na przykład 500 pikseli Następnie podzielić to przez 2 daje 250

Następnie należy sprawdzić, co kolor każdego piksela jest w miejscu (250 szerokości i wysokości) (gdzie iteracyjne pomyślał wysokosc

To, co wtedy robimy, to tylko sprawdzenie pionowej linii pikseli obrazu w pionie.Test jednak, że wszystkie piksele sprawdzają, czy kolor jest cokolwiek Z wyjątkiem białego. Zrobiłem to, więc nie masz przeszukać WSZYSTKO 500 * wysokości pikseli, a ponieważ prawie zawsze natkniesz się na kolor na środku strony:

Jego działanie ... trochę powolne ... Musi być lepszy sposób na zrobienie tego? Możesz go zmienić, aby wyszukiwał linie 2/3/4 w pionie, aby zwiększyć szansę na wykrycie strony, która nie jest pusta, ale to potrwa jeszcze dłużej.

(Należy również pamiętać, korzystając z rozmiaru obrazu, aby sprawdzić, czy zawiera coś nie zadziała w tym przypadku, ponieważ strona z dwóch zdań na i rozmiar pustej strony jest zbyt blisko siebie)

Po dodaniu rozwiązania.

Zasoby pomagające we wdrożeniu i zrozumieniu rozwiązania.

(Zauważ, że na pierwszej stronie, podaną Pizelformat jest rzeczywiście PixelFormat) - Mały błąd wiem, po prostu wspomnieć, może powodować pewne zamieszanie.

Po wdrożeniu metody przyspieszenia polowania na piksele prędkość nie wzrosła tak bardzo. Więc sądzę, że robię coś złego.

Stary czas = 15,63 dla 40 zdjęć.

Nowy czas = 15,43 do 40 obrazów

widziałem z wielkim artykule DocMax quoted, że kod „zamki” w zestawie pikseli. (lub tak to zrozumiałem) Zrobiłem więc blokadę w środkowym rzędzie pikseli każdej strony. Czy byłoby to właściwe posunięcie?

private int testPixels(String sourceDir) 
    { 
     //iterate through images 
     string[] fileEntries = Directory.GetFiles(sourceDir).Where(x => x.Contains("JPG")).ToArray(); 

     var q = from string x in Directory.GetFiles(sourceDir) 
       where x.ToLower().EndsWith(".jpg") 
       select new FileInfo(x); 

     int holder = 1; 
     foreach (var z in q) 
     { 
      Bitmap mybm= Bitmap.FromFile(z.FullName) as Bitmap; 
      int blank = getPixelData2(mybm); 

      if (blank == 0) 
      { 
       holder = 0; 
       break; 
      } 
     } 
     return holder; 
    } 

A potem klasa

private unsafe int getPixelData2(Bitmap bm) 
     { 
      BitmapData bmd = bm.LockBits(new System.Drawing.Rectangle((bm.Width/2), 0, 1, bm.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, bm.PixelFormat); 

      int blue; 
      int green; 
      int red; 

      int width = bmd.Width/2; 
      for (int y = 0; y < bmd.Height; y++) 
      { 
       byte* row = (byte*)bmd.Scan0 + (y * bmd.Stride); 

       blue = row[width * 3]; 
       green = row[width * 2]; 
       red = row[width * 1]; 

       // Console.WriteLine("Blue= " + blue + " Green= " + green + " Red= " + red); 
       //Check to see if there is some form of color 
       if ((blue != 255) || (green != 255) || (red != 255)) 
       { 
        bm.Dispose(); 
        return 1; 
       } 
      } 
      bm.Dispose(); 
      return 0; 
     } 
+0

Czy mierzyłeś czas, ile zajmuje? Jeśli tak, to jaki był czas i jaka była wysokość obrazu? – 3aw5TZetdf

+1

Musisz zrobić coś złego w swojej implementacji, ponieważ twój algorytm wydaje mi się dobry. Znalezienie jednej kolumny mapy bitowej nie powinno zająć więcej czasu. –

+0

Łączny czas na 32 zdjęć = 00: 00: 12.9187389 Wysokość = 6552 Szerokość = 4580 – Ruan

Odpowiedz

7

Jeśli można tolerować szanse na to błędne podejście wydaje się dobrze; W moim przypadku zrobiłem coś bardzo podobnego, chociaż zawsze miałem wizualne potwierdzenie, by poradzić sobie z błędami.

W przypadku wydajności kluczowym pytaniem otwartym jest pytanie o sposób testowania pikseli. Jeśli używasz Bitmap.GetPixel, masz problemy z wydajnością. (Wyszukaj "Bitmap.GetPixel slow" w Google, aby zobaczyć wiele dyskusji.)

Znacznie lepsza wydajność będzie pochodzić z uzyskania wszystkich pikseli jednocześnie, a następnie pętli nad nimi. Osobiście lubię Bob Powell's LockBits discussion dla jasności i kompletności. Dzięki takiemu podejściu sprawdzenie wszystkich pikseli może być uzasadnione w zależności od potrzeb związanych z wydajnością.

+0

Jesteś naprawdę na miejscu, używam Bitmap.GetPixel. Dziękuję chorym Sprawdź to rozwiązanie i opublikuj moje wyniki tutaj, aby znaleźć pełne rozwiązanie i "odważyć się powiedzieć" standard, jak sprawdzić obraz. – Ruan

+0

Więc wdrożyłem rozwiązanie. Jedyna rzecz to, że czasy są prawie identyczne. Stary czas = 15.63 dla 40 obrazów. Nowy czas to = 15,43 dla 40 zdjęć. Wyjaśnię jako dodatkowe informacje na moje pytanie powyżej, co zrobiłem. – Ruan

+0

Przyspiesza to z ułamkiem. Myślę, że trudno jest zobaczyć wzrost z ilością posiadanych danych. Dziękuję – Ruan

2

Jeśli używasz System.Drawing.Bitmap można przyspieszyć rzeczy (zasadniczo), przez:

  1. Nie używając getPixel aby uzyskać dostęp do pikselach użytku LockBits i UnlockBits skopiowanie obrazu do bitmapy zwykła pamięć. Zobacz przykłady na temat korzystania z urządzenia MSDN documentation.
  2. Nie wywoływanie właściwości Szerokość, Wysokość lub Rozmiar w pętli for. Rozmiar wywołania raz, przechowaj wartości w zmiennej lokalnej i użyj tych w pętli.

Uwagi:

  1. Przy korzystaniu System.Drawing.Bitmap obraz może być w pamięci urządzenia i dostępu może być czasochłonne.
  2. Nie pamiętam, czy wczytanie obrazu do bitmapy już konwertuje go do formatu RGB, ponieważ inne formaty są trudniejsze do pracy, ale jeśli tak nie jest, możesz utworzyć bitmapę RGB o tym samym rozmiarze, co oryginalny obraz, pobierz obiekt graficzny (Graphics.FromImage) i użyj DrawImage, aby narysować oryginalny obraz w bitmapie RGB.

Edytuj: Przejdź do uderzenia DocMax.

W każdym razie dla szybkości możesz także spróbować użyć alternatywnych bibliotek, takich jak doskonała FreeImage, która zawiera owijarki C#.

0

skalowanie obrazu do 1x1 następnie sprawdzić jeden piksel

nowe Bitmap (previousImage, nowy rozmiar (1, 1));

+0

To jest genialne, niestety nie działa na większości obrazów, które wypróbowałem (zestaw płytek 64x56 z wartościami kolorów argb). Pojedynczy piksel często wynosi 0,0,0,0, nawet jeśli źródło zawiera pewne dane obrazu. – PeteB

+0

Zrobiłem kolejny test używając 2x2 i sprawdzając wszystkie cztery piksele. Było lepiej, ale nadal było puste, gdy w kafelku była niewielka ilość treści. – PeteB