画像処理アプリに新しい機能を追加。
— プログラミング素人 (@s51517765) 2020年8月9日
画像にぼかしを入れられるようにした。 pic.twitter.com/SqEwAF8oJS
ブログにスクリーンショットを載せるときに、映り込ませたくないものがあるときに一部分にぼかしを入れるための機能を作りました。
C#で画像処理ソフト、これでとりあえず入れ込みたい機能はすべて盛り込んだので完成です。
ぼかしのアルゴリズムは画質の向上のために数々考案されていますが、もっとも簡単にRGBの色要素を範囲内で平均化するという方法をとりました。
選択範囲をstartPoint
からendPoint
の対角線で指定される長方形とし、ぼかしのサイズをblur_size
すると、各RGBの平均は
for (int y1 = 0; y1 < blur_size; y1++) { for (int x1 = 0; x1 < blur_size; x1++) { red += canvas.GetPixel(Math.Min(startPoint.X, endPoint.X) + x + x1, Math.Min(startPoint.Y, endPoint.Y) + y + y1).R; green += canvas.GetPixel(Math.Min(startPoint.X, endPoint.X) + x + x1, Math.Min(startPoint.Y, endPoint.Y) + y + y1).G; blue += canvas.GetPixel(Math.Min(startPoint.X, endPoint.X) + x + x1, Math.Min(startPoint.Y, endPoint.Y) + y + y1).B; } } red /= (int)Math.Pow(blur_size, 2); green /= (int)Math.Pow(blur_size, 2); blue /= (int)Math.Pow(blur_size, 2);
のようになります。
このように算出したRGBで一つの範囲を塗りつぶします。
SolidBrush brush = new SolidBrush(Color.FromArgb(100, red, green, blue)); brush.Color = Color.FromArgb(red, green, blue); g.FillRectangle(brush, Math.Min(startPoint.X, endPoint.X) + x, Math.Min(startPoint.Y, endPoint.Y) + y, blur_size, blur_size);
このほかに考慮すべきは、startPoint
とendPoint
の位置関係で、左上から右下に向けて選択されるとは限らないので、左上の点はMath.Min(startPoint.X, endPoint.X) , Math.Min(startPoint.Y, endPoint.Y)
のように選択します。
また、選択範囲がキャンバスの外に出てしまうと配列外参照の例外が発生してしまうので、
if (endPoint.X > FinalPictureWidth) endPoint.X = FinalPictureWidth; else if (endPoint.X < 0) endPoint.X = 0;
のように、キャンバスの範囲内に修正します。ここで、開始点はキャンバスの中でないとイベントが発生しないのでノーチェックでOKです。
private void pictureBox1_MouseUp(object sender, MouseEventArgs e) { if (FlagMask == 2) { //Lineを消す if (backupImage != null) g.DrawImage(backupImage, 0, 0); //ImageオブジェクトのGraphicsオブジェクトを作成する g = Graphics.FromImage(canvas); int blur_size = (int)numericUpDownBlurSize.Value; if (endPoint.X > FinalPictureWidth) endPoint.X = FinalPictureWidth; else if (endPoint.X < 0) endPoint.X = 0; if (endPoint.Y > FinalPictureHeight) endPoint.Y = FinalPictureHeight; else if (endPoint.Y < 0) endPoint.Y = 0; int size_x = Math.Abs(startPoint.X - endPoint.X); int size_y = Math.Abs(startPoint.Y - endPoint.Y); for (int x = 0; x < size_x - blur_size; x += blur_size) { for (int y = 0; y < size_y - blur_size; y += blur_size) { int red = 0; int green = 0; int blue = 0; for (int y1 = 0; y1 < blur_size; y1++) { for (int x1 = 0; x1 < blur_size; x1++) { red += canvas.GetPixel(Math.Min(startPoint.X, endPoint.X) + x, Math.Min(startPoint.Y, endPoint.Y) + y).R; green += canvas.GetPixel(Math.Min(startPoint.X, endPoint.X) + x, Math.Min(startPoint.Y, endPoint.Y) + y).G; blue += canvas.GetPixel(Math.Min(startPoint.X, endPoint.X) + x, Math.Min(startPoint.Y, endPoint.Y) + y).B; } } red /= (int)Math.Pow(blur_size, 2); green /= (int)Math.Pow(blur_size, 2); blue /= (int)Math.Pow(blur_size, 2); SolidBrush brush = new SolidBrush(Color.FromArgb(100, red, green, blue)); brush.Color = Color.FromArgb(red, green, blue); g.FillRectangle(brush, Math.Min(startPoint.X, endPoint.X) + x, Math.Min(startPoint.Y, endPoint.Y) + y, blur_size, blur_size); } } pictureBox1.Image = canvas; } }
関連記事
s51517765.hatenadiary.jps51517765.hatenadiary.jp
s51517765.hatenadiary.jp