Subpixel-Zoom


9

Ihre Aufgabe ist es, ein 24-BPP-sRGB-Bild aufzunehmen und dasselbe Bild 3x in rote, grüne und blaue Subpixel hochskaliert auszugeben. Das resultierende Bild besteht vollständig aus reinen schwarzen, roten, grünen und blauen Pixeln.

Jedes Pixel aus dem Quellbild erzeugt beim Zoomen eine Anordnung von 9 Subpixeln, die entweder ein- oder ausgeschaltet sein können (dh ihre jeweilige Farbe oder Schwarz). Die spezifische Anordnung verwendet drei Spalten von Rot, Grün und Blau in dieser Reihenfolge wie folgt:

RGB-Subpixel

(Beachten Sie, dass die Ränder dieser "Pixel" nur zur Demonstration dienen.)

Da jedes der neun Subpixel nur ein- oder ausgeschaltet sein kann, müssen Sie das Eingabebild quantisieren und verschiedene Subpixelmuster verwenden, um 3 Helligkeitsstufen zu erzielen.

Für jedes Subpixel im Bild:

  • Für die Farbstufen 0-74 sollten alle Subpixel schwarz sein.
  • Für die Farbstufen 75-134 sollte das mittlere Subpixel die jeweilige Farbe und die anderen beiden schwarz sein.
  • Für die Farbstufen 135-179 sollte das mittlere Subpixel schwarz sein und die anderen beiden sollten die jeweilige Farbe haben
  • Für die Farbstufen 180-255 sollten alle drei Subpixel ihre jeweilige Farbe haben

Ich habe diese Levelbereiche gewählt, weil diese zufällig gut aussehen

Wenden Sie diese Transformation auf jedes Pixel im Bild an und geben Sie das subpixel-hochskalierte Bild aus.

Einzelpixel-Beispiele

rgb (40, 130, 175) erzeugt dieses Muster:

00B / 0G0 / 00B

rgb (160, 240, 100) erzeugt dieses Muster:

RG0 / 0GB / RG0

Beispiele für Vollbilder

Mona Lisa Mona Lisa Subpixel

Sternenklare Nacht Sternennacht-Subpixel

Papagei Papageien-Subpixel

Bilder aus Wikipedia

Regeln und Notizen

  • Die Eingabe und Ausgabe kann in einem beliebigen Format erfolgen, unabhängig davon, ob es sich um tatsächliche Bilddateien oder (möglicherweise verschachtelte) Listen mit RGB-Werten handelt.
  • Sie können davon ausgehen, dass sich die Pixel mit 24BPP im sRGB-Farbraum befinden.

Viel Spaß beim Golfen!


2
Die anfängliche Beschreibung klingt nach Un-Bayering. Es stellt sich heraus, dass dies nicht der Fall ist, teilweise aufgrund der unkonventionellen 3x3-Maske, sondern hauptsächlich aufgrund der Quantisierung, aber IMO ist es immer noch näher am Un-Bayering als am Subpixel-Zoom (was mit einer Art Kantenerkennung auf Anti-Skalierung hochskaliert wäre) alias).
Peter Taylor

danke für eine interessante herausforderung .... wird diese eigentlich für irgendetwas im wirklichen leben verwendet?
Don Bright

Antworten:


4

JavaScript (Node, Chrome, Firefox), 111 Byte

E / A-Format: Wertematrix [R,G,B].

a=>[...a,...a,...a].map((r,y)=>r.flat().map((_,x)=>a[y/3|0][x/3|0].map(v=>x--%3|511+y%3%2*3104>>v/15&1?0:255)))

Probieren Sie es online aus! (nur ein einziges Pixel)

Wie?

Alle Schwellenwerte sind Vielfache von 15. Anstatt explizite Vergleichstests durchzuführen, ist es etwas kürzer, eine Bitmaske zu testen, bei der jedes Bit ein Intervall von 15 Werten darstellt (mit Ausnahme des höchstwertigen Bits, das einem einzelnen Wert zugeordnet ist).

 bit | range   | top/bottom | middle
-----+---------+------------+--------
  0  |   0- 14 |     off    |   off
  1  |  15- 29 |     off    |   off
  2  |  30- 44 |     off    |   off
  3  |  45- 59 |     off    |   off
  4  |  60- 74 |     off    |   off
  5  |  75- 89 |     off    |    on
  6  |  90-104 |     off    |    on
  7  | 105-119 |     off    |    on
  8  | 120-134 |     off    |    on
  9  | 135-149 |      on    |   off
 10  | 150-164 |      on    |   off
 11  | 165-179 |      on    |   off
 12  | 180-194 |      on    |    on
 13  | 195-209 |      on    |    on
 14  | 210-224 |      on    |    on
 15  | 225-239 |      on    |    on
 16  | 240-254 |      on    |    on
 17  |   255   |      on    |    on

10

Wir bekommen:

  • 000000000111111111511
  • 0000001110000111113615

Kommentiert

a =>                      // a[] = input matrix
  [...a, ...a, ...a]      // create a new matrix with 3 times more rows
  .map((r, y) =>          // for each row r[] at position y:
    r.flat()              //   turn [[R,G,B],[R,G,B],...] into [R,G,B,R,G,B,...]
                          //   i.e. create a new list with 3 times more columns
    .map((_, x) =>        //   for each value at position x:
      a[y / 3 | 0]        //     get [R,G,B] from the original matrix
       [x / 3 | 0]        //     for the pixel at position (floor(x/3), floor(y/3))
      .map(v =>           //     for each component v:
        x-- % 3 |         //       1) yield a non-zero value if this is not the component
                          //          that we're interested in at this position
        511 +             //       2) use either 511 for top and bottom pixels
        y % 3 % 2 * 3104  //          or 3615 for the middle pixel (y mod 3 = 1)
        >> v / 15         //          divide v by 15
        & 1               //          and test the corresponding bit
        ?                 //       if either of the above tests is truthy:
          0               //         yield 0
        :                 //       else:
          255             //         yield 255
      )                   //     end of map() over RGB components
    )                     //   end of map() over columns
  )                       // end of map() over rows

Beispiel

Das folgende Code-Snippet verarbeitet den Kopf von Mona Lisa (64x64). Funktioniert nicht mit Edge.


3

Gelee , 27 Bytes

<“⁷KṆ‘‘Ḅœ?Ɗo⁹’)×€"3⁼þ¤)ẎZ)Ẏ

[0,255][r, g, b]

Probieren Sie es online aus! In diesem Beispiel wird ein Zwei-mal-Zwei-Bild aufgenommen, wobei das obere linke Pixel das erste Beispielpixel ist, das obere rechte Pixel das zweite Beispielpixel ist, das untere linke Pixel ein schwarzes Pixel ist und das untere rechte Pixel ein weißes Pixel ist Pixel.

Wie?

<“⁷KṆ‘‘Ḅœ?Ɗo⁹’)×€"3⁼þ¤)ẎZ)Ẏ - Link: list of lists of lists of integers, I
                         )  - for each row, R, in I:
                      )     -   for each pixel, P, in R:
              )             -     for each integer, C, in P:
 “⁷KṆ‘                      -       list of code-page indices = [135,75,180]
<                           -       less than -> [C<135,C<75,C<180] 
          Ɗ                 -       last three links as a monad:
      ‘                     -         increment -> [1+(C<135),1+(C<75),1+(C<180)]
       Ḅ                    -         from binary -> 4*(1+(C<135))+2*(1+(C<75))+1+(C<180)
        œ?                  -         permutation at that index of [C<135,C<75,C<180]
                            -         when all permutations sorted lexicographically
                            -       ... a no-op for all but [0,0,1]->[0,1,0]
            ⁹               -       256
           o                -       logical OR  e.g. [0,1,0]->[256,1,256]
             ’              -       decrement               ->[255,0,255]
                     ¤      -     nilad followed by link(s) as a nilad:
                  3         -       three
                    þ       -       table with: (i.e. [1,2,3] . [1,2,3])
                   ⁼        -         equal?    -> [[1,0,0],[0,1,0],[0,0,1]]
                 "          -     zip with:
                €           -       for each:
               ×            -         multiply
                       Ẏ    -   tighten (reduce with concatenation)
                        Z   -   transpose
                          Ẏ - tighten

Ich versuche herauszufinden, wo es [[1,0,0]. [0,1,0], [0,0,1]] codiert, und ich bin verblüfft.
Don Bright

@donbright 3⁼þ¤führt ein äußeres Produkt des [1,2,3]=[1,2,3]Nachgebens aus, [[1=1,2=1,3=1],[2=1,2=2,2=3],[3=1,3=2,3=3]]das ist [[1,0,0],[0,1,0],[0,0,1]].
Jonathan Allan

2

Wolfram Language (Mathematica) , 186 Bytes

Eingabe und Ausgabe sind Listen von RGB-Werten

(g=#;Flatten[(T=Transpose)@Flatten[T/@{{#,v={0,0,0},v},{v,#2,v},{v,v,#3}}&@@(If[(l=Max@#)<75,v,If[74<l<135,{0,l,0},If[134<l<179,{l,0,l},{l,l,l}]]]&/@#)&/@g[[#]],1]&/@Range[Length@g],1])&

Probieren Sie es online aus!


Wolfram Language (Mathematica), 243 Bytes

Dieser zweite Code ist eine Funktion , die einen als Eingabe Bild und gibt ein Bild
(ich weiß nicht , warum die Leute in den Kommentaren waren verwirrt)

Also, wenn Sie dieses Bild füttern

Geben Sie hier die Bildbeschreibung ein

in diese Funktion

(i=#;Image[Flatten[(T=Transpose)@Flatten[T/@{{#,v={0,0,0},v},{v,#2,v},{v,v,#3}}&@@(If[(l=Max@#)<75,v,If[74<l<135,{0,l,0},If[134<l<179,{l,0,l},{l,l,l}]]]&/@#)&/@ImageData[i,"Byte"][[#]],1]&/@Range[Last@ImageDimensions@i],1],ColorSpace->"RGB"])&


Sie erhalten diese Ausgabe

Geben Sie hier die Bildbeschreibung ein


2
Würde dies nicht als fest codierte Eingabe gelten?
Attinat

"Eingabe und Ausgabe können in jedem geeigneten Format erfolgen, unabhängig davon, ob es sich um tatsächliche Bilddateien handelt ...". Nein, iist ein Bild.
J42161217

Ich würde @attinat zustimmen, das sieht nach Hardcodierung aus.
Jonathan Frech

Ich habe einige Änderungen vorgenommen und hoffe, dass jetzt alles klar ist.
J42161217

1

C # (Visual C # Interactive Compiler) , 157 Byte

n=>{int i=0,j=n[0].Length;for(;;Write(z(0)+",0,0|0,"+z(1)+",0|0,0,"+z(2)+"\n|"[++i%j&1]));int z(int k)=>(((511^i/j%3%2*4064)>>n[i/j/3][i%j][k]/15)&1^1)*255;}

Druckt das RGB der Ausgabe. Die Ausgabe ist durch Zeilenumbrüche getrennt und nicht ausgerichtet. Ursprünglich benutzte ich eine Bitmaske, um ein- 1und 0auszuschalten, aber dann sah ich Arnauld's Antwort, und mir wurde klar, dass die Verwendung 0von Ein und 1Aus Bytes in der Zahl sparen könnte. Die TIO-Verbindung enthält ein 4 "x 2 Pixel großes Beispiel" Bild ".

Probieren Sie es online aus!


0

APL + WIN, 102 Bytes

Fordert eine 2D-Matrix von Pixeln als 24-Bit-Ganzzahlen auf, wie sie im Bild erscheinen würden

((⍴a)⍴,3 3⍴255*⍳3)×a←(3 1×⍴m)⍴∊⍉((1↓⍴m)/⍳↑⍴m)⊂n←(-+⌿n)⊖n←1 0↓0 75 135 180∘.≤,m←(1 3×⍴m)⍴,⍉(3⍴256)⊤,m←⎕

Probieren Sie es online aus! Mit freundlicher Genehmigung von Dyalog Classic

Gibt eine 2d-Matrix mit 24-Bit-Ganzzahlen des transformierten Bildes aus. Der größte Teil des Codes übernimmt die Formatierung der Ein- und Ausgabe.

Beispiel: Nehmen Sie ein 2 x 2-Bild auf, das aus den Beispielpixeln besteht

Eingang:

2654895 10547300
2654895 10547300

Ausgabe:.

0     0 16581375 255 65025        0
0 65025        0   0 65025 16581375
0     0 16581375 255 65025        0
0     0 16581375 255 65025        0
0 65025        0   0 65025 16581375
0     0 16581375 255 65025        0

0

Rost - 281 Bytes

fn z(p:Vec<u8>,wh:[usize;2])->Vec<u8>{let mut o=vec![0;wh[0]*wh[1]*27];for m in 0..wh[0]{for n in 0..wh[1]{for i in 1..=3{for j in 0..3{o[m*9+n*wh[0]*27+j*wh[0]*9+i*2]=match p[18+m*3+n*wh[0]*3+3-i]{75..=134=>[0,1,0],135..=179=>[1,0,1],180..=255=>[1,1,1],_=>[0,0,0],}[j]*255;}}}}o}

Diese Zeile ist eine Funktion, die der Herausforderung gerecht wird. Bei der Eingabe handelt es sich jedoch tatsächlich um Daten im TGA-Dateiformat, wie auf paulbourke.net beschrieben , sowie um eine vorab analysierte Breite und Höhe des Bilds in Pixel. Es gibt Pixeldaten für die Ausgabe als Bytes in einem Vektor zurück, der neunmal so groß ist wie die eingegebenen Pixeldaten.

use std::fs::File;use std::io::{Read,Write};fn main(){let mut p=vec![];let mut o=vec![0u8;18];File::open("i.tga").unwrap().read_to_end(&mut p).unwrap();let mut wh=[0;2];let h=|x|p[x] as usize;let g=|x|(3*x/256) as u8;for i in 0..2{wh[i]=h(12+i*2)+256*h(13+i*2);o[12+i*2]=g(wh[i]*256);o[13+i*2]=g(wh[i]);}let mut f=File::create("o.tga").unwrap();o[2]=2;o[16]=24;o.extend(z(p,wh));f.write(&o).unwrap();}

Diese zweite Zeile ist eine main () -Funktion, die eine Eingabedatei mit dem Namen i.tga in eine Ausgabedatei mit dem Namen o.tga umwandeln kann, indem die Funktion z aus der ersten Zeile aufgerufen wird, ohne externe Bibliotheken zu verwenden. Es behandelt das Parsen von Breite / Höhe, das Erstellen eines Headers für die Ausgabedatei und das Lesen und Schreiben von Dateien. Es würde 402 Bytes hinzufügen, wenn die Herausforderung Datei-E / A für insgesamt 683 erfordert. Es ist nützlich zum Testen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.