Jak pochmurno

22

Wyzwanie

Biorąc pod uwagę obraz nieba, musisz wyprowadzić osłonę chmur w oktach. Dostarczony obraz będzie plikiem obrazu (typ zależy od Ciebie), a wyjście powinno mieć format STDOUT.

Oktas

W meteorologii okta jest jednostką miary używaną do opisywania wielkości zachmurzenia w dowolnym miejscu, takim jak stacja pogodowa. Warunki na niebie są szacowane na podstawie tego, ile ósmych nieba jest zachmurzonych, od 0 oktas (całkowicie czyste niebo) do 8 oktas (całkowicie zachmurzone).

Niebo zawsze będzie obrazem z około południa (czyli błękitne niebo, a nie czerwone / nocne niebo).

Kolor chmury zawsze będzie kolorem zgodnym z następującym wzorem:

#ABCDEF

Gdzie AB >= C0, CD >= C0iEF >= C0 .

Lub w RGB:

(A, B, C)

Gdzie A >= 192, B >= 192iC >= 192 .

Oto procent pokrycia związany z oktami:

0%    - 0 oktas
12.5% - 1 okta
25%   - 2 oktas
37.5% - 3 oktas
50%   - 4 oktas
62.5% - 5 oktas
75%   - 6 oktas
87.5% - 7 oktas
100%  - 8 oktas

Procenty to procent obrazu, który jest chmurą.

Jeśli procent chmury twojego obrazu nie jest wielokrotnością 12,5, powinieneś zaokrąglić do najbliższego.

Wydajność

Wyjście powinno być po prostu liczbą okta (nie musisz podawać jednostki).

Przykłady

1 okta (18,030743615677714% chmury)

0 okt (0,0% chmury)

3 okty (42.66319444444445% chmury)

1 okta (12.000401814778645% chmury)

Kod Python używany do obliczania liczb

Zwycięski

Najkrótszy kod w bajtach wygrywa.

Rozpad beta
źródło
Czy to nie ostatnie 3 okty?
TheLethalCoder
@TheLethalCoder Whoops, edytowane
Beta Decay
Czy istnieje maksymalny wymiar obrazu?
Kudłaty
2
Dodałem czwarty przypadek testowy, który wymaga zaokrąglenia w górę do 12,5, ponieważ odpowiedzi wykorzystujące podłogę całkowitą minęłyby pierwsze 3 przypadki testowe.
Justin Mariner
1
Jeśli chodzi o języki, które nie mają możliwości przetwarzania obrazów, takie jak C ++, czy można korzystać z biblioteki? Jeśli tak, to w przypadku liczby bajtów powinno to uwzględniać tylko napisany kod, a także rozmiar plików DLL wymaganych do uruchomienia programu?
HatsuPointerKun

Odpowiedzi:

10

Python 2 , 114 110 98 bajtów

-4 bajty dzięki TheLethalCoder
-12 bajtów dzięki Ruud

import PIL.Image as P
i=P.open(input()).getdata()
print round(8.*sum(min(x)>191for x in i)/len(i))

Wypróbuj online!

Pręt
źródło
Użyć 191zamiast tego?
TheLethalCoder
2
Chciałem zasugerować x&y&z&192>191, ale zaktualizowana wersja jest równie krótka.
Arnauld
2
Można potencjalnie zastąpić import PIL.Image as Pz from PIL.Image import*i zapisywać 1 bajt kiedy zmienia i=P.opensię i=open? Nie wiem, czy to spowodowałoby problemy, ponieważ open jest już zdefiniowaną funkcją, ale nie mogę przetestować, ponieważ nie mam możliwości zainstalowania modułu.
Arnold Palmer
1
Tak, to wydaje się działać. Oszczędza 1 bajt.
Arfie
2
@Rod twój kod nie musi działać na wszystkich platformach - język jest definiowany przez tłumacza. Jeśli działa dla Ciebie, to jest ważny.
Tim
10

MATL , 18 17 bajtów

Yi191>3&A1eYm8*Yo

Przykład działa z czterema dostarczonymi obrazami (przepraszam za jakość podglądu; kliknij, aby uzyskać pełną rozdzielczość):

wprowadź opis zdjęcia tutaj

Lub usuń cztery ostatnie znaki, aby zobaczyć wyniki bez zaokrąglania:

wprowadź opis zdjęcia tutaj

Wyjaśnienie

Yi     % Implicitly input filename or URL. Read image. Gives an M×N×3 array
191>   % Does each entry exceed 191?
3&A    % True for 3rd-dim "lines" that only contain true. Gives an M×N matrix
1e     % Linearize (flatten) into a 1×L row vector, with L = M*N
Ym     % Mean of vector
8*     % Multiply by 8
Yo     % Round. Implicitly display
Luis Mendo
źródło
Zastanawiam się, co można zrobić za pomocą esolangów
Евгений Новиков
6

Java (OpenJDK 8) , 204 bajty

i->{int x=0,y=0,t=0,w=i.getWidth(),h=i.getHeight();for(;x<w;)for(y=0;y<h;){java.awt.Color c=new java.awt.Color(i.getRGB(x++,y++));if(c.getRed()>191&&c.getBlue()>191&&c.getGreen()>191)t++;}return 8*t/w/h;}

Wypróbuj online! Zawsze zapominam, że TIO wysyła STDERR do zakładki debugowania. Może w przypadku błędu może podświetlić się na czerwono?

Roman Gräf
źródło
Kilka rzeczy: Twój kod działa obecnie w nieskończonej pętli, ponieważ nigdy nie zwiększasz xani y. Przypisałeś y=0dwa razy, więc możesz usunąć pierwsze zadanie. Klasa Colormusi być w pełni kwalifikowana ( java.awt.Color) lub musisz uwzględnić import w swojej liczbie bajtów. Twój kod kończy się niepowodzeniem dla 4. przypadku testowego (zwraca 0 zamiast 1).
Justin Mariner,
Wiem, że to było trochę czasu, ale można golf 6 bajtów poprzez usunięcie wsporników wewnętrznych dla pętli i zmiana &&celu &i ,y=0do ,y: Spróbuj go online.
Kevin Cruijssen
6

C #, 150 146 bajtów

b=>{int t=0,c=0,w=0,h;for(;w<b.Width;++w)for(h=0;h<b.Height;++t){var p=b.GetPixel(w,h++);if(p.R>191&p.G>191&p.B>191)c++;}return(int)(c/(t+0d)*8);}

Zaoszczędzono 4 bajty dzięki @Ian H.

Wersja pełna / sformatowana:

using System.Drawing;

namespace System
{
    class P
    {
        static void Main()
        {
            Func<Bitmap, int> f = b =>
            {
                int t = 0, c = 0, w = 0, h;
                for (; w < b.Width; ++w)
                    for (h = 0; h < b.Height; ++t)
                    {
                        var p = b.GetPixel(w, h++);

                        if (p.R > 191 & p.G > 191 & p.B > 191)
                            c++;
                    }

                return (int)(c / (t + 0d) * 8);
            };

            string[] testCases =
            {
                @"Appearance_of_sky_for_weather_forecast,_Dhaka,_Bangladesh.JPG",
                @"spanish-sky.jpeg",
                @"why-is-sky-blue-1.jpg",
            };

            foreach (string testCase in testCases)
            {
                using (Bitmap bitmap = new Bitmap(testCase))
                {
                    Console.WriteLine(f(bitmap));
                }
            }

            Console.ReadLine();
        }
    }
}
TheLethalCoder
źródło
for(h=0 h<b.Height;++t)Myślę, że przegapiłeś tam dwukropek
Kritixi Lithos
2
Można wymienić /0.125z *8na końcu zaoszczędzić kilka bajtów.
Ian H.,
@ Cowsquack Usunąłem średnik zamiast spacji! Naprawiono teraz ..
TheLethalCoder
3

C #, 313 bajtów

namespace System.Drawing.Imaging{b=>{unsafe{int t=0,c=0,y=0,x,w=b.Width,h=b.Height;var d=b.LockBits(new Rectangle(0,0,w,h),(ImageLockMode)1,(PixelFormat)137224);for(;y<h;++y){var r=(byte*)d.Scan0+y*d.Stride;for(x=0;x<w*3;++t)if(r[x++]>191&r[x++]>191&r[x++]>191)c++;}b.UnlockBits(d);return(int)(c/(t+0d)/0.125);}}}

Oczywiście dłuższa niż moja inna odpowiedź, ale ta wykorzystuje LockBitsi unsafekod do bezpośredniego dostępu do obrazu w pamięci; jako taki jest niezwykle szybki. Prawdopodobnie mógłbym usunąć połączenie zUnlockBits ale jest to bardziej poprawne.

Wersja pełna / sformatowana:

namespace System.Drawing.Imaging
{
    class P
    {
        static void Main()
        {
            Func<Bitmap, int> f = b =>
            {
                unsafe
                {
                    int t = 0, c = 0, y = 0, x, w = b.Width, h = b.Height;

                    var d = b.LockBits(new Rectangle(0, 0, w, h), (ImageLockMode)1, (PixelFormat)137224);
                    for (; y < h; ++y)
                    {
                        var r = (byte*)d.Scan0 + y * d.Stride;

                        for (x = 0; x < w * 3; ++t)
                            if (r[x++] > 191 & r[x++] > 191 & r[x++] > 191)
                                c++;
                    }
                    b.UnlockBits(d);

                    return (int)(c / (t + 0d) / 0.125);
                }
            };

            string[] testCases =
            {
                @"Appearance_of_sky_for_weather_forecast,_Dhaka,_Bangladesh.JPG",
                @"spanish-sky.jpeg",
                @"why-is-sky-blue-1.jpg",
            };

            foreach (string testCase in testCases)
            {
                using (Bitmap bitmap = new Bitmap(testCase))
                {
                    Console.WriteLine(f(bitmap));
                }
            }

            Console.ReadLine();
        }
    }
}
TheLethalCoder
źródło
3

PowerShell , 200 bajtów

$a=New-Object System.Drawing.Bitmap $args[0]
0..($a.Height-1)|%{$h=$_;0..($a.Width-1)|%{$i+=(("$($a.GetPixel($_,$h)|select R,G,B)"|iex)['R','G','B']-ge192).count-eq3}}
[int]($i/($a.Height*$a.Width)*8)

Pobiera dane wejściowe $args[0]jako pełną ścieżkę pliku obrazu, konstruuje New Bitmapobiekt $a. To tylko wewnętrzna nazwa obiektu; obsługuje JPG, PNG itp.

Następnie podwójnie zapętlamy obraz, .heighta następnie .widthobraz, dotykając każdego z nich pixel. Możemy wyciągnąć R,G,Bwartości, a następnie wybrać te, które są -greaterthanor eWyn się 192i upewnij się, że countjest 3(czyli wszystkie z nich są biało-owski). Ten wynik logiczny jest dodawany do naszego akumulatora $i.

Następnie dzielimy się, aby uzyskać procent, pomnóż go, 8aby uzyskać liczbę okt, a następnie, [int]aby uzyskać tylko liczbę całkowitą. (Pamiętaj, że powoduje to zaokrąglanie za pomocą Bankera - jeśli nie jest to dozwolone, zmiana metody zaokrąglania będzie wymagała kilku kolejnych bajtów).

AdmBorkBork
źródło
2

dc, 74 bajty

???*sa?[1+]ss[r1+r]st[?191<s]su0ddsd[0luxluxlux3=t1+dla>r]dsrxr8*la2/+la/p

Dane wejściowe są traktowane jako plik P3 ppm, a wszystkie białe znaki są znakami nowej linii. Dane wyjściowe to STDOUT.

Wypróbuj online!

poi830
źródło
2

JavaScript, 83 77 bajtów

-6 bajtów według ETHproductions

f=i=>(z=a=b=0,i.map(e=>{z=e<192||z;(++b%4)||((z||(a+=64))&&(z=0))}),a/b+1>>1)

Wejścia

Obrazek 1

Zdjęcie nr 2

Zdjęcie nr 3

Zdjęcie nr 4

Próbny

Евгений Новиков
źródło
1
Bardzo fajne rozwiązanie. Przydatną sztuczką z funkcjami strzałek ES6 jest zawijanie wszystkiego w nawiasy, oddzielone przecinkami ( a=>(b,c,d)) zamiast wykonywania a=>{b;c;return d}lub a=>eval("b;c;d"). Działa to, chyba że masz jakąś pętlę, w którym to przypadku prawdopodobnie najlepiej będzie użyć tej evalmetody.
ETHprodukcje
2

C (POSIX), 103 bajty

Zakłada wejście jako plik BMP na standardowym wejściu.

b,c,i,m=0xc0c0c0;main(){lseek(0,54,0);for(;read(0,&b,3);c+=(b&m)==m,i++);printf("%d",(i+16*c)/(2*i));}
yoann
źródło
2

Kod maszynowy x86, 34 bajty

51
31 D2
AD
F7 D0
25 C0 C0 C0 00
75 01
42
E2 F3
C1 E2 03
DB 04 24
52
DB 04 24
DE F1
DB 1C 24
58
5A
C3

Te bajty kodu definiują funkcję, która pobiera dane bitmapy i zwraca wartość całkowitą wskazującą jej okty. Podobnie jak w C , tablice (podobnie jak mapy bitowe) są reprezentowane jako wskaźnik do pierwszego elementu oraz rozmiar / długość. Tak więc ta funkcja przyjmuje dwa parametry: całkowitą liczbę pikseli na mapie bitowej (wiersze x kolumny) i wskaźnik do samej mapy bitowej.

W tym kodzie zastosowano niestandardową konwencję wywoływania opartą na rejestrze, w której wskaźnik bitmapy jest przekazywany w pliku ESI rejestru, a rozmiar mapy bitowej jest przekazywany do ECXrejestru. Wynik (oktas) jest zwykle zwracany EAX.

Jak już wspomniano powyżej, dane wejściowe są traktowane jako mapa bitowa. W szczególności używany jest format 32-bpp w formacie little-endian, ale kanał alfa (bajt najwyższego rzędu) jest ignorowany. Upraszcza to wiele rzeczy, pozwalając nam po prostu iterować każdy piksel i sprawdzać jego 32-bitową wartość koloru RGB. Zastosowano tu również sprytną optymalizację. Zamiast izolować każdy składnik koloru i sprawdzać, czy jest to> = 192, po prostu maskujemy całą 32-bitową wartość o 0xC0C0C0 i sprawdzamy, czy wynik to> = 0xC0C0C0. Spowoduje to ocenę wartości true dla wszystkich kolorów „chmurowych” i false dla wszystkich kolorów „niebiańskich” (niebędących chmurami). Dobrze, ja myślałem, że to mądry! :-) Z pewnością oszczędza dużą liczbę bajtów.

Dlatego, aby przetestować ten kod, musisz przekonwertować obrazy wejściowe na bitmapy o 32 bitach na sekundę. Nie można do tego użyć Windows Paint, ponieważ obsługuje on maksymalnie 24 bity na piksel. Istnieje jednak wiele innych rozwiązań programowych, takich jak Adobe Photoshop. Użyłem tego bezpłatnego narzędzia , które konwertuje PNG do BMP o 32 bitach na sekundę w systemie Windows, co oznacza, że ​​potrzebujesz tylko konwersji z JPEG na PNG (co potrafi Paint).

Inne założenia, które moim zdaniem są wyjątkowo uzasadnione:

  • Zakłada się, że bitmapa ma rozmiar większy niż 0 ( tj . Zakłada się, że zawiera co najmniej jeden piksel). Jest to uzasadnione, ponieważ gdy niebo jest puste, mamy większe problemy niż meteorologia.
  • DFZakłada się, że flag kierunku ( ) jest czysty, dzięki czemu będziemy poprawnie iterować przez mapę bitową za pomocą LODSDinstrukcji. Jest to to samo założenie przyjęte przez większość konwencji wywoływania x86, więc wydaje się uczciwe. Jeśli ci się nie podoba, dodaj 1 bajt do liczby dlaCLD instrukcji.
  • Zakłada się, że tryb zaokrąglania dla FPU x87 jest ustawiony na zaokrąglenie do najbliższego parzystego. To gwarantuje, że otrzymamy prawidłowe zachowanie, gdy przekonwertujemy liczbę okt z liczb zmiennoprzecinkowych tymczasowych na końcowy wynik w postaci liczb całkowitych, co weryfikuje przypadek testowy nr 4. To założenie jest uzasadnione, ponieważ jest to stan domyślny dla FPU i go zachować nawet w kodzie C (gdzie obcięcie jest domyślnym zachowaniem zaokrąglania, zmuszając kompilatory, które chcą być zgodne ze standardami, do generowania nieefektywnego kodu zmieniającego zaokrąglanie , wykonuje konwersję, a następnie zmienia z powrotem tryb zaokrąglania).

Mnemoniki do montażu bez golfa:

; int ComputeOktas(void*    bmpBits  /* ESI */,
;                  uint32_t bmpSize  /* ECX */);
   push  ecx                  ; save size on stack
   xor   edx, edx             ; EDX = 0 (cloudy pixel counter)

CheckPixels:
   lodsd                      ; EAX = DS:[ESI]; ESI += 4
   not   eax
   and   eax, 0x00C0C0C0
   jnz   NotCloudy
   inc   edx
NotCloudy:
   loop  CheckPixels          ; ECX -= 1; loop if ECX > 0

   shl    edx, 3              ; counter *= 8
   fild   DWORD PTR [esp]     ; load original size from stack
   push   edx
   fild   DWORD PTR [esp]     ; load counter from stack
   fdivrp st(1), st(0)        ; ST(0) = counter*8 / size
   fistp  DWORD PTR [esp]     ; convert to integer, rounding to nearest even
   pop    eax                 ; load result
   pop    edx
   ret

Z pewnością nie udało ci się tak dobrze i nadal zastanawiasz się, jak działa kod? :-)
Cóż, to całkiem proste. Po prostu iterujemy bitmapę po jednej wartości 32-bitowej na raz, sprawdzając, czy wartość RGB tego piksela jest „zachmurzona”, czy „nieprzejrzysta”. Jeśli jest pochmurno, zwiększamy nasz wstępnie wyzerowany licznik. Na koniec obliczamy: piksele zachmurzonepiksele całkowite  × 8
(co odpowiada: pikselom pochmurnympikselom całkowitym  ÷ 0,125).

Nie mogę do tego dołączyć łącza TIO ze względu na potrzebę wprowadzenia obrazów wejściowych. Mogę jednak dostarczyć uprząż, której użyłem do przetestowania tego w systemie Windows:

#include <stdio.h>
#include <assert.h>
#include <Windows.h>

int main()
{
   // Load bitmap as a DIB section under Windows, ensuring device-neutrality
   // and providing us direct access to its bits.
   HBITMAP hBitmap = (HBITMAP)LoadImage(NULL,
                                        TEXT("C:\\...\\test1.bmp"),
                                        IMAGE_BITMAP,
                                        0, 0,
                                        LR_LOADFROMFILE  | LR_CREATEDIBSECTION);
   assert(hBitmap != NULL);

   // Get the bitmap's bits and attributes.
   DIBSECTION dib;
   GetObject(hBitmap, sizeof(dib), &dib);
   assert(dib.dsBm.bmBitsPixel == 32);
   uint32_t cx = dib.dsBm.bmWidth;
   uint32_t cy = abs(dib.dsBm.bmHeight);
   uint32_t sz = cx * cy;
   assert(sz > 0);

   int oktas = ComputeOktas(sz, dib.dsBm.bmBits);

   printf("%d\n", oktas);

   return 0;
}

Uważaj jednak na to! Jak zdefiniowano powyżej, ComputeOktaswykorzystuje niestandardową konwencję wywoływania, której kompilator C nie będzie przestrzegał. Musisz dodać kod u góry procedury języka asemblera, aby załadować wartości ze stosu do oczekiwanych rejestrów, np . :

mov  ecx, DWORD PTR [bmpSize]
mov  esi, DWORD PTR [bmpBits]
Cody Gray
źródło
1

JavaScript (ES6), 218 bajtów

(a,c=document.createElement`canvas`,w=c.width=a.width,h=c.height=a.height,x=c.getContext`2d`)=>x.drawImage(a,0,0)||x.getImageData(0,0,w,h).data.reduce((o,_,i,d)=>o+(i%4|d[i++]<192|d[i++]<192|d[i]<192?0:1),0)/w/h*8+.5|0

Pobiera Imageobiekt jako dane wejściowe, które można utworzyć z <image>elementu.

Przetestuj to tutaj na CodePen!

Alternatywny

Jeśli dane wejściowe można przyjąć jako płaską tablicę wartości RGBA, o wymiarach: 82 bajty

(d,w,h)=>d.reduce((o,_,i)=>o+(i%4|d[i++]<192|d[i++]<192|d[i]<192?0:1),0)/w/h*8+.5|0

Ten format wejściowy jest bardzo podobny do tego, co sugeruje ta odpowiedź w meta .

Justin Mariner
źródło
1

Matematyka 89 bajtów

Poniżej binaryzuje obraz i określa ułamek chmur, czyli białych pikseli. Następnie określa, ile razy .125 pasuje do wyniku. Zwraca dolną granicę tej wartości.

o@i_:=⌊8Tr@Flatten[ImageData@MorphologicalBinarize[i,.932],1]/Times@@ImageDimensions@i⌋
DavidC
źródło