OpenCVでPhotoshopの「コンテンツに応じた塗りつぶし」のような処理が出来るようなので試してみます。
実行環境構築
プロジェクトの作成
mkdir プロジェクト名
cd プロジェクト名
dotnet new winforms
dotnet add package OpenCvSharp4.Windows
dotnet add package OpenCvSharp4.Extensions
code .
ソースプログラム
namespace InpaintSample;
using OpenCvSharp;
using OpenCvSharp.Extensions;
public partial class Form1 : Form
{
Mat? view = null;
public Form1()
{
InitializeComponent();
Text = "インペイント";
Size = new System.Drawing.Size(850, 800);
var fnt = new Font("MS UI Gothic", 12);
var vb = new Bitmap(800, 600);
using (var g = Graphics.FromImage(vb)) {
g.FillRectangle(Brushes.White, 0, 0, vb.Width, vb.Height);
g.DrawString("こちらにD&D", fnt, Brushes.Green, 0.0f, 0.0f);
}
var ud = new SplitContainer {
Dock = DockStyle.Fill,
Orientation = Orientation.Horizontal, // 上下
Panel1MinSize = 120,
};
var picboxV = new PictureBox {
SizeMode = PictureBoxSizeMode.Zoom,
Dock = DockStyle.Fill,
AllowDrop = true,
Image = vb,
};
var execBtn = new RadioButton {
Text = "フィルターOFF",
Appearance = Appearance.Button,
AutoCheck = false,
Location = new System.Drawing.Point(10, 10),
Size = new System.Drawing.Size(180, 50),
};
var toClip = new Button {
Text = "コピー",
Location = new System.Drawing.Point(200, 10),
Size = new System.Drawing.Size(120, 50),
};
var fromClip = new Button {
Text = "貼り付け",
Location = new System.Drawing.Point(330, 10),
Size = new System.Drawing.Size(120, 50),
};
picboxV.DragEnter += (sender, e) => {
if (e.Data == null) return;
if(!e.Data.GetDataPresent(DataFormats.FileDrop)) return;
e.Effect = DragDropEffects.Copy;
};
picboxV.DragDrop += (sender, e) => {
if (e.Data == null) return;
if(!e.Data.GetDataPresent(DataFormats.FileDrop)) return;
string path = ((string[])e.Data.GetData(DataFormats.FileDrop))[0];
if (view is not null) view.Dispose();
view = Cv2.ImRead(path);
if (picboxV.Image is not null) picboxV.Image.Dispose();
picboxV.Image = BitmapConverter.ToBitmap(view);
execBtn.Checked = false;
};
execBtn.Click += async (sender, e) => {
if (view is null) return;
if (execBtn.Checked == true) {
if (picboxV.Image is not null) picboxV.Image.Dispose();
picboxV.Image = BitmapConverter.ToBitmap(view);
execBtn.Text = "フィルターOff";
execBtn.Checked = false;
} else {
var bitmap = await Task.Run<Bitmap>(()=>{
using (var result = new Mat())
using (var mask = new Mat())
{
Cv2.CvtColor(view, mask, ColorConversionCodes.RGB2GRAY);
for (int y = 0; y < view.Height; y++) {
for (int x = 0; x < view.Width; x++) {
var pic = view.At<Vec3b>(y, x);
if (pic[0] == 255 && pic[1] == 0 && pic[2] == 255) {
mask.Set(y, x, (byte)255);
} else {
mask.Set(y, x, (byte)0);
}
}
}
Cv2.Inpaint(view, mask, result, 0.0, InpaintMethod.Telea);
return BitmapConverter.ToBitmap(result);
}
});
picboxV.Image?.Dispose();
picboxV.Image = bitmap;
execBtn.Text = "フィルターOn";
execBtn.Checked = true;
}
};
toClip.Click += (sender, e) => {
if (picboxV.Image is null) return;
var ms = new MemoryStream();
picboxV.Image.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
Clipboard.SetData("PNG", ms);
};
fromClip.Click += (sender, e) => {
var obj = Clipboard.GetData("PNG");
if (obj == null) return;
var ms = (MemoryStream)obj;
if (ms is null) return;
if (view is not null) view.Dispose();
using(var b = new Bitmap(ms)) {
view = BitmapConverter.ToMat(b);
if (view.Channels() == 4)
Cv2.CvtColor(view, view, ColorConversionCodes.RGBA2RGB);
}
if (picboxV.Image is not null) picboxV.Image.Dispose();
picboxV.Image = BitmapConverter.ToBitmap(view);
execBtn.Checked = false;
};
ud.Panel1.Controls.Add(picboxV);
ud.Panel2.Controls.AddRange(new Control[]{execBtn,toClip,fromClip});
Controls.Add(ud);
}
}
実行
dotnet run
元画像
インペイント処理を行う部分をペイントソフトで紫色(255,0.255)で塗りつぶしておく。(GIMPの場合、塗りつぶしのプロパティ⇒類似色の識別→なめらかにのチェックを外して塗りつぶし。PNG形式など劣化しないファイル形式が望ましい。)
ドラッグアンドドロップ
処理実行
違和感はありますが塗りつぶし処理が行われています。
コメント