Ne Kadar Bulutlu?


22

Meydan okuma

Gökyüzünün bir görüntüsü göz önüne alındığında, bulut örtüsünü oktas olarak çıkarmanız gerekir. Sağlanan görüntü bir görüntü dosyası olacaktır (tür size bağlıdır) ve çıktı STDOUT olmalıdır.

okta

Meteorolojide okta, meteoroloji istasyonu gibi herhangi bir yerdeki bulut örtüsünün miktarını tanımlamak için kullanılan bir ölçü birimidir. Gökyüzü koşulları, gökyüzünün sekizde birinin bulutta kaplandığı, 0 oktadan (tamamen açık gökyüzü) ila 8 oktaya (tamamen bulutlu) kadar tahmin edilmektedir.

Gökyüzü her zaman gün ortasından bir resim olacak (yani mavi gökyüzü, kırmızı / gece gökyüzü değil).

Bir bulutun rengi her zaman aşağıdaki deseni izleyen bir renk olacaktır:

#ABCDEF

Nerede AB >= C0, CD >= C0ve EF >= C0.

Veya, RGB’de:

(A, B, C)

Nerede A >= 192, B >= 192ve C >= 192.

İşte okta ile ilgili yüzde ortalamalar:

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

Yüzdeler, bulut olan görüntünün yüzdesidir.

Resminizin yüzde bulutunun değeri 12,5'in katları değilse, en yakına yuvarlamanız gerekir.

Çıktı

Çıktı sadece okta numarası olmalıdır (birimi söylemek zorunda değilsiniz).

Örnekler

1 okta (18.030743615677714% bulut)

0 oktas (% 0.0 bulut)

3 oktas (42.66319444444445% bulut)

1 okta (12.000401814778645% bulut)

Sayıları hesaplamak için kullanılan Python kodu

Kazanan

Bayt cinsinden en kısa kod kazanır.


Sonuncusu 3 oktas değil mi?
TheLethalCoder

@TheLethalCoder Düzenlendi, düzenlendi
Beta Decay,

Bir görüntünün boyutlarında maksimum var mı?
Shaggy,

2
Tamsayı döşeme kullanan cevaplar ilk 3 test vakasını geçiyor olacağı için, 12.5'e kadar yuvarlama gerektiren bir 4. test vakası ekledim.
Justin Mariner,

1
C ++ gibi görüntü işleme özelliklerine sahip olmayan diller hakkında bir kütüphane kullanmak uygun mudur? Öyleyse, bayt sayısı için, yalnızca yazılı kodu mu yoksa programı çalıştırmak için gereken DLL dosyalarının boyutunu mu saymalı?
HatsuPointerKun

Yanıtlar:


10

Python 2 , 114 110 98 bayt

TheLethalCoder sayesinde -4 bayt
Ruud sayesinde 12 bayt

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

Çevrimiçi deneyin!


kullanım 191 kullanın?
TheLethalCoder

2
Bunu önerecektim x&y&z&192>191, ancak güncellenmiş versiyon kısa.
Arnauld, temmuz

2
Potansiyel yerine Could import PIL.Image as Pile from PIL.Image import*değiştirirken ve 1 byte kaydetmek i=P.openiçin i=open? Açık zaten tanımlanmış bir işlev olduğundan bunun sorunlara yol açıp açmadığını bilmiyorum, ancak modülü kuramadığım için test edemiyorum.
Arnold Palmer

1
Evet, bu iş gibi görünüyor. 1 bayt kaydeder.
Arfie

2
@ Kodunuzu tüm platformlarda çalıştırmak zorunda değilsiniz - dil yorumlayıcı tarafından tanımlanır. Sizin için çalışırsa, o zaman geçerlidir.
Tim,

10

MATL , 18 17 bayt

Yi191>3&A1eYm8*Yo

Örnek, sağlanan dört görüntüyle çalışır (önizleme kalitesi için özür dilerim; tam çözünürlük için tıklayın):

enter image description here

Veya sonuçları yuvarlamadan görmek için son dört karakteri kaldırın:

enter image description here

açıklama

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

Esolangs kullanarak neler yapılabilir merak ediyorum
Евгений

6

Java (OpenJDK 8) , 204 bayt

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;}

Çevrimiçi deneyin! Her zaman TIO'nun STDERR'yi hata ayıklama sekmesine gönderdiğini unutuyorum.


Çok az şey var: kodunuz şu anda sonsuz bir döngüde çalışıyor, çünkü siz hiçbir zaman artırmıyorsunuz xveya y. Atanan y=0ilk atamayı kaldırmak böylece, iki kere. Sınıf Color, tam kalifiye ( java.awt.Color) olmalı veya alma işlemini bayt sayınıza eklemelisiniz. Kodunuz 4. sınama durumu için başarısız olur (1 yerine 0 döndürür).
Justin Mariner,

Bir süre geçtiğini biliyorum, ancak iç forge braketlerini söküp ve to- &&to değiştirerek 6 bayt golf oynayabilirsiniz : Çevrimiçi deneyin. &,y=0,y
Kevin Cruijssen

6

C #, 150 146 bayt

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);}

@Ian H sayesinde 4 byte kurtarıldı

Tam / Biçimli sürüm:

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();
        }
    }
}

for(h=0 h<b.Height;++t)Orada bir yarı-kolon özledim bence
Kritixi Lithos

2
Sonunda bir kaç bayt kaydetmek için /0.125ile değiştirebilirsiniz *8.
Ian H.

@Cowsquack Boşluk yerine yarı sütunu sildim! Şimdi düzeltildi ..
TheLethalCoder

3

C #, 313 bayt

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);}}}

Açıkçası, diğer cevabımdan daha uzun, ama bu , bellekteki resme doğrudan erişmek için kullanıyor LockBitsve unsafekod kullanıyor ; Bu şekilde inanılmaz hızlı. Muhtemelen aramayı kaldırabilirimUnlockBits ama onunla daha doğru.

Tam / Biçimli sürüm:

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();
        }
    }
}

3

PowerShell , 200 bayt

$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)

Girişi $args[0]tam görüntü dosya yolu olarak alır, New Bitmapiçine bir nesne inşa eder$a . Bu sadece dahili nesne adıdır; JPG, PNG, vb. destekler.

Daha sonra , her birine dokunarak görüntünün içinde .heightve sonra iki kez döngülenir . Biz çekin değerleri ve sonra olanları seçmek reaterthanor için Elemeleri emin ve yapmak olduğu (yani hepsi beyaz-ish). Bu Boole sonucu akümülatörümüze eklendi.widthpixelR,G,B-ge192count3$i .

Daha sonra yüzdeyi elde etmek için bölün 8, oktas sayısını almak için çarpın ve sonra [int]sadece bir tamsayı elde etmek için çoğaldık . (Bunun, Bankanın Yuvarlama işlemini gerçekleştirdiğini unutmayın - buna izin verilmezse, yuvarlama yöntemini değiştirmek için birkaç bayt olacaktır.)


2

dc, 74 bayt

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

Giriş, tüm boşluklarla yeni satırlar olarak bir P3 ppm dosyası olarak alınır. Çıkış STDOUT içindir.

Çevrimiçi deneyin!


2

JavaScript, 83 77 bayt

ETHproductions tarafından -6 bayt

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

Girdiler

Resim # 1

Resim 2

Resim 3

Resim 4

gösteri


1
Çok güzel bir çözüm. ES6 ok işlevlerine sahip kullanışlı bir püf nokta, her şeyi parantez içine almak, veya a=>(b,c,d)yapmak yerine virgül ( ) ile ayırmaktır . Bu, bir çeşit döngüye sahip olmadığınız sürece işe yarar, bu durumda muhtemelen yöntemi kullanarak en iyi durumda olursunuz . a=>{b;c;return d}a=>eval("b;c;d")eval
ETHproductions

2

C (POSIX), 103 bayt

Girdiyi stdin'de BMP dosyası olarak kabul eder.

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));}

2

x86 Makine Kodu, 34 bayt

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

Bu kod baytları, bir bitmap girişi alan ve oktasını gösteren bir tamsayı değeri döndüren bir işlev tanımlar. C gibi gibi, diziler (bitmapler gibi) ilk elemana bir işaretçi ve bir boyut / uzunluk olarak temsil edilir. Bu nedenle, bu işlev iki parametre alır: bitmap'teki toplam piksel sayısı (satırlar × sütunlar) ve bitmap'in kendisine bir işaretçi.

Bu kod, bitmap işaretçisinin ESIkayıt defterine iletildiği ve bitmap boyutunun kayıt defterine iletildiği özel bir kayıt tabanlı çağrı kuralı kullanır ECX. Sonuç (oktaş) her zamanki gibi iade edilir.EAX .

Yukarıda belirtildiği gibi giriş bir bitmap olarak alınır. Spesifik olarak, 32-bpp formatı, biraz endian formatta kullanılır, ancak alfa kanalı (en yüksek sıradaki bayt) dikkate alınmaz. Bu, pek çok şeyi basitleştirir, her bir piksele basitçe yinelememize ve 32 bit RGB renk değerini kontrol etmemize izin verir. Akıllıca bir optimizasyon da burada kullanılmaktadır. Her renk bileşenini izole etmek ve> = 192 olup olmadığını kontrol etmek yerine, tüm 32 bitlik değeri 0xC0C0C0 ile maskeleyip sonucun> = 0xC0C0C0 olup olmadığını test ederiz. Bu, tüm "bulut" renkleri için doğru, tüm "gökyüzü" (bulut olmayan) renkler için yanlış olarak değerlendirilecektir. Peki, ben o zeki olduğunu düşündüm! :-) Kesinlikle çok sayıda bayt tasarrufu sağlar.

Bu nedenle, bu kodu test etmek için, giriş görüntülerini 32 bpp bitmap'lere dönüştürmeniz gerekir. Bunun için Windows Paint'i kullanamazsınız, çünkü piksel başına maksimum 24 bit desteklemektedir. Ancak, Adobe Photoshop gibi bunu yapabilecek başka yazılım çözümleri de var. Ben kullanılan bu ücretsiz aracıBir PNG'yi Windows'ta 32 bpp BMP'ye dönüştüren , bu da yalnızca JPEG'den PNG'ye (Paint'in yapabileceği) dönüştürmeniz gereken anlamına gelir.

Benim öne sürdüğüm diğer varsayımlar kesinlikle makul:

  • Bitmap'in 0'dan büyük bir boyuta sahip olduğu kabul edilir ( yani en az bir piksel içerdiği varsayılır). Bu makul, çünkü gökyüzü boş olduğunda meteorolojiden daha büyük problemlerimiz var.
  • Yön işaretinin ( DF) açık olduğu varsayılır, böylece LODSDtalimatı kullanarak bitmap boyunca doğru şekilde yineleniriz . Bu x86 çağrı sözleşmelerinin çoğu tarafından yapılan varsayımla aynıdır, bu yüzden adil görünüyor. Hoşunuza gitmediyse, bir sayı için 1 bayt ekleyin.CLD talimat .
  • X87 FPU’nun yuvarlama modunun, en yakına yuvarlağa ayarlandığı varsayılmıştır. Bu, okta sayısını kayan noktadan geçici bir noktadan nihai tamsayı sonucuna dönüştürdüğümüzde doğru davranışı elde etmemizi sağlar (4 numaralı test durumu). Bu varsayım mantıklıdır, çünkü bu FPU için varsayılan durumdur ve C kodunda bile tutulmalıdır (burada kesmenin varsayılan yuvarlama davranışıdır, yuvarlamayı değiştiren verimsiz kod üretmeyi standartlaştırmak isteyen derleyicileri zorlar) modu, dönüştürme yapar ve sonra yuvarlama modunu geri değiştirir).

Ungolfed montaj anımsatıcıları:

; 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

Elbette bütün bu yolu bulamadı ve hala kodun nasıl çalıştığını merak ediyorsun? :-)
Eh, oldukça basit. Sadece bir seferde bitmapte bir 32 bitlik değeri yineleyerek, piksel RGB değerinin "bulutlu" veya "bulutlu değil" olup olmadığını kontrol ettik. Hava bulutluysa, sıfırlanan sayacımızı artırırız. Sonunda hesaplıyoruz: bulutlu piksellertoplam pikseller  × 8
(buna eşittir: bulutlu piksellertoplam pikseller  ÷ 0.125).

Giriş görüntülerine duyulan ihtiyaç nedeniyle bunun için bir TIO bağlantısı içeremiyorum. Bununla birlikte, bunu Windows'ta test etmek için kullandığım kablo demetini sağlayabilirim:

#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;
}

Yine de buna dikkat et! Yukarıda tanımlandığı gibi, ComputeOktasbir C derleyicisinin saygı göstermeyeceği özel bir çağrı kuralları kullanır. Yığından gelen değerleri beklenen kayıtlara yüklemek için, montaj dili prosedürünün en üstüne kod eklemeniz gerekir, örneğin :

mov  ecx, DWORD PTR [bmpSize]
mov  esi, DWORD PTR [bmpBits]

1

JavaScript (ES6), 218 bayt

(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

Bir Imagenesneyi bir <image>elemandan yaratılabilen girdi olarak alır .

CodePen'de burada test edin!

Alternatif

Girdi düz RGBA değerleri dizisi olarak alınabiliyorsa, boyutları: 82 bayt

(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

Bu giriş biçimi, meta üzerindeki bu cevabın önerdiğine çok benzer .


1

Mathematica 89 bayt

Aşağıdaki, görüntüyü ikilileştirir ve bulutların oranını, yani beyaz pikselleri belirler. Daha sonra, kaç kere .125 sonuç için uygun olduğunu belirler. Bu değerin tabanını döndürür.

o@i_:=⌊8Tr@Flatten[ImageData@MorphologicalBinarize[i,.932],1]/Times@@ImageDimensions@i⌋
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.