using System.Diagnostics;
using System;
using System.Windows;
using Reactive.Bindings;
using System.ComponentModel;
using System.Linq;
using System.Reactive.Linq;
using System.Windows.Media.Imaging;
using OpenCvSharp;
using OpenCvSharp.WpfExtensions;
using System.Threading.Tasks;
using System.Windows.Media;
using System.Collections.Generic;
namespace WpfSample15OpenCVFilter
{
public class MainWindowViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public ReactiveCommand<DragEventArgs> PreviewDropCommand { get; } = new ReactiveCommand<DragEventArgs>();
// オリジナル画像のOpenCVオブジェクト
private Mat _orginalMat;
// オリジナル画像の表示用
public ReactiveProperty<WriteableBitmap> OriginalImage { get; private set;} = new ReactiveProperty<WriteableBitmap>();
// フィルター処理可能フラグ
public ReactiveProperty<bool> FilterEnabled { get; private set;} = new ReactiveProperty<bool>(false);
// ぼかし処理の繰り返し回数
public ReactiveProperty<int> BlurNumberOfTimes { get; private set;} = new ReactiveProperty<int>(6);
// ノンローカルミーンフィルタ
public ReactiveProperty<int> NonLocalMeanH { get; private set;} = new ReactiveProperty<int>(12);
// ズーム倍率
public ReactiveProperty<int> ZoomScale { get; private set;} = new ReactiveProperty<int>(1);
// 加工画像のOpenCVオブジェクト
private Mat _modifiedMat;
// 加工画像の表示用
public ReactiveProperty<WriteableBitmap> ModifiedImage { get; private set;} = new ReactiveProperty<WriteableBitmap>();
// フィルター処理
public ReactiveCommand FilterCommand { get; } = new ReactiveCommand();
// クリア処理
public ReactiveCommand ClearCommand { get; } = new ReactiveCommand();
// ラプラシアンフィルタksize
public ReactiveProperty<int> LaplacianKsize { get; private set;} = new ReactiveProperty<int>(1);
// アンシャープマスキングフィルタK
public ReactiveProperty<int> UnsharpMaskingK { get; private set;} = new ReactiveProperty<int>(15);
// 画像の保存処理
public ReactiveCommand SaveCommand { get; } = new ReactiveCommand();
// オリジナル画像ファイルのパス
private string _originalImageFilePath = "";
// ロード時の処理
public ReactiveCommand LoadedCommand { get; } = new ReactiveCommand();
// クローズ時の処理
public ReactiveCommand ClosingCommand { get; } = new ReactiveCommand();
private WriteableBitmap LoadPicture(string path)
{
if (_orginalMat != null) _orginalMat.Dispose();
_orginalMat = new Mat(path, ImreadModes.Grayscale);
var bitmapSource = (WriteableBitmap)BitmapSourceConverter.ToBitmapSource(_orginalMat);
bitmapSource.Freeze();
return bitmapSource;
//OriginalImage.Value = bitmapSource;
}
protected virtual void OnPropertyChanged(string name)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
// 加工画像の初期化
private void initializeModifiedImage()
{
if (_modifiedMat != null) _modifiedMat.Dispose();
_modifiedMat = null;
ModifiedImage.Value = null;
}
// 画像の保存
private string SavePicture()
{
// 保存用のパス生成
var dir = System.Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
dir = System.IO.Path.Combine(dir, System.DateTime.Now.ToString("yyyyMMdd"));
if (System.IO.Directory.Exists(dir) == false)
{
System.IO.Directory.CreateDirectory(dir);
}
var f = System.IO.Path.GetFileNameWithoutExtension(_originalImageFilePath);
var path = System.IO.Path.Combine(dir, (f + ".png"));
// 保存処理
using (System.IO.FileStream stream = new System.IO.FileStream(path, System.IO.FileMode.Create))
{
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(ModifiedImage.Value));
encoder.Save(stream);
}
return path;
}
// フィルター処理
private WriteableBitmap filters()
{
double[,] kernel = { { 0.0, 1.0/16.0, 0.0},
{ 1.0/16.0, 12.0/16.0, 1.0/16.0},
{ 0.0, 1.0/16.0, 0.0},
};
_modifiedMat = _orginalMat.Clone();
// ぼかし処理
for(int x=0; x<BlurNumberOfTimes.Value; ++x)
{
Cv2.Filter2D(_modifiedMat, _modifiedMat, -1, InputArray.Create(kernel));
}
// ラプラシアンフィルタ
Mat edge = _modifiedMat.Clone();
// 奇数の場合のみ処理
if (LaplacianKsize.Value % 2 == 1)
{
Cv2.Laplacian(_modifiedMat, edge, MatType.CV_8UC1, LaplacianKsize.Value);
// ノンローカルミーンフィルタ
Cv2.FastNlMeansDenoising(_modifiedMat, _modifiedMat, (float)NonLocalMeanH.Value);
/*
Cv2.Laplacian(_modifiedMat, edge, MatType.CV_64FC1, LaplacianKsize.Value);
// 8bitに変換
edge = edge * 255;
edge.ConvertTo(edge, MatType.CV_8UC1);
*/
// 減算
_modifiedMat = _modifiedMat - edge;
// ノンローカルミーンフィルタ
Cv2.FastNlMeansDenoising(_modifiedMat, _modifiedMat, (float)NonLocalMeanH.Value);
}
else
{
// ノンローカルミーンフィルタ
Cv2.FastNlMeansDenoising(_modifiedMat, _modifiedMat, (float)NonLocalMeanH.Value);
}
// アンシャープマスキングフィルタ
double k = (double)UnsharpMaskingK.Value / 10.0;
double[,] unsharpKernel = { { -k/9.0, -k/9.0, -k/9.0},
{ -k/9.0, 1.0+8.0*k/9.0, -k/9.0},
{ -k/9.0, -k/9.0, -k/9.0},
};
if (UnsharpMaskingK.Value > 0)
{
Cv2.Filter2D(_modifiedMat, _modifiedMat, -1, InputArray.Create(unsharpKernel));
}
// Mat => WritableBitmap 変換
//var b = (WriteableBitmap)BitmapSourceConverter.ToBitmapSource(_modifiedMat);
var b = WriteableBitmapConverter.ToWriteableBitmap(_modifiedMat);
b.Freeze();
return b;
}
private string getSettingJsonPath()
{
var path = System.Reflection.Assembly.GetEntryAssembly().Location;
var dir = System.IO.Path.GetDirectoryName(path);
var settingJsonPath = System.IO.Path.Combine(dir, "setting.json");
return settingJsonPath;
}
public MainWindowViewModel()
{
PropertyChanged += (o, e) => {};
// ドラッグアンドドロップ
PreviewDropCommand.Subscribe(async e => {
if (e.Data.GetDataPresent(DataFormats.FileDrop) == false) return;
var path = ((string[])e.Data.GetData(DataFormats.FileDrop))[0];
if (System.IO.File.Exists(path) == false) return;
var ext = System.IO.Path.GetExtension(path).ToUpper();
var validExtensions = new List<string> {".PNG", ".JPEG", ".JPG", ".BMP"};
if (validExtensions.Contains(ext) == false) return;
FilterEnabled.Value = false;
var b = await Task.Run(() => LoadPicture(path));
_originalImageFilePath = path;
OriginalImage.Value = b;
FilterEnabled.Value = true;
});
// フィルター処理
FilterCommand.Subscribe(async _ => {
// ボタン類の無効化
FilterEnabled.Value = false;
initializeModifiedImage();
// フィルター処理
var b = await Task.Run(() => filters());
ModifiedImage.Value = b;
// ボタン類の有効化
FilterEnabled.Value = true;
});
// クリア処理
ClearCommand.Subscribe(_=>{
initializeModifiedImage();
});
// 画像の保存処理
SaveCommand.Subscribe(async _=>{
if (_originalImageFilePath == "") return;
if (ModifiedImage.Value == null) return;
// ボタン類の無効化
FilterEnabled.Value = false;
var s = await Task.Run(() => SavePicture());
// ボタン類の有効化
FilterEnabled.Value = true;
});
// ロード時の処理
LoadedCommand.Subscribe(_ => {
var settingJsonPath = getSettingJsonPath();
if (System.IO.File.Exists(settingJsonPath) == false) return;
string jsonStr = "";
var encoding = System.Text.Encoding.GetEncoding("utf-8");
using(var reader = new System.IO.StreamReader(settingJsonPath, encoding))
{
jsonStr = reader.ReadToEnd();
}
var settingInfo = System.Text.Json.JsonSerializer.Deserialize<SettingInfo>(jsonStr);
BlurNumberOfTimes.Value = settingInfo.BlurNumberOfTimes;
LaplacianKsize.Value = settingInfo.LaplacianKsize;
NonLocalMeanH.Value = settingInfo.NonLocalMeanH;
UnsharpMaskingK.Value = settingInfo.UnsharpMaskingK;
});
// クローズ時の処理
ClosingCommand.Subscribe(_ => {
var settingJsonPath = getSettingJsonPath();
var settingInfo = new SettingInfo{
BlurNumberOfTimes = BlurNumberOfTimes.Value,
LaplacianKsize = LaplacianKsize.Value,
NonLocalMeanH = NonLocalMeanH.Value,
UnsharpMaskingK = UnsharpMaskingK.Value,
};
var jsonStr = System.Text.Json.JsonSerializer.Serialize(settingInfo);
var encoding = System.Text.Encoding.GetEncoding("utf-8");
using(var writer = new System.IO.StreamWriter(settingJsonPath, false, encoding))
{
writer.WriteLine(jsonStr);
}
});
}
}
}
ファイル名:SettingInfo.cs
namespace WpfSample15OpenCVFilter
{
public class SettingInfo
{
public int BlurNumberOfTimes{ get; set; }
public int NonLocalMeanH{ get; set; }
public int LaplacianKsize{ get; set; }
public int UnsharpMaskingK{ get; set; }
}
}
コメント