『象印クイズ ヒントでピント』は、テレビ朝日系列局ほかで、1979年3月4日から1994年9月25日まで、毎週日曜 19:30 – 20:00に放送されていたクイズ番組です。前回に続いてクイズで出てきそうなモザイク画像をつくります。元ネタはこんな感じです。
最初にコンストラクタで元画像を渡せばモザイクを生成するクラスを作成します。
1 2 3 4 5 6 7 8 9 |
public class ImageWithMosaic { Bitmap SourceBitmap; public ImageWithMosaic(Bitmap sourceBitmap) { SourceBitmap = sourceBitmap; } } |
モザイクは全体を正方形に分割してその正方形を同じ色で塗りつぶします。どの色で塗りつぶすかはその位置の色を平均したものとします。GetColorメソッドは位置を指定するとその部分の平均の色を計算して返します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
public class ImageWithMosaic { public int PixelSize = 10; Color GetColor(int colum, int row) { List<Color> colors = new List<Color>(); int width = SourceBitmap.Width; int height = SourceBitmap.Height; for (int x = colum * PixelSize; x < (colum + 1) * PixelSize; x++) { for (int y = row * PixelSize; y < (row + 1) * PixelSize; y++) { if (x < width && y < height) colors.Add(SourceBitmap.GetPixel(x, y)); } } if (colors.Count == 0) return Color.White; int r = (int)colors.Average(x => x.R); int g = (int)colors.Average(x => x.G); int b = (int)colors.Average(x => x.B); return Color.FromArgb(r, g, b); } } |
SetColorメソッドはGetColorメソッドで得られた色を新しいBitmapにセットします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public class ImageWithMosaic { void SetColor(Bitmap bitmap, int colum, int row, Color color) { int width = SourceBitmap.Width; int height = SourceBitmap.Height; for (int x = colum * PixelSize; x < (colum + 1) * PixelSize; x++) { for (int y = row * PixelSize; y < (row + 1) * PixelSize; y++) { if (x < width && y < height) bitmap.SetPixel(x, y, color); } } } } |
GetImageWithMosaicメソッドはGetColorメソッドとSetColorメソッドを使って、一辺が引数と同じ長さをもつ正方形で全体を分割してモザイクを生成します。引数が1かそれよりも小さい場合はもとの画像をそのまま返します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
public class ImageWithMosaic { public Bitmap GetImageWithMosaic(int pixelSize) { if (PixelSize <= 1) return SourceBitmap; PixelSize = pixelSize; int width = SourceBitmap.Width; int height = SourceBitmap.Height; Bitmap newBitmap = new Bitmap(width, height); for (int x = 0; x < width / PixelSize + 1; x++) { for (int y = 0; y < height / PixelSize + 1; y++) { Color color = GetColor(x, y); SetColor(newBitmap, x, y, color); } } return newBitmap; } } |
次にForm1クラスにおける処理ですが、タイマーをつかって粗いモザイクから細かいモザイクへと変化させていきます。そしてモザイクを構成する正方形の一辺の長さが1になったらそれ以上の処理は意味を持たないのでタイマーを止めます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
public partial class Form1 : Form { ImageWithMosaic imageWithMosaic; Timer Timer = new Timer(); int PartSize = 30; // モザイクを構成する正方形の一辺の長さ Bitmap BitmapWithMosaic = null; // ImageWithMosaic.GetImageWithMosaicメソッドか返したBitmap public Form1() { InitializeComponent(); Bitmap sourceBitmap = Properties.Resources.neko; imageWithMosaic = new ImageWithMosaic(sourceBitmap); Timer.Interval = 1000; Timer.Tick += Timer_Tick; Timer.Start(); // Formのサイズを周囲に10ピクセルの余白ができる大きさにする this.ClientSize = new Size(600 + 20, 415 + 20); this.BackColor = Color.Black; this.DoubleBuffered = true; } private void Timer_Tick(object sender, EventArgs e) { PartSize--; // モザイクを構成する正方形を毎秒小さくしていく。1になったらタイマーを止める Text = String.Format("PartSize = {0}", PartSize); BitmapWithMosaic = imageWithMosaic.GetImageWithMosaic(PartSize); if (PartSize == 1) Timer.Stop(); Invalidate(); } protected override void OnPaint(PaintEventArgs e) { // BitmapWithMosaicが存在しない場合はなにもしない if (BitmapWithMosaic == null) return; e.Graphics.DrawImage(BitmapWithMosaic, new Rectangle(10, 10, BitmapWithMosaic.Width, BitmapWithMosaic.Height)); base.OnPaint(e); } } |