2016年1月20日水曜日

画像を油絵風に変換する[C#]

 機能はメインのPCのOS(Windows10)が起動しなくなった。まぁ調べたところOSが悪いというよりもう寿命だったみたい。CPUが熱で落ちて運悪く重要なファイルが破損したようです。

 今は再インストールをしている最中です(´Д`)ハァ…。

 愚痴はこのへんにして,今日は画像を油絵風に変換するプログラムを作成しました。

1.アルゴリズム


 比較的簡単な方法です。

 まず元の画像からランダムに一個点を選びます。


 次にその点の色を取り出します。ここでは赤とします。次にその点の周辺にその色の円を書きます。この時ちょっと透明度を入れるといいです。


 まぁこんな感じ。今手作業で適当にやったから辺だけど,本当はもう少しいい感じになる。これを繰り返すとこんな感じになる。

 半透明の円が組み合わさって元の色を作る。他の色との境界部分は混ざり合うという算段です。これが本当に油絵風と言っていいのかは読者様の感性にお任せします。

2.ソースコード

ソースコードにするとこんな感じ。
/**
 *  2015/10/19
 *  画像を油絵風に変換するプログラム
 */

using System;
using System.Drawing;

class Program
{
 // 一辺をどのぐらい分割するか
 // この値を大きくすると精細な画像になる
 const int N = 128;
 
 static void Main()
 {
  Console.WriteLine("a.jpgという画像をを読み込みます");
  
  var img = new Bitmap("a.jpg");
  
  Console.WriteLine("画像を変換し,b.jpgという名前で保存します");
  
  OilPainting(img).Save("b.jpg");
  
  Console.WriteLine("保存が完了しました");
 }
 
 // 油絵っぽい画像に変換するプログラム
 static Bitmap OilPainting(Bitmap src)
 {
  // 描画用のBitmapクラス
  var img = new Bitmap(src);
  // 長辺の長さを出す
  var min = Math.Min(img.Width,img.Height);
  // 円の半径を計算する
  var r = min / N;
  // 乱数生成用クラス
  var rand = new Random();
  // 打点回数(絵全体を覆える回数にしなければならない)
  var count = 6*img.Width * img.Height / (r*r);
  // 描画するのに必要なGraphicsクラス
  var g = Graphics.FromImage(img);
  
  for(int i = 0 ; i < count ; i++ ) 
  {
   // ランダムに点を決める
   var x = rand.Next(src.Width);
   var y = rand.Next(src.Height);
   // 色を取り出す。この時透明度を入れておくといい感じになる
   var color = Color.FromArgb(128,src.GetPixel(x,y));
   // 描画に必要なSolidBrushクラスを先ほど作成した色からつくる
   var brush = new SolidBrush(color);
   
   // 円の描画
   // 円の中心が(x,y)に来るように調整してある
   g.FillEllipse(brush,x-r,y-r,2*r,2*r);
  }
  
  // 変換後の画像を返す
  return img;
 }
}

 「ぱくたそ」さんから借りてきた画像を変換してみた。


 もう一度言いますがこれが本当に油絵風と言っていいのかは読者様の感性にお任せします。

0 件のコメント:

コメントを投稿