Skip to content

Commit 56a0240

Browse files
committed
feature: add copying image to clipboard; refactor: rearrange menu and thresholding
1 parent 17a4c75 commit 56a0240

11 files changed

Lines changed: 148 additions & 43 deletions

JSharp/ImageProcessingCore.cs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -575,20 +575,26 @@ public static Mat SimpleThreshold(Mat image, int threshold, SimpleThresholdingMe
575575
thresholdType = ThresholdType.Binary;
576576
CvInvoke.Threshold(image, result, threshold, 255, thresholdType);
577577
break;
578-
case SimpleThresholdingMethod.Adaptive:
579-
int odd = 11;
580-
int constantSubtracter = 5;
581-
CvInvoke.AdaptiveThreshold(image, result, 255, AdaptiveThresholdType.MeanC, ThresholdType.Binary, odd, constantSubtracter);
582-
break;
583578
case SimpleThresholdingMethod.Otsu:
584579
thresholdType = ThresholdType.Otsu;
585-
CvInvoke.Threshold(image, result, 0, 255, thresholdType);
580+
double value = CvInvoke.Threshold(image, result, 0, 255, thresholdType);
586581
break;
587582
};
588583

589584
return result;
590585
}
591586

587+
public static Mat AdaptiveThreshold(Mat image)
588+
{
589+
Mat result = new Mat();
590+
591+
int odd = 11;
592+
int constantSubtracter = 5;
593+
CvInvoke.AdaptiveThreshold(image, result, 255, AdaptiveThresholdType.MeanC, ThresholdType.Binary, odd, constantSubtracter);
594+
595+
return result;
596+
}
597+
592598
/// <summary>
593599
/// Applies thresholding to the input image based on the given thresholds and mode.
594600
/// </summary>

JSharp/Resources/Thresholding.Designer.cs

Lines changed: 27 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

JSharp/Resources/Thresholding.de.resx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,15 @@
117117
<resheader name="writer">
118118
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
119119
</resheader>
120+
<data name="AdaptiveThresholding" xml:space="preserve">
121+
<value>Adaptives Schwellenwertverfahren</value>
122+
</data>
120123
<data name="Analyze" xml:space="preserve">
121124
<value>Analysieren</value>
122125
</data>
126+
<data name="OneThreshold" xml:space="preserve">
127+
<value>Ein Schwellenwert</value>
128+
</data>
123129
<data name="ProjectStr" xml:space="preserve">
124130
<value>Projekt</value>
125131
</data>
@@ -147,4 +153,7 @@
147153
<data name="ThresholdingStr" xml:space="preserve">
148154
<value>Schwellenwertverfahren</value>
149155
</data>
156+
<data name="TwoThresholds" xml:space="preserve">
157+
<value>Zwei Schwellenwerte</value>
158+
</data>
150159
</root>

JSharp/Resources/Thresholding.pl.resx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,15 @@
117117
<resheader name="writer">
118118
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
119119
</resheader>
120+
<data name="AdaptiveThresholding" xml:space="preserve">
121+
<value>Progowanie Adaptacyjne</value>
122+
</data>
120123
<data name="Analyze" xml:space="preserve">
121124
<value>Przeprowadź Analizę</value>
122125
</data>
126+
<data name="OneThreshold" xml:space="preserve">
127+
<value>Jeden Próg</value>
128+
</data>
123129
<data name="ProjectStr" xml:space="preserve">
124130
<value>Projekt</value>
125131
</data>
@@ -147,4 +153,7 @@
147153
<data name="ThresholdingStr" xml:space="preserve">
148154
<value>Progowanie</value>
149155
</data>
156+
<data name="TwoThresholds" xml:space="preserve">
157+
<value>Dwa Progi</value>
158+
</data>
150159
</root>

JSharp/Resources/Thresholding.resx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,15 @@
117117
<resheader name="writer">
118118
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
119119
</resheader>
120+
<data name="AdaptiveThresholding" xml:space="preserve">
121+
<value>Adaptive Thresholding</value>
122+
</data>
120123
<data name="Analyze" xml:space="preserve">
121124
<value>Analyze</value>
122125
</data>
126+
<data name="OneThreshold" xml:space="preserve">
127+
<value>One Threshold</value>
128+
</data>
123129
<data name="ProjectStr" xml:space="preserve">
124130
<value>Project</value>
125131
</data>
@@ -147,4 +153,7 @@
147153
<data name="ThresholdingStr" xml:space="preserve">
148154
<value>Thresholding</value>
149155
</data>
156+
<data name="TwoThresholds" xml:space="preserve">
157+
<value>Two Thresholds</value>
158+
</data>
150159
</root>

JSharp/Utility/SimpleThresholdingMethod.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ namespace JSharp.Utility
1010
public enum SimpleThresholdingMethod
1111
{
1212
Standard,
13-
Adaptive,
1413
Otsu
1514
}
1615

@@ -19,7 +18,6 @@ public static class SimpleThresholdingTypeHelper
1918
private static readonly Dictionary<string, SimpleThresholdingMethod> thresholdingTypeMapping = new Dictionary<string, SimpleThresholdingMethod>()
2019
{
2120
{ Thresholding.ThresholdingStandard, SimpleThresholdingMethod.Standard },
22-
{ Thresholding.ThresholdingAdaptive, SimpleThresholdingMethod.Adaptive },
2321
{ Thresholding.ThresholdingOtsu, SimpleThresholdingMethod.Otsu },
2422
};
2523

JSharp/ViewModels/MainWindowViewModel.cs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,13 +97,15 @@ public System.Windows.Controls.RadioButton SelectedButton
9797
public DelegateCommand PyramidUp_ClickCommand { get; }
9898
public DelegateCommand PyramidDown_ClickCommand { get; }
9999
public DelegateCommand SimpleThreshold_ClickCommand { get; }
100+
public DelegateCommand AdaptiveThresholding_ClickCommand { get; }
100101
public DelegateCommand Watershed_ClickCommand { get; }
101102
public DelegateCommand Inpaint_ClickCommand { get; }
102103
public DelegateCommand GrabCut_ClickCommand { get; }
103104
public DelegateCommand DetailedAnalyze_ClickCommand { get; }
104105
public DelegateCommand OpenSettings_ClickCommand { get; }
105106
public DelegateCommand Rotate_ClickCommand { get; }
106107
public DelegateCommand Flip_ClickCommand { get; }
108+
public DelegateCommand CopyToSystem_ClickCommand { get; }
107109
#endregion
108110

109111
public MainWindowViewModel()
@@ -143,13 +145,15 @@ public MainWindowViewModel()
143145
PyramidUp_ClickCommand = new DelegateCommand(PyramidUp_Click);
144146
PyramidDown_ClickCommand = new DelegateCommand(PyramidDown_Click);
145147
SimpleThreshold_ClickCommand = new DelegateCommand(SimpleThreshold_Click);
148+
AdaptiveThresholding_ClickCommand = new DelegateCommand(AdaptiveThresholding_Click);
146149
Watershed_ClickCommand = new DelegateCommand(Watershed_Click);
147150
Inpaint_ClickCommand = new DelegateCommand(Inpaint_Click);
148151
GrabCut_ClickCommand = new DelegateCommand(GrabCut_Click);
149152
DetailedAnalyze_ClickCommand = new DelegateCommand(DetailedAnalyze_Click);
150153
OpenSettings_ClickCommand = new DelegateCommand(OpenSettings_Click);
151154
Rotate_ClickCommand = new DelegateCommand(Rotate_Click);
152155
Flip_ClickCommand = new DelegateCommand(Flip_Click);
156+
CopyToSystem_ClickCommand = new DelegateCommand(CopyToSystem_Click);
153157
#endregion
154158
}
155159

@@ -1095,6 +1099,22 @@ private void SimpleThreshold_Click()
10951099
thresholderWindow.Show();
10961100
}
10971101

1102+
private void AdaptiveThresholding_Click()
1103+
{
1104+
if (FocusedImage == null)
1105+
{
1106+
MessageBox.Show(Errors.NoImageFocused, Strings.Error, MessageBoxButton.OK, MessageBoxImage.Error);
1107+
return;
1108+
}
1109+
else if (FocusedImage.MatImage.NumberOfChannels != Constants.Grayscale_ChannelCount)
1110+
{
1111+
MessageBox.Show(Errors.ImageNotGrayscale, Strings.Error, MessageBoxButton.OK, MessageBoxImage.Error);
1112+
return;
1113+
}
1114+
1115+
FocusedImage.PerformAdaptiveThresholding();
1116+
}
1117+
10981118
private void Watershed_Click()
10991119
{
11001120
if (FocusedImage == null)
@@ -1163,7 +1183,7 @@ private void GrabCut_Click()
11631183
FocusedImage.UpdateImageSource(image);
11641184
}
11651185

1166-
public void OpenSettings_Click()
1186+
private void OpenSettings_Click()
11671187
{
11681188
SettingsWindow settingsWindow = new SettingsWindow();
11691189
SettingsWindowViewModel settingsWindowViewModel = new SettingsWindowViewModel();
@@ -1176,6 +1196,18 @@ public void OpenSettings_Click()
11761196
}
11771197
}
11781198

1199+
private void CopyToSystem_Click()
1200+
{
1201+
if (FocusedImage == null)
1202+
{
1203+
MessageBox.Show(Errors.NoImageFocused, Strings.Error, MessageBoxButton.OK, MessageBoxImage.Error);
1204+
return;
1205+
}
1206+
1207+
BitmapSource bitmapSource = FocusedImage.MatImage.MatToBitmapSource();
1208+
Clipboard.SetImage(bitmapSource);
1209+
}
1210+
11791211
private void DetailedAnalyze_Click()
11801212
{
11811213
if (FocusedImage == null)

JSharp/ViewModels/NewImageWindowViewModel.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,13 @@ public void PerformSimpleThresholding(Mat img, int threshold, SimpleThresholding
481481
UpdateImageSource(image);
482482
}
483483

484+
public void PerformAdaptiveThresholding()
485+
{
486+
Mat image = MatImage;
487+
image = ImageProcessingCore.AdaptiveThreshold(image);
488+
UpdateImageSource(image);
489+
}
490+
484491
public void Restore(Mat image)
485492
{
486493
UpdateImageSource(image);

JSharp/Views/MainWindow.xaml

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -25,50 +25,53 @@
2525
<Menu Width="Auto" Height="20" VerticalAlignment="Top" Grid.Row="0">
2626
<MenuItem Header="{x:Static resx:UIStrings.File}">
2727
<MenuItem x:Name="Open" Header="{x:Static resx:Strings.Open}">
28-
<MenuItem x:Name="OpenGray" Header="{x:Static resx:Strings.OpenGray}" Command="{Binding OpenGray_ClickCommand}"/>
29-
<MenuItem x:Name="OpenRGB" Header="{x:Static resx:Strings.OpenRGB}" Command="{Binding OpenRgb_ClickCommand}"/>
28+
<MenuItem Header="{x:Static resx:Strings.OpenGray}" Command="{Binding OpenGray_ClickCommand}"/>
29+
<MenuItem Header="{x:Static resx:Strings.OpenRGB}" Command="{Binding OpenRgb_ClickCommand}"/>
3030
</MenuItem>
31-
<MenuItem x:Name="Save" Header="{x:Static resx:Strings.Save}" Command="{Binding Save_ClickCommand}"/>
32-
<MenuItem x:Name="SaveAs" Header="{x:Static resx:Strings.SaveAs}" Command="{Binding SaveAs_ClickCommand}"/>
33-
<MenuItem x:Name="SaveAll" Header="{x:Static resx:Strings.SaveAll}" Command="{Binding SaveAll_ClickCommand}"/>
31+
<MenuItem Header="{x:Static resx:Strings.Save}" Command="{Binding Save_ClickCommand}"/>
32+
<MenuItem Header="{x:Static resx:Strings.SaveAs}" Command="{Binding SaveAs_ClickCommand}"/>
33+
<MenuItem Header="{x:Static resx:Strings.SaveAll}" Command="{Binding SaveAll_ClickCommand}"/>
3434
<Separator/>
35-
<MenuItem x:Name="Exit" Header="{x:Static resx:UIStrings.Exit}" Command="{Binding Exit_ClickCommand}"/>
35+
<MenuItem Header="{x:Static resx:UIStrings.Exit}" Command="{Binding Exit_ClickCommand}"/>
36+
</MenuItem>
37+
<MenuItem Header="Edit">
38+
<MenuItem Header="Copy to System" Command="{Binding CopyToSystem_ClickCommand}"/>
39+
<Separator />
40+
<MenuItem Header="{x:Static resx:Strings.Transform}">
41+
<MenuItem Header="{x:Static resx:Strings.Rotate}" Command="{Binding Rotate_ClickCommand}"/>
42+
<MenuItem Header="{x:Static resx:Strings.Flip}" Command="{Binding Flip_ClickCommand}"/>
43+
</MenuItem>
3644
</MenuItem>
3745
<MenuItem Header="{x:Static resx:Strings.Image}">
38-
<MenuItem x:Name="Duplicate" Header="{x:Static resx:Strings.Duplicate}" Command="{Binding Duplicate_CommandClick}"/>
39-
<MenuItem x:Name="Convert" Header="{x:Static resx:Strings.Convert}">
40-
<MenuItem x:Name="Grayize" Header="{x:Static resx:Strings.Grayize}" Command="{Binding Grayize_ClickCommand}"/>
41-
<MenuItem x:Name="ConvertRgbToHsv" Header="{x:Static resx:Strings.RgbToHsv}" Command="{Binding ConvertRgbToHsv_ClickCommand}"/>
42-
<MenuItem x:Name="ConvertRgbToLab" Header="{x:Static resx:Strings.RgbToLab}" Command="{Binding ConvertRgbToLab_ClickCommand}"/>
46+
<MenuItem Header="{x:Static resx:Strings.Duplicate}" Command="{Binding Duplicate_CommandClick}"/>
47+
<MenuItem Header="{x:Static resx:Strings.Convert}">
48+
<MenuItem Header="{x:Static resx:Strings.Grayize}" Command="{Binding Grayize_ClickCommand}"/>
49+
<MenuItem Header="{x:Static resx:Strings.RgbToHsv}" Command="{Binding ConvertRgbToHsv_ClickCommand}"/>
50+
<MenuItem Header="{x:Static resx:Strings.RgbToLab}" Command="{Binding ConvertRgbToLab_ClickCommand}"/>
4351
</MenuItem>
4452
<Separator/>
4553
<MenuItem Header="Histogram">
46-
<MenuItem x:Name="ShowHistogram" Header="{x:Static resx:Strings.ShowHistogram}" Command="{Binding ShowHistogram_ClickCommand}"/>
47-
<MenuItem x:Name="StretchHistogram" Header="{x:Static resx:Strings.StretchHistogram}" Command="{Binding StretchHistogram_ClickCommand}"/>
48-
<MenuItem x:Name="StretchContrast" Header="{x:Static resx:Strings.StretchContrast}" Command="{Binding StretchContrast_ClickCommand}"/>
49-
<MenuItem x:Name="EqualizeHistogram" Header="{x:Static resx:Strings.EqualizeHistogram}" Command="{Binding EqualizeHistogram_ClickCommand}" />
54+
<MenuItem Header="{x:Static resx:Strings.ShowHistogram}" Command="{Binding ShowHistogram_ClickCommand}"/>
55+
<MenuItem Header="{x:Static resx:Strings.StretchHistogram}" Command="{Binding StretchHistogram_ClickCommand}"/>
56+
<MenuItem Header="{x:Static resx:Strings.StretchContrast}" Command="{Binding StretchContrast_ClickCommand}"/>
57+
<MenuItem Header="{x:Static resx:Strings.EqualizeHistogram}" Command="{Binding EqualizeHistogram_ClickCommand}" />
5058
</MenuItem>
5159
<Separator/>
52-
<MenuItem Header="{x:Static resx:Strings.Transform}">
53-
<MenuItem Header="{x:Static resx:Strings.Rotate}" Command="{Binding Rotate_ClickCommand}"/>
54-
<MenuItem Header="{x:Static resx:Strings.Flip}" Command="{Binding Flip_ClickCommand}"/>
55-
</MenuItem>
56-
<MenuItem x:Name="SplitChannels" Header="{x:Static resx:Strings.SplitChannels}" Command="{Binding SplitChannels_ClickCommand}"/>
60+
<MenuItem Header="{x:Static resx:Strings.SplitChannels}" Command="{Binding SplitChannels_ClickCommand}"/>
5761
<Separator/>
5862
<MenuItem Header="{x:Static resx:Strings.PyramidUp}" Command="{Binding PyramidUp_ClickCommand}"/>
5963
<MenuItem Header="{x:Static resx:Strings.PyramidDown}" Command="{Binding PyramidDown_ClickCommand}"/>
6064
</MenuItem>
61-
<MenuItem Header="Basic operations">
62-
<MenuItem x:Name="Negate" Header="{x:Static resx:Strings.Negate}" Command="{Binding Negate_ClickCommand}"/>
65+
<MenuItem Header="Process">
66+
<MenuItem Header="{x:Static resx:Strings.Negate}" Command="{Binding Negate_ClickCommand}"/>
6367
<MenuItem Header="{x:Static resx:Strings.Posterize}" Command="{Binding Posterize_ClickCommand}"/>
6468
<MenuItem Header="{x:Static resx:Strings.Filters}">
6569
<MenuItem Header="{x:Static resx:Strings.Convolve}" Command="{Binding Convolve_ClickCommand}"/>
6670
<MenuItem Header="{x:Static resx:Strings.Median}" Command="{Binding Median_ClickCommand}"/>
6771
<MenuItem Header="{x:Static resx:Strings.DoubleConvolve}" Command="{Binding DoubleConvolve_ClickCommand}"/>
6872
</MenuItem>
6973
<MenuItem Header="{x:Static resx:Strings.ImageCalculator}" Command="{Binding ImageCalculator_ClickCommand}"/>
70-
</MenuItem>
71-
<MenuItem Header="Process">
74+
<Separator/>
7275
<MenuItem Header="{x:Static resx:Strings.MorphologicalOperations}">
7376
<MenuItem Header="{x:Static resx:Strings.Erode}" Command="{Binding Erode_ClickCommand}"/>
7477
<MenuItem Header="{x:Static resx:Strings.Dilate}" Command="{Binding Dilate_ClickCommand}"/>
@@ -81,8 +84,11 @@
8184
<MenuItem Header="{x:Static resx:Strings.PlotProfile}" Command="{Binding PlotProfile_ClickCommand}"/>
8285
</MenuItem>
8386
<MenuItem Header="Advanced operations">
84-
<MenuItem Header="{x:Static resx:Strings.Thresholding}" Command="{Binding SimpleThreshold_ClickCommand}"/>
85-
<MenuItem Header="{x:Static resx:Thresholding.ThresholdingStr}" Command="{Binding Threshold_ClickCommand}"/>
87+
<MenuItem Header="{x:Static resx:Strings.Thresholding}">
88+
<MenuItem Header="{x:Static resx:Thresholding.OneThreshold}" Command="{Binding SimpleThreshold_ClickCommand}"/>
89+
<MenuItem Header="{x:Static resx:Thresholding.TwoThresholds}" Command="{Binding Threshold_ClickCommand}"/>
90+
<MenuItem Header="{x:Static resx:Thresholding.AdaptiveThresholding}" Command="{Binding AdaptiveThresholding_ClickCommand}"/>
91+
</MenuItem>
8692
<MenuItem Header="{x:Static resx:Strings.Watershed}" Command="{Binding Watershed_ClickCommand}"/>
8793
<MenuItem Header="{x:Static resx:Strings.Inpaint}" Command="{Binding Inpaint_ClickCommand}"/>
8894
<MenuItem Header="{x:Static resx:Strings.GrabCut}" Command="{Binding GrabCut_ClickCommand}"/>
@@ -94,8 +100,8 @@
94100
<MenuItem Header="{x:Static resx:Thresholding.Analyze}" Command="{Binding Analyze_ClickCommand}"/>
95101
</MenuItem>
96102
<MenuItem Header="{x:Static resx:UIStrings.Settings}" Command="{Binding OpenSettings_ClickCommand}"/>
97-
<MenuItem x:Name="Help" Header="{x:Static resx:UIStrings.Help}">
98-
<MenuItem x:Name="About" Header="{x:Static resx:UIStrings.About}" Click="About_Click"/>
103+
<MenuItem Header="{x:Static resx:UIStrings.Help}">
104+
<MenuItem Header="{x:Static resx:UIStrings.About}" Click="About_Click"/>
99105
</MenuItem>
100106
</Menu>
101107
<Label x:Name="LblFocusedImage" Content="{Binding LblFocusedImageContent, TargetNullValue=null}" Grid.Row="1" HorizontalAlignment="Left" Margin="0,2,0,0" VerticalAlignment="Top" Height="31" Width="Auto"/>

0 commit comments

Comments
 (0)