C#(GDI+) C#(others)
Delphi(Graphics) Delphi(others)
BBS Blog
Link Misc. Index
C#(GDI+) : Contour
C#(GDI+) : Contour
R,
G,
B をそれぞれ一次独立な直交座標とみたてて、
RGB 空間のなかでの「色の距離」をはかって、輪郭を描画する
Contour() をつくった。
photo by
0 W8ing
Contour() では
HistoStretch() の有無を設定できる。さらに
b24bit が
fasle のときは、返される画像はグレースケールであるが、
b24bit が
true のときは
PixelFormat.Format24bppRgb のフォーマットで返す。
全コードをしめす。
最新の
ImageUtils.cs は
ここからダウンロードできる。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Imaging;
using ImageUtils;
namespace Contour
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public static bool Contour(ref Bitmap bmp, bool bStretch, bool b24bit)
{
if (bmp.PixelFormat != PixelFormat.Format24bppRgb)
return false;
int w = bmp.Width;
int h = bmp.Height;
Rectangle rct = new Rectangle(0, 0, w - 1, h - 1);
double[] dis = new double[4];
int[] ix = new int[4];
int[] iy = new int[4];
double max;
double dd = 1.732d;
byte r, g, b;
Bitmap tmp = new Bitmap(w, h, PixelFormat.Format8bppIndexed);
ImgUtils.SetGrayPalette(tmp);
BmpProc24 src = new BmpProc24(bmp);
BmpProc8 dst = new BmpProc8(tmp);
for (int y = 0; y < h; y++)
for (int x = 0; x < w; x++)
{
src.SetXY(x, y);
r = src.R; g = src.G; b = src.B;
ix[0] = x + 1; iy[0] = y - 1; // upper-right
ix[1] = x + 1; iy[1] = y; // right
ix[2] = x + 1; iy[2] = y + 1; // lower-right
ix[3] = x; iy[3] = y + 1; // lower
for (int i = 0; i < 4; i++)
if (rct.Contains(ix[i], iy[i]))
{
src.SetXY(ix[i], iy[i]);
dis[i] = (src.R - r) * (src.R - r) +
(src.G - g) * (src.G - g) +
(src.B - b) * (src.B - b);
}
else
dis[i] = 0d;
max = 0;
for (int i = 0; i < 4; i++)
if (dis[i] > max) max = dis[i];
dst[x, y] = ImgUtils.AdjustByte(255d - Math.Sqrt(max) / dd);
}
ImgUtils.CallDispose(dst, src);
if (bStretch) ImgUtils.HistoStretch(ref tmp);
if (b24bit)
{
Graphics gr = Graphics.FromImage(bmp);
gr.DrawImageUnscaled(tmp, 0, 0);
gr.Dispose();
tmp.Dispose();
}
else
{
bmp.Dispose();
bmp = tmp;
}
return true;
}
private void button1_Click(object sender, EventArgs e)
{
Bitmap bmp = new Bitmap(@"C:\Home\img\camellia.png");
int w = bmp.Width;
int h = bmp.Height;
Graphics g = this.CreateGraphics();
g.DrawImageUnscaled(bmp, 5, 5);
Bitmap tmp = bmp.Clone() as Bitmap;
if (Contour(ref tmp, false, false))
{
g.DrawImageUnscaled(tmp, 5, h + 10);
Clipboard.SetImage(tmp);
}
tmp.Dispose();
tmp = bmp.Clone() as Bitmap;
if (Contour(ref tmp, true, false))
g.DrawImageUnscaled(tmp, w + 10, h + 10);
tmp.Dispose();
g.Dispose();
bmp.Dispose();
}
}
}
まず、カレントピクセルに対して、その右上、右、右下、下のピクセルの色の距離の二乗を計算して、配列に入れる。
double[] dis = new double[4];
int[] ix = new int[4];
int[] iy = new int[4];
...
src.SetXY(x, y);
r = src.R; g = src.G; b = src.B;
ix[0] = x + 1; iy[0] = y - 1; // upper-right
ix[1] = x + 1; iy[1] = y; // right
ix[2] = x + 1; iy[2] = y + 1; // lower-right
ix[3] = x; iy[3] = y + 1; // lower
for (int i = 0; i < 4; i++)
if (rct.Contains(ix[i], iy[i]))
{
src.SetXY(ix[i], iy[i]);
dis[i] = (src.R - r) * (src.R - r) +
(src.G - g) * (src.G - g) +
(src.B - b) * (src.B - b);
}
else
dis[i] = 0d;
そして、その最大値をもとめ、平方根を
255 に規格化してから、
255 から引いた値をカレントの色とする。
max = 0;
for (int i = 0; i < 4; i++)
if (dis[i] > max) max = dis[i];
dst[x, y] = ImgUtils.AdjustByte(255d - Math.Sqrt(max) / dd);
以上を全ピクセルについて行った後、
b24bit に応じた処理をして終わり。
if (bStretch) ImgUtils.HistoStretch(ref tmp);
if (b24bit)
{
Graphics gr = Graphics.FromImage(bmp);
gr.DrawImageUnscaled(tmp, 0, 0);
gr.Dispose();
tmp.Dispose();
}
else
{
bmp.Dispose();
bmp = tmp;
}
return true;
このフィルタは、
KuwaharaAlpha() と組み合わせるとおもしろい。
を
KuwaharaAlpha() block = 6 では、
となり、なかなか雰囲気がある。
■ 参考
対応するブログ記事
© Copyright by Junki 2005.9 -