CodeIQ MAGAZINECodeIQ MAGAZINE

【謎解きプログラム】フィルターを使ってみよう【SVG】解答と解説

2017.02.09 Category:CodeIQ問題解説・リーダーボード Tag:

  • 3
  • このエントリーをはてなブックマークに追加
entry

言語不問で、プログラムにちなんだ謎を解く「謎解きプログラム」。

あなたは見事、謎を解けましたか? というわけで、出題者の柳井さんによる解答と解説をどうぞ!
by CodeIQ運営事務局

【謎解きプログラム】フィルターを使ってみよう【SVG】

本問題は、表題のテーマで、プログラムにちなんだ謎を解くというものでした。

それでは以下、各問題とその解答を見ていきましょう。

問題のオープニング

ある日、出社すると、あなたのPCのログイン画面に、謎の挑戦状が表示されていた。

「24時間以内にが解けない場合は、このPCのデータは消失する。

 は、あなたが真のプログラマーなら解けるものだ」

これは挑戦状ではなく脅迫状だ!

そこには、見たことのない謎が掲載されていた。

あなたは歴戦のプログラマーとして、データを救うために、この謎に挑むことになった。

予備知識

SVGのフィルターは、<filter>タグ内で、各種フィルターのタグを使いフィルターをかけていきます。その際、in属性で入力名、result属性で出力名を指定して、パイプ処理のように効果を連結していきます。

in属性に指定する名前には、「SourceGraphic」(元の図形)や、「SourceAlpha」(元の図形のアルファチャンネル)といった特別なものもあります。また、result属性で指定した名前を、他のフィルターのin属性で指定できます。

各種フィルターのタグは、先頭の「fe」を取った名前の効果になります。以下、例です。

「feGaussianBlur」→「GaussianBlur」(ガウスぼかし)
「feOffset」→「Offset」(オフセット)
「feMorphology」→「Morphology」(形態)、属性「operator」が「dilate」なら拡張
「feColorMatrix」→「ColorMatrix」(カラーマトリクス)

また、<feMerge>タグ内では、「<feMergeNode>」タグで入力を描画順に並べて図形を合成できます。

問題1

以下に示されたSVGの場合、実際に描画される図を、図1~3で選んでください。

<svg viewBox="0 0 200 200">
  <defs>
    <filter id="f1" filterUnits="objectBoundingBox"
      x="-1" y="-1" width="3" height="3">
      <feGaussianBlur
        in="SourceAlpha" stdDeviation="10"
        result="blur"/>
      <feMerge>
        <feMergeNode in="blur"/>
        <feMergeNode in="SourceGraphic"/>
      </feMerge>
    </filter>
  </defs>
  <rect x="0" y="0" width="200" height="200"
    stroke-width="3" stroke="#fa0" fill="#ffa"/>
  <circle cx="100" cy="100" r="75"
    filter="url(#f1)"
    stroke-width="3" stroke="#0a6" fill="#afc"/>
</svg>

図1

図2

図3

// 選択肢
図1
図2
図3

上から順番に見ていきましょう。

<feGaussianBlur in="SourceAlpha" stdDeviation="10" result="blur"/>

上記では、入力(in)が「SourceAlpha」(元の画像のアルファ値)で、出力(result)が「blur」(という名前)になっています。

「feGaussianBlur」は、ガウスぼかしのフィルターです。「standard deviation」(標準偏差、散らばり具合)では散らばり具合を指定します。これで、元画像のアルファ値を元に、ぼかした画像が作成されます。

<feMerge>
  <feMergeNode in="blur"/>
  <feMergeNode in="SourceGraphic"/>
</feMerge>

次に、「<feMerge>」で、配下の「<feMergeNode>」の2画像を合成しています。

合成する画像は、入力(in)が「blur」(先ほど、ガウスぼかしフィルターで作った画像)と、入力(in)が「SourceGraphic」(元の画像)です。

この合成の順番は、「blur」が先で、「SourceGraphic」が後になります。つまり、ガウスぼかしをかけた画像を描画して、元の画像を描画することになります。

そのため、作成される図は、図2となり、2番目の選択肢の「図2」が答えになります。

問題2

以下に示されたSVGの場合、実際に描画される図を、図1~3で選んでください。

<svg viewBox="0 0 200 200">
  <defs>
    <filter id="f2" filterUnits="objectBoundingBox"
      x="-1" y="-1" width="3" height="3">
      <feGaussianBlur
        in="SourceAlpha" stdDeviation="10"
        result="blur"/>
      <feOffset
        in="blur" dx="10" dy="10"
        result="offset"/>
      <feMerge>
        <feMergeNode in="offset"/>
        <feMergeNode in="SourceGraphic"/>
      </feMerge>
    </filter>
  </defs>
  <rect x="0" y="0" width="200" height="200"
    stroke-width="3" stroke="#fa0" fill="#ffa"/>
  <circle cx="100" cy="100" r="75"
    filter="url(#f2)"
    stroke-width="3" stroke="#0a6" fill="#afc"/>
</svg>
図1

図2

図3

// 選択肢
図1
図2
図3

上から順番に見ていきましょう。

<feGaussianBlur in="SourceAlpha" stdDeviation="10" result="blur"/>

上記では、入力(in)が「SourceAlpha」(元の画像のアルファ値)で、出力(result)が「blur」(という名前)になっています。

「feGaussianBlur」は、ガウスぼかしのフィルターです。「standard deviation」(標準偏差、散らばり具合)では散らばり具合を指定します。これで、元画像のアルファ値を元に、ぼかした画像が作成されます。

<feOffset in="blur" dx="10" dy="10" result="offset"/>

次に、上記では、入力(in)が「blur」(ガウスぼかしフィルターで作った画像)で、出力が「offset」(という名前)になっています。

「feOffset」は、オフセットのフィルターです。「dx」「dy」で、X軸、Y軸の移動量を指定します。これで、入力画像を、「dx」「dy」分移動した画像が作成されます。

<feMerge>
  <feMergeNode in="offset"/>
  <feMergeNode in="SourceGraphic"/>
</feMerge>

最後に、「<feMerge>」で、「<feMergeNode>」の2つの画像を合成しています。

合成する画像は、入力(in)が「offset」(先ほど、オフセットフィルターで作った画像)と、入力(in)が「SourceGraphic」(元の画像)になります。

この合成の順番は、「offset」が先で、「SourceGraphic」が後になります。つまり、ガウスぼかしをかけて移動した画像を描画して、元の画像を描画することになります。

そのため、作成される図は、図3となり、3番目の選択肢の「図3」が答えになります。

問題3

以下に示されたSVGの場合、実際に描画される図を、図1~3で選んでください。

<svg viewBox="0 0 200 200">
  <defs>
    <filter id="f3" filterUnits="objectBoundingBox"
      x="-1" y="-1" width="3" height="3">
      <feMorphology
        in="SourceAlpha" operator="dilate" radius="3"
        result="morph"/>
      <feColorMatrix
        in="morph" type="matrix" values="0 0 0 0 1
                                         0 0 0 0 1
                                         0 0 0 0 1
                                         0 0 0 1 0"
        result="mtrx"/>
      <feOffset
        in="morph" dx="5" dy="5"
        result="offset"/>
      <feMerge>
        <feMergeNode in="offset"/>
        <feMergeNode in="mtrx"/>
        <feMergeNode in="SourceGraphic"/>
      </feMerge>
    </filter>
  </defs>
  <rect x="0" y="0" width="200" height="200"
    stroke-width="3" stroke="#fa0" fill="#ffa"/>
  <circle cx="100" cy="100" r="75"
    filter="url(#f3)"
    stroke-width="3" stroke="#0a6" fill="#afc"/>
</svg>
図1

図2

図3

// 選択肢
図1
図2
図3

上から順番に見ていきましょう。

<feMorphology in="SourceAlpha" operator="dilate" radius="3" result="morph"/>

上記では、入力(in)が「SourceAlpha」(元の画像のアルファ値)で、出力(result)が「morph」(という名前)になっています。

「feMorphology」は、形態のフィルターです。属性「operator」が「dilate」なら拡張を行ないます。その際の「radius」(半径、範囲)は「3」になります。

<feColorMatrix in="morph" type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"

次に、上記では、入力(in)が「morph」(形態フィルターで作った画像)で、出力が「matrix」(という名前)になっています。

カラーマトリクスの値として、以下の行列を指定して、真っ白にしています。

// 行列
0 0 0 0 1
0 0 0 0 1
0 0 0 0 1
0 0 0 1 0
<feOffset in="blur" dx="5" dy="5" result="offset"/>

続いて、上記では、入力(in)が「morph」(形態フィルターで作った画像)で、出力が「offset」(という名前)になっています。

「feOffset」は、オフセットのフィルターです。「dx」「dy」で、X軸、Y軸の移動量を指定します。これで、入力画像を、「dx」「dy」分移動した画像が作成されます。


<feMerge>
  <feMergeNode in="offset"/>
  <feMergeNode in="mtrx"/>
  <feMergeNode in="SourceGraphic"/>
</feMerge>

最後に、「<feMerge>」で、「<feMergeNode>」の3つの画像を合成しています。

合成する画像は、入力(in)が「offset」(先ほど、オフセットフィルターで作った画像)、入力(in)が「mtrx」(先ほど、カラーマトリクスフィルターで作った画像)と、入力(in)が「SourceGraphic」(元の画像)になります。

この合成の順番は、「offset」が先で、次に「mtrx」、最後に「SourceGraphic」となります。つまり、アルファ値を膨張させて移動した画像を描画して、アルファ値を膨張させて白くした画像を描画して、元の画像を描画することになります。

そのため、作成される図は、図1となり、1番目の選択肢の「図1」が答えになります。

CodeIQ運営事務局より

柳井さん、ありがとうございました!
現在、柳井さんの最新問題が出題中です。
ぜひ挑戦してみてくださいね!

  • 3
  • このエントリーをはてなブックマークに追加

■関連記事

【コードミステリ】数字に隠されたメッセージ【言語不問】解答と解説... 【コードミステリ】数字に隠されたメッセージ【言語不問】 本問題は、表題のテーマで、簡単なプログラムを書くものです。 喜屋武ちあきさんによるCodeIQ MAGAZINEでのブックレビューに合わせて、『顔貌売人』(文藝春秋)とのコラボ問題として出題されたものです。 それでは以下、問題とその解...
数学の問題をプログラミングで解こう!「ディバイド・アウト」問題解説... 問題のおさらい 自然数 n と素数 p に対し、n の階乗(n!)を p でこれ以上割り切れなくなるまで繰り返し割り、その商をさらに p で割ったときの余りを F(n, p) と定義します。 例えば F(12, 5)=4 です。 12!(=479001600)は 5 で最大 2 回割ることができ...
【息抜き】ファイル名を作ろう【言語不問】解答と解説... 【息抜き】ファイル名を作ろう【言語不問】 本問題は、表題のテーマで、簡単なプログラムを書くものです。 それでは以下、問題とその解答を見ていきましょう。 問題 ファイルをディレクトリ内に作成する際、同じ名前のファイルがあると、末尾に数字を付けるなどして同じ名前にならないようにします。 こうし...
【夏のミステリー】殺人現場のコード 解答と解説... 【夏のミステリー】殺人現場のコード 本問題は、表題のテーマで、簡単なプログラムを書くものです。 それでは以下、問題とその解答を見ていきましょう。 問題 殺人現場にプログラマが倒れていて、途中までプログラムが書かれている。 「続きを書いて欲しい」 これはダイイングメッセージなのか? どう...
数学の問題をプログラミングで解こう!「キャンディ・アンド・チョコレート」問題解説... 問題のおさらい n 個のキャンディをグループに分けます。 グループの最大のキャンディの個数が k 個となるような分け方の数を F(n, k) と定義します。 例えば、F(8, 3)=5 です。このときの分け方を以下に示します。 なお個々のキャンディを区別せずに扱う点に注意してください。 同...
【夏のミステリー】時間制限の密室 解答と解説... 【夏のミステリー】時間制限の密室 本問題は、表題のテーマで、簡単なプログラムを書くものです。 それでは以下、問題とその解答を見ていきましょう。 問題 (なんやかんやあって)命からがら逃げてきた、あなた。 しかし逃げ込んだ部屋にあなたが入った途端、自動でドアはロックされ、しかも10分後にはガ...

今週のPickUPレポート

新着記事

週間ランキング

CodeIQとは

CodeIQ(コードアイキュー)とは、自分の実力を知りたいITエンジニア向けの、実務スキル評価サービスです。

CodeIQご利用にあたって
関連サイト
codeiq

リクルートグループサイトへ