画像にエフェクトをかけて遊ぼう — (3)複数のエフェクトを組み合わせる

いろいろなエフェクト

前回はTeshFxのいくつかのエフェクトを紹介した。
今回はそれらのエフェクトを複数組み合わせてあたらしいエフェクトを作る方法について学ぶ。

前提

下記の環境がすでに揃っていることが前提なので、もしまだのものがあればリンクをたどって準備していただきたい。

  • Processingがインストールされていること
      –>まだの場合:Processingのインストール(Windows編、Mac編、Linux編)
  • バージョンの0.0.5以降のTeshFxがインストールされていること
      →まだの場合、または0.0.4かそれよりも古い場合:TeshFxのインストール

チェーンフィルター

複数のフィルターを組み合わせるものをTeshFxではチェーンフィルターという。これは「複数のフィルターをチェーン(鎖)で繋ぐ」という意味だ。
チェーンフィルター自身もまたTeshFxフィルターなので、「複数のフィルターを組み合わせて新しいフィルターを作る」と思っていただきたい。

さて、このチェーンフィルターはTeshFxChainFilterという名前で、複数のフィルターを繋ぐのは次のようにおこなう。

  TeshFxFilterChain chain = new TeshFxFilterChain()  // チェーンフィルターを生成
                              .add(filter1)  // 1番目のフィルターをチェーンフィルターに追加
                              .add(filter2)  // 2番目のフィルターをチェーンフィルターに追加
			…
                              .add(filterN);  // N番目のフィルターをチェーンフィルターに追加

このようにフィルターはいくらでも繋ぐことができる。これを実行するのは他のフィルターと同じように、

		chain.filter(元の画像);

とするだけでよい。繋がれたフィルターは追加された順に実行される。

減色フィルター

ここでチェーンフィルターを使って複数のフィルターを繋ぐ例に入る前にもう一つフィルターを紹介する。
「TeshFxReduceColorFilter(減色フィルター)」だ。
このフィルターを使うと画像の色数を落とすことができる。写真画像の場合、一般的には色数が多いほどより美しく自然な感じになるものだが、色数を落とすことで様々なエフェクトをかけることができる。また、ファイルに保存したときのファイルサイズを減らすこともできる。

この減色フィルターの使用例は下記のとおり。

PImage image; // 変数 imageを宣言

import teshfx.filter.*; // TeshFxFilterを使うことを宣言


void setup() {
  size(480, 640); // ウィンドウサイズを480x640に指定
  //ネットからURLで指定した画像をダウンロードして”image”という変数に代入する
  image = loadImage("https://coding4.art/wp-content/uploads/2022/11/teshnakamura.jpg"); 

  TeshFxFilter reduceFilter = new TeshFxReduceColorFilter() // TeshFxReduceColorFilterを生成
               .colors(4)  // colorsを4に設定 
               .init();    // パラメータを設定した際の最後の処理
  

  // imageに減色フィルターをかける
  image = reduceFilter.filter(image);
}

void draw() {
  image(image, 0, 0); // “image”を表示する
}

void dispose() {
  save("chained.png"); // エフェクトをかけた画像を保存
}

これを実行すると下記の画像が表示される。

減色フィルター

元の写真と比べるとイラストっぽくなった。

12行目でcolorsというパラメータを4に設定しているが、これは「色数を4色にする」という意味ではない。コンピュータで色を作る場合、RGB(Red Green Blue)の3原色で表す方法があるが、Processingではデフォルトではこの赤、緑、青をそれぞれ256段階で表している。つまり256の3乗で16,777,216ということだ。この原色フィルターのパラメータcolorsは赤、緑、青のそれぞれを何色にするか、という値で、ここで4と設定した場合、4の3乗で64色ということになる。つまり、16,777,216色だったものが64色まで減色された、ということだ。

赤、緑、青の色数を別々の値にしたい場合は下記のように書くこともできる。

.colors(赤の色数, 緑の色数, 青の色数)

言い換えると、先程の.colors(4)は.colors(4, 4, 4)と同じ意味である、ということだ。

チェーンフィルターを使った例

さて、チェーンフィルターに戻ろう。
ここでは先程の減色フィルターを使って、「減色–>エッジ」というエフェクトをするフィルターを作る。

PImage image; // 変数 imageを宣言

import teshfx.filter.*; // TeshFxFilterを使うことを宣言


void setup() {
  size(480, 640); // ウィンドウサイズを480x640に指定
  //ネットからURLで指定した画像をダウンロードして”image”という変数に代入する
  image = loadImage("https://coding4.art/wp-content/uploads/2022/11/teshnakamura.jpg"); 

  TeshFxFilter reduceFilter = new TeshFxReduceColorFilter() // TeshFxReduceColorFilterを生成
               .colors(4)  // colorsを4に設定 
               .init();    // パラメータを設定した際の最後の処理
  TeshFxFilter edgeFilter = new TeshFxEdgeFilter(); // TeshFxEdgeFilterを生成
  
  // チェーンフィルターを生成
  TeshFxFilterChain chain = new TeshFxFilterChain()
                              .add(reduceFilter)  // TeshFxReduceColorFilterをチェーンフィルターに追加
                              .add(edgeFilter); // TeshFxEdgeFilterをチェーンフィルターに追加

  // imageにチェーンフィルターをかける
  image = chain.filter(image);
}

void draw() {
  image(image, 0, 0); // “image”を表示する
}

void dispose() {
  save("chained.png"); // エフェクトをかけた画像を保存
}

これを実行すると下記の画像が表示される。
前回のエッジフィルターだけのときよりもノイズが消されてより線画らしくなっている。

コードの解説は下記のとおり。

11-14行目
ここではこれから繋ぐフィルター、減色フィルター、エッジフィルターを生成している。

17-19行目
ここでチェーンフィルターを生成し、先程生成した2つのフィルターを繋いでいる。

20行目
imageにチェーンフィルターをかけている。

繋ぐ順番を変えてみる

18行と19行をつぎのように入れ替えてみる。

                              .add(edgeFilter) // TeshFxEdgeFilterをチェーンフィルターに追加
                             .add(reduceFilter);  // TeshFxReduceColorFilterをチェーンフィルターに追加

先程は「画像を減色して、その縁をとって線画にする」というエフェクトだったが、上記のようにチェーンフィルターに追加する順番を入れ替えると「画像の縁をとって線画にし、減色する」ということになる。
これを実行させると下記のような画像が表示される。

フィルタをかける順番を入れ替えるだけで出来上がる画像が変わっている。

3つ以上のフィルターを繋ぐ

先程のコードでは2つのフィルターを繋いで新しいフィルターを作ったが、繋ぐフィルターの数には制限がない。もちろんフィルターをたくさんつけると処理に時間がかかるようになるが。
今度は例として先程の2つのフィルターを繋いだ例の前にぼかしフィルターを入れて、「ぼかし–>減色–>エッジ」という3つのフィルターを繋いだ新しいフィルターを作る。コードは下記の通り。

PImage image; // 変数 imageを宣言

import teshfx.filter.*; // TeshFxFilterを使うことを宣言


void setup() {
  size(480, 640); // ウィンドウサイズを480x640に指定
  //ネットからURLで指定した画像をダウンロードして”image”という変数に代入する
  image = loadImage("https://coding4.art/wp-content/uploads/2022/11/teshnakamura.jpg"); 

  TeshFxFilter blurFilter = new TeshFxBlurFilter()  // TeshFxBlurFilterを生成
           .radius(5)  // radiusを5に設定
           .init();
  TeshFxFilter edgeFilter = new TeshFxEdgeFilter();   // TeshFxEdgeFilterを生成
  TeshFxFilter reduceFilter = new TeshFxReduceColorFilter() // TeshFxReduceColorFilterを生成
               .colors(4)  // colorsを4に設定 
               .init();    // パラメータを設定した際の最後の処理
  
  // チェーンフィルターを生成
  TeshFxFilterChain chain = new TeshFxFilterChain()
                                 .add(blurFilter)
                                 .add(reduceFilter)  // TeshFxReduceColorFilterをチェーンフィルターに追加
                                 .add(edgeFilter); // TeshFxEdgeFilterをチェーンフィルターに追加

  // imageにチェーンフィルターをかける
  image = chain.filter(image);
}

void draw() {
  image(image, 0, 0); // “image”を表示する
}

void dispose() {
  save("chained.png"); // エフェクトをかけた画像を保存
}

先程のコードと比べると変更点はフィルターを生成するところとそれらをチェーンフィルターに追加するところだけだ。
これを実行すると下記の画像が表示される。

「減色–>エッジ」の前にぼかしフィルターを入れることでノイズが減って線画というよりもかなり略して書いた絵のようになった。

オーバーレイフィルターと透明化フィルター

オーバーレイフィルター

ここで元の画像に上記の線画を重ねて表示したい。
2つの画像を重ねて表示するためのフィルターは「TeshFxOverlayFilter(オーバーレイフィルター)」だ。
まず、このオーバーレイフィルターの使い方の例として下記のコードを見ていただきたい。

PImage image; // 変数 imageを宣言

import teshfx.filter.*; // TeshFxFilterを使うことを宣言


void setup() {
  size(480, 640); // ウィンドウサイズを480x640に指定
  //ネットからURLで指定した画像をダウンロードして”image”という変数に代入する
  image = loadImage("https://coding4.art/wp-content/uploads/2022/11/teshnakamura.jpg"); 

  //ネットからもう一つの画像をダウンロードして”image2”という変数に代入する
  PImage image2 = loadImage("https://coding4.art/wp-content/uploads/2022/11/name.png"); 

   // TeshOverlayFilterを生成  
  TeshFxFilter overlay = new TeshFxOverlayFilter(image);
  
  // imageにlineをオーバーレイする
  image = overlay.filter(image2);
}

void draw() {
  image(image, 0, 0); // “image”を表示する
}

void dispose() {
  save("chained.png"); 
}

これは今までのイケメン画像に加えてもう一つ別の画像もダウンロードし、それをイケメン画像にオーバーレイしている例である。

実行してみると。。。あれ?イケメンが表示されない。
この上からかぶせているimage2は透明な部分がないため、イケメン画像をすべて上書きしたようになっている。

そこで、12行目のURLを書き換える。

  PImage image2 = loadImage("https://coding4.art/wp-content/uploads/2022/11/name2.png"); 

このname2.pngというファイルは、先程の画像の背景を透明にしたものだ。
これを実行すると、

イケメン画像に名前がオーバーレイされている。

このコードの15行目でTeshFxOverlayFilterが生成されている。オーバーレイフィルターは生成の際にベースの画像(一番下になる画像)を指定する必要がある。ここではimageだ。

そして18行目でフィルターをかけるが、このとき上に重ねる画像を指定する。

透明化フィルター

上記の文字がちゃんとオーバーレイされたのは文字の画像(image2)の背景を手動で透明にしたのだが、これをコードでやってみよう。

先程作った線画をイケメン画像にオーバーレイしたいのだが、線画も背景が白なので、うまくオーバーレイできない。そこで特定の色を透明化するフィルターTeshFxTransparentFilter(透明化フィルター)を紹介する。

TeshFxTransparentFilterの生成方法は下記のとおり。

  TeshFxFilter <変数名>  = new TeshFxTransparentFilter()
	.backgroundcolor(<背景色のRGB>)
              .torelance(<許容値>)
              .init();

パラメータbackgroundcolorは背景色をRGBで表したもの。デフォルトは白(255, 255, 255)なので、何も指定しない場合は白を背景として透明化する。torelanceというパラメータは背景色を判断する際の許容誤差だ。背景をある色と指定した場合でも、写真などでは微妙な誤差が発生するため、指定した色に完全に一致するところと一致しないところが出てくることがあるので、ある程度の誤差を許容する必要がある。このパラメータはデフォルトでは10となっているので、もし透明化がうまく行かない場合はこの値を調整すれば良い。

ではオーバーレイフィルターと透明化フィルターを使って、先程の線画をイケメン画像にオーバーレイしよう。コードは下記の通り。

PImage image; // 変数 imageを宣言

import teshfx.filter.*; // TeshFxFilterを使うことを宣言


void setup() {
  size(480, 640); // ウィンドウサイズを480x640に指定
  //ネットからURLで指定した画像をダウンロードして”image”という変数に代入する
  image = loadImage("https://coding4.art/wp-content/uploads/2022/11/teshnakamura.jpg"); 

  TeshFxFilter blurFilter = new TeshFxBlurFilter()  // TeshFxBlurFilterを生成
           .radius(5)  // radiusを5に設定
           .init();
  TeshFxFilter edgeFilter = new TeshFxEdgeFilter();   // TeshFxEdgeFilterを生成
  TeshFxFilter transparentFilter  = new TeshFxTransparentFilter()   // TeshFxTransparentFilterを生成
              .torelance(60)  // torelanceを60に設定
              .init();
   // TeshChainFilterを生成
  TeshFxFilterChain chain = new TeshFxFilterChain()
                              .add(blurFilter)  // TeshFxBlurFilterをチェーンフィルターに追加
                              .add(edgeFilter)  // TeshFxEdgeFilterをチェーンフィルターに追加
                              .add(transparentFilter);  // TeshFxTransparentFilterをチェーンフィルターに追加
  // imageにチェーンフィルターをかけたものをlineに保存する
  PImage line = chain.filter(image);
  
   // TeshOverlayFilterを生成  
  TeshFxFilter overlay = new TeshFxOverlayFilter(image);
  
  // imageにlineをオーバーレイする
  image = overlay.filter(line);
}

void draw() {
  image(image, 0, 0); // “image”を表示する
}

void dispose() {
  save("chained.png"); 
}

実行するといい感じに写真が縁取りされているようなエフェクトがかかっている。

19-21行目で透明化フィルターを生成し、そのtorelance値を60に設定している。

フィルターをチェーンフィルターに追加する24-27行目は先程の線画と全く同じだが、28行目でそれを透明化フィルターを追加している。

30行目でこのチェーンフィルターをかけた画像をlineという別の変数に代入している。

そして33行目で元のイケメン画像をベースにしたオーバーレイフィルターを生成し、36行目でこのベース画像に先程取ったlineを重ね合わせている。

TeshFxTransparentFilterはフィルターをかける(filter関数を呼ぶ)ごとに、内部で重ねた結果を保持しているので、異なる画像を次々とオーバーレイすることで複数の画像をオーバーレイすることができる。

この例では38行目でイケメン画像に線画をオーバーレイし、41行目で線画がオーバーレイされた画像にさらに文字をオーバーレイしている。

PImage image; // 変数 imageを宣言

import teshfx.filter.*; // TeshFxFilterを使うことを宣言


void setup() {
  size(480, 640); // ウィンドウサイズを480x640に指定
  //ネットからURLで指定した画像をダウンロードして”image”という変数に代入する
  image = loadImage("https://coding4.art/wp-content/uploads/2022/11/teshnakamura.jpg"); 

  //ネットからもう一つの名前の画像をダウンロードして”name”という変数に代入する
  PImage name = loadImage("https://coding4.art/wp-content/uploads/2022/11/name2.png"); 

  TeshFxFilter blurFilter = new TeshFxBlurFilter()  // TeshFxBlurFilterを生成
           .radius(5)  // radiusを5に設定
           .init();
  TeshFxFilter edgeFilter = new TeshFxEdgeFilter();   // TeshFxEdgeFilterを生成
  TeshFxFilter reduceFilter = new TeshFxReduceColorFilter() // TeshFxReduceColorFilterを生成
               .colors(4)  // colorsを4に設定 
               .init();    // パラメータを設定した際の最後の処理

  TeshFxFilter transparentFilter  = new TeshFxTransparentFilter()   // TeshFxTransparentFilterを生成
              .torelance(60)  // torelanceを60に設定
              .init();
   // TeshChainFilterを生成
  TeshFxFilterChain chain = new TeshFxFilterChain()
                              .add(blurFilter)
                              .add(reduceFilter)  // TeshFxBlurFilterをチェーンフィルターに追加
                              .add(edgeFilter)  // TeshFxEdgeFilterをチェーンフィルターに追加
                              .add(transparentFilter);  // TeshFxTransparentFilterをチェーンフィルターに追加
  // imageにチェーンフィルターをかけたものをlineに保存する
  PImage line = chain.filter(image);
  
   // TeshOverlayFilterを生成  
  TeshFxFilter overlay = new TeshFxOverlayFilter(image);
  
  // imageにlineをオーバーレイする
  image = overlay.filter(line);
  
  // imageにnameをオーバーレイする
  image = overlay.filter(name);  
}

void draw() {
  image(image, 0, 0); // “image”を表示する
}

void dispose() {
  save("chained.png"); 
}

これを実行すると、線画と文字の両方がオーバーレイされている。

まとめ

  • 複数のフィルターを繋いで使うためにチェーンフィルターを使う。
  • チェーンフィルターはそれ自体もフィルターなので他のフィルターと同じように使うことができる。
  • 減色フィルターは写真などの色数を減らすエフェクトをかけるフィルターである。
  • オーバーレイフィルターはある画像にもう一つの画像をオーバーレイするフィルターである。
  • 透明化フィルターは指定した色を透明化するフィルターで、オーバーレイフィルターと合わせて使うことでレイヤーを重ねるようなエフェクトを作ることができる。
  • 複数のフィルターを繋いだり、色々と工夫することで独特の効果を実現することができる。
タイトルとURLをコピーしました