Como está nublado?

22

Desafio

Dada uma imagem do céu, você deve exibir a cobertura de nuvens em octas. A imagem fornecida será um arquivo de imagem (o tipo é seu) e a saída deve ser STDOUT.

Oktas

Na meteorologia, um okta é uma unidade de medida usada para descrever a quantidade de nuvens em qualquer local, como uma estação meteorológica. As condições do céu são estimadas em termos de quantos oitavos do céu estão cobertos de nuvens, variando de 0 octas (céu completamente limpo) a 8 octas (completamente nublado).

O céu sempre será uma imagem por volta do meio-dia (portanto, céu azul, não vermelho / céu noturno).

A cor de uma nuvem sempre será uma cor que segue o seguinte padrão:

#ABCDEF

Onde AB >= C0, CD >= C0eEF >= C0 .

Ou, em RGB:

(A, B, C)

Onde A >= 192, B >= 192eC >= 192 .

Aqui estão as porcentagens de cobertura relacionadas aos octas:

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

As porcentagens são a porcentagem da imagem que é nuvem.

Se a nuvem percentual da sua imagem não for um múltiplo de 12,5, você deve arredondar para o mais próximo.

Saída

A saída deve ser apenas o número okta (você não precisa dizer a unidade).

Exemplos

1 octa (18,030743615677714% de nuvem)

0 octas (nuvem de 0,0%)

3 octas (42.66319444444445% de nuvem)

1 octa (12.000401814778645% de nuvem)

Código Python usado para calcular números

Ganhando

O menor código em bytes vence.

Beta Decay
fonte
O último não é 3 octas?
TheLethalCoder
@TheLethalCoder Whoops, editado
Decay Beta
Existe um máximo para as dimensões de uma imagem?
34
2
Adicionei um quarto caso de teste que requer arredondamentos de até 12,5, pois as respostas que usam piso inteiro passariam nos três primeiros casos de teste.
23717 Justin Mariner
1
Sobre idiomas que não possuem recursos de processamento de imagem como C ++, é possível usar uma biblioteca? Em caso afirmativo, para a contagem de bytes, deve contar apenas o código escrito ou também o tamanho dos arquivos DLL necessários para executar o programa?
HatsuPointerKun

Respostas:

10

Python 2 , 114 110 98 bytes

-4 bytes graças ao TheLethalCoder
-12 bytes graças ao Ruud

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

Experimente online!

Cajado
fonte
Usar em 191vez disso?
TheLethalCoder
2
Eu ia sugerir x&y&z&192>191, mas a versão atualizada é tão curta.
Arnauld
2
Você poderia substituir import PIL.Image as Pcom from PIL.Image import*e salvar 1 byte quando mudar i=P.openpara i=open? Não sei se isso causaria problemas, pois abrir já é uma função definida, mas não posso testar, pois não tenho a capacidade de instalar o módulo.
Arnold Palmer
1
Sim, isso parece funcionar. Economiza 1 byte.
Arfie
2
@ Rod seu código não precisa ser executado em todas as plataformas - o idioma é definido pelo intérprete. Se for executado para você, é válido.
Tim
10

MATL , 18 17 bytes

Yi191>3&A1eYm8*Yo

O exemplo é executado com as quatro imagens fornecidas (desculpe pela qualidade da visualização; clique para obter a resolução máxima):

insira a descrição da imagem aqui

Ou remova os quatro últimos caracteres para ver os resultados sem arredondar:

insira a descrição da imagem aqui

Explicação

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
fonte
Eu me pergunto o que pode ser feito usando esolangs
Евгений Новиков
6

Java (OpenJDK 8) , 204 bytes

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

Experimente online! Eu sempre esqueço que o TIO envia STDERR para a guia debug. Talvez ele possa destacar o vermelho em caso de erro?

Roman Gräf
fonte
Poucas coisas: seu código atualmente é executado em um loop infinito, já que você nunca incrementa xou y. Você atribuiu y=0duas vezes para remover a primeira atribuição. A classe Colordeve ser totalmente qualificada ( java.awt.Color) ou você deve incluir a importação na sua contagem de bytes. E seu código falha no quarto caso de teste (retorna 0 em vez de 1).
23717 Justin Mariner
Eu sei que tem sido um tempo, mas você pode golfe 6 bytes por retirar os suportes do interior para-loop, e mudar o &&que &e ,y=0para ,y: Experimente online.
Kevin Cruijssen
6

C #, 150 146 bytes

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

Guardado 4 bytes graças a @Ian H.

Versão completa / formatada:

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
fonte
for(h=0 h<b.Height;++t)Eu acho que você perdeu um ponto e vírgula lá
Kritixi Lithos
2
Você pode substituir /0.125por *8no final para salvar alguns bytes.
31717 Ian Ian H.
@ Cowsquack eu tinha excluído o ponto e vírgula em vez do espaço! Corrigido agora ..
TheLethalCoder 31/07
3

C #, 313 bytes

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

Obviamente, mais do que minha outra resposta, mas essa usa LockBitse unsafecodifica para acessar diretamente a imagem na memória; como tal, é incrivelmente rápido. Provavelmente eu poderia remover a chamada paraUnlockBits mas é mais correto com ela lá.

Versão completa / formatada:

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
fonte
3

PowerShell , 200 bytes

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

Obtém entrada $args[0] como o caminho completo do arquivo da imagem, constrói um New Bitmapobjeto $a. Este é apenas o nome do objeto interno; suporta JPG, PNG, etc.

Em seguida, fazemos um loop duplo na imagem .heighte depois .widthna imagem, tocando cada uma delas pixel. Retiramos os R,G,Bvalores e, em seguida, selecionamos aqueles que são -grealmente qualificados epara192 e certifique-se de que counté 3(ou seja, todos eles são branco-ish). Esse resultado booleano é adicionado ao nosso acumulador $i.

Em seguida, dividimos para obter a porcentagem, multiplicamos por 8para obter o número de octas e, em seguida, [int]para obter apenas uma saída inteira. (Observe que isso executa o arredondamento do banqueiro - se isso não for permitido, serão necessários mais alguns bytes para alterar o método de arredondamento.)

AdmBorkBork
fonte
2

dc, 74 bytes

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

A entrada é tomada como um arquivo P3 ppm, com todos os espaços em branco como novas linhas. A saída é para STDOUT.

Experimente online!

poi830
fonte
2

JavaScript, 83 77 bytes

-6 bytes por 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)

Entradas

Imagem 1

Imagem # 2

Imagem # 3

Imagem 4

Demo

Евгений Новиков
fonte
1
Solução muito boa. Um truque útil com as funções de seta do ES6 é agrupar tudo entre parênteses, separados por vírgulas ( a=>(b,c,d)) em vez de fazer a=>{b;c;return d}ou a=>eval("b;c;d"). Isso funciona, a menos que você tenha algum tipo de loop; nesse caso, provavelmente será melhor usar o evalmétodo
ETHproductions
2

C (POSIX), 103 bytes

Assume a entrada como arquivo BMP no stdin.

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
fonte
2

Código de máquina x86, 34 bytes

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

Esses bytes de código definem uma função que recebe uma entrada de bitmap e retorna um valor inteiro indicando seus oktas. Como em C , matrizes (como bitmaps) são representadas como um ponteiro para o primeiro elemento e um tamanho / comprimento. Portanto, essa função usa dois parâmetros: o número total de pixels no bitmap (linhas × colunas) e um ponteiro para o próprio bitmap.

Esse código usa uma convenção de chamada personalizada baseada em registro, em que o ponteiro de bitmap é passado no ESIregistro e o tamanho do bitmap é passado no ECXregistro. O resultado (octas) é, normalmente, retornado emEAX .

Como já mencionado acima, a entrada é tomada como um bitmap. Especificamente, um formato de 32 bpp é usado, em um formato little endian, mas o canal alfa (byte de ordem mais alta) é ignorado. Isso simplifica muitas coisas, permitindo simplesmente percorrer cada pixel e verificar seu valor de cor RGB de 32 bits. Uma otimização inteligente também é usada aqui. Em vez de isolar cada componente de cor e verificar se é> = 192, apenas mascaramos o valor inteiro de 32 bits por 0xC0C0C0 e testamos se o resultado é> = 0xC0C0C0. Isso será avaliado como verdadeiro para todas as cores "nuvem" e falso para todas as cores "céu" (sem nuvem). Bem, eu pensei que era inteligente! :-) Certamente salva um grande número de bytes.

Portanto, para testar esse código, você precisará converter as imagens de entrada em bitmaps de 32 bpp. Você não pode usar o Windows Paint para isso, porque ele suporta no máximo 24 bits por pixel. No entanto, existem várias outras soluções de software que podem fazer isso, como o Adobe Photoshop. Usei essa ferramenta gratuita , que converte um PNG em um BMP de 32 bpp no ​​Windows, o que significa que você só precisa converter de JPEG para PNG (o que o Paint pode fazer).

Outras suposições que afirmo são eminentemente razoáveis:

  • Supõe-se que o bitmap tenha um tamanho maior que 0 ( isto é, supõe-se que contenha pelo menos um pixel). Isso é razoável porque, quando o céu é nulo, temos problemas maiores que a meteorologia.
  • O sinalizador de direção ( DF) é assumido como claro, para que iteremos corretamente pelo bitmap usando oLODSD instrução Essa é a mesma suposição feita pela maioria das convenções de chamada x86, portanto parece justo. Se você não gostar, adicione 1 byte à contagem para obter uma CLDinstrução.
  • Presume-se que o modo de arredondamento para a FPU x87 esteja definido como arredondar para o par mais próximo. Isso garante que obtemos o comportamento correto ao converter o número de octas de um resultado temporário de ponto flutuante para o resultado inteiro final, conforme verificado no caso de teste nº 4. Essa suposição é razoável, porque esse é o estado padrão da FPU e deve ser mantido mesmo no código C (onde truncamento é o comportamento de arredondamento padrão, forçando os compiladores que desejam ser compatíveis com os padrões a gerar código ineficiente que altera o arredondamento , faz a conversão e depois altera o modo de arredondamento).

Mnemônicos de montagem não destruídos:

; 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

Certamente você não chegou até aqui e ainda está se perguntando como o código funciona? :-)
Bem, é bem simples. Apenas iteramos o bitmap de um valor de 32 bits por vez, verificando se o valor RGB do pixel está "nublado" ou "não nublado". Se estiver nublado, incrementamos nosso contador pré-zerado. No final, calculamos: pixels nubladospixels totais  × 8
(o que é equivalente a: pixels nubladospixels totais  ÷ 0,125).

Não posso incluir um link TIO para isso devido à necessidade de imagens de entrada. No entanto, posso fornecer o chicote que usei para testar isso no 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;
}

Tenha cuidado com isso, no entanto! Conforme definido acima, ComputeOktasusa uma convenção de chamada personalizada, que um compilador C não respeitará. Você precisa adicionar código na parte superior do procedimento da linguagem assembly para carregar valores da pilha nos registros esperados, por exemplo :

mov  ecx, DWORD PTR [bmpSize]
mov  esi, DWORD PTR [bmpBits]
Cody Gray
fonte
1

JavaScript (ES6), 218 bytes

(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

Pega um Imageobjeto como entrada, que pode ser criado a partir de um <image>elemento.

Teste aqui no CodePen!

Alternativo

Se a entrada puder ser tomada como uma matriz plana de valores RGBA, com dimensões: 82 bytes

(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

Esse formato de entrada é muito semelhante ao que esta resposta na meta sugere.

Justin Mariner
fonte
1

Mathematica 89 bytes

A seguir, binariza a imagem e determina a fração de nuvens, ou seja, pixels brancos. Em seguida, determina quantas vezes .125 se encaixa no resultado. Retorna o piso desse valor.

o@i_:=⌊8Tr@Flatten[ImageData@MorphologicalBinarize[i,.932],1]/Times@@ImageDimensions@i⌋
DavidC
fonte