【发布时间】:2019-09-23 10:28:06
【问题描述】:
我想通过在图像上绘制矩形来绘制选区,但选区似乎有很大的偏差。这是我的代码。
EdgeDetectionWindow.xaml
<Window x:Class="SenpiCHC.EdgeDetectionWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SenpiCHC"
xmlns:codeg="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
Title="EdgeDetectionWindow" Width="1270" Height="720"
WindowState="Maximized"
WindowStyle="None">
<Window.Resources>
<ObjectDataProvider x:Key="dataFromEnum"
MethodName="GetValues"
ObjectType="{x:Type codeg:Enum}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="local:SelectedEdgeDetectionType"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</Window.Resources>
<Grid>
<StackPanel>
<Image x:Name="imgDynamic"
MouseDown="ImgDynamic_MouseDown"
MouseMove="ImgDynamic_MouseMove"
MouseUp="ImgDynamic_MouseUp"
Width="1000"
Height="562"/>
<Button Content="Select file"
Margin="30"
Width="100"
x:Name="selectFileBtn"
Click="SelectFileBtn_Click"/>
<ComboBox Margin="10"
Width="100"
x:Name="edgeDetectionCbox"
SelectionChanged="EdgeDetectionCbox_SelectionChanged"
ItemsSource="{Binding Source={StaticResource dataFromEnum}}">
</ComboBox>
<Button Content="Detect now!"
Margin="30"
Width="100"
x:Name="detectBtn"
Click="DetectBtn_Click"/>
</StackPanel>
</Grid>
</Window>
EdgeDetectionWindow.xaml.cs
public partial class EdgeDetectionWindow : Window
{
Image<Bgr, byte> _imgInput;
private bool IsSelecting = false;
private double X0, Y0, X1, Y1;
private Bitmap ImageCopy;
public EdgeDetectionWindow()
{
InitializeComponent();
}
private void SelectFileBtn_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
if (openFileDialog.ShowDialog() == true)
{
Uri fileUri = new Uri(openFileDialog.FileName);
imgDynamic.Source = new BitmapImage(fileUri); // Why bitmapimage? //put the imagefile into the window
ImageCopy = new Bitmap(openFileDialog.FileName);
_imgInput = new Image<Bgr, byte>(openFileDialog.FileName);
}
}
private void ImgDynamic_MouseDown(object sender, MouseButtonEventArgs e)
{
IsSelecting = true;
X0 = e.GetPosition(imgDynamic).X;
Y0 = e.GetPosition(imgDynamic).Y;
}
private void ImgDynamic_MouseMove(object sender, MouseEventArgs e)
{
if (!IsSelecting) return;
//Save the final point
X1 = e.GetPosition(this.imgDynamic).X;
Y1 = e.GetPosition(this.imgDynamic).Y;
//Make a bitmap to display the rectangle
Bitmap bm = new Bitmap(ImageCopy);
//Draw the rectangle
using (Graphics gr = Graphics.FromImage(bm))
{
gr.DrawRectangle(Pens.Red,
(float)Math.Min(X0, X1), (float)Math.Min(Y0, Y1),
(float)Math.Abs(X0 - X1), (float)Math.Abs(Y0 - Y1));
}
//Display the rectangle
imgDynamic.Source = BitmapToImageSource(bm);
}
private void ImgDynamic_MouseUp(object sender, MouseButtonEventArgs e)
{
if (!IsSelecting) return;
IsSelecting = false; //reset the value
//Display the rectangle
imgDynamic.Source = BitmapToImageSource(ImageCopy);
}
private void EdgeDetectionCbox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
}
private void DetectBtn_Click(object sender, RoutedEventArgs e)
{
if (edgeDetectionCbox.SelectedItem.ToString().Equals("Canny"))
{
//Receive input from inputbox
CannyInputDialogue popup = new CannyInputDialogue();
popup.ShowDialog();
int tresh = int.Parse(popup.Tresh);
int treshLinking = int.Parse(popup.TreshLinking);
//Do canny
//Create grayscale
Image<Gray, byte> _imgCanny = new Image<Gray, byte>(_imgInput.Width, _imgInput.Height, new Gray(0)); //canny with 0 intensity gray image
_imgCanny = _imgInput.Canny(tresh, treshLinking);
//Display the image because imgDynamic.Source cannot display image from emgucv directly
Bitmap display = _imgCanny.ToBitmap();
imgDynamic.Source = BitmapToImageSource(display);
}
else if (edgeDetectionCbox.SelectedItem.ToString().Equals("RobertCross"))
{
//Do robertcross
}
else if (edgeDetectionCbox.SelectedItem.ToString().Equals("Laplacian"))
{
//Do laplacian
LaplacianInputDialogue popup = new LaplacianInputDialogue();
popup.ShowDialog();
int apertureSize = int.Parse(popup.ApertureSize);
//Do grayscale
Image<Gray, byte> _imgGray = _imgInput.Convert<Gray, byte>(); //somehow it has to be converted(?)
//Do sobel
Image<Gray, float> _imgLaplacian = new Image<Gray, float>(_imgInput.Width, _imgInput.Height); //canny with 0 intensity gray image
_imgLaplacian = _imgGray.Laplace(apertureSize);
//Display the image because imgDynamic.Source cannot display image from emgucv directly
Bitmap display = _imgLaplacian.ToBitmap();
imgDynamic.Source = BitmapToImageSource(display);
}
else if (edgeDetectionCbox.SelectedItem.ToString().Equals("Sobel"))
{
//Receive input from inputbox
SobelInputDialogue popup = new SobelInputDialogue();
popup.ShowDialog();
int xorder = int.Parse(popup.Xorder);
int yorder = int.Parse(popup.Yorder);
int apertureSize = int.Parse(popup.ApertureSize);
//Do grayscale
Image<Gray, byte> _imgGray = _imgInput.Convert<Gray, byte>(); //somehow it has to be converted(?)
//Do sobel
Image<Gray, float> _imgSobel = new Image<Gray, float>(_imgInput.Width, _imgInput.Height); //canny with 0 intensity gray image
_imgSobel = _imgGray.Sobel(xorder, yorder, apertureSize);
//Display the image because imgDynamic.Source cannot display image from emgucv directly
Bitmap display = _imgSobel.ToBitmap();
imgDynamic.Source = BitmapToImageSource(display);
}
}
BitmapImage BitmapToImageSource(Bitmap bitmap)
{
using (MemoryStream memory = new MemoryStream())
{
bitmap.Save(memory, System.Drawing.Imaging.ImageFormat.Bmp);
memory.Position = 0;
BitmapImage bitmapimage = new BitmapImage();
bitmapimage.BeginInit();
bitmapimage.StreamSource = memory;
bitmapimage.CacheOption = BitmapCacheOption.OnLoad;
bitmapimage.EndInit();
return bitmapimage;
}
}
}
我已经尝试将 e.GetPosition() 参数放到 this 或 imgDynamic 中,但它仍然相差很大。有什么解决方法吗?如果我的代码非常混乱,我很抱歉,因为我仍在努力了解更多信息。
【问题讨论】:
-
首先,您不应该在 WPF 应用程序中使用 WinForms System.Drawing.Bitmap 类。要在图像顶部绘制选择矩形,请使用 Rectangle。然后从源 BitmapImage 创建一个 CroppedBitmap。如果您能详细说明您的实际目标,我们或许可以提供更合适的方法。
-
我打算创建一个应用程序,在该应用程序中,用户将选择用户将其确定为对象的区域并在所选区域上应用边缘检测。然后应用程序将以像素为单位计算对象的面积(在应用边缘检测之后)。不过我还是不知道该怎么做。