如何将图像更新到不同的线程?

时间:2014-07-23 03:39:17

标签: c# wpf multithreading

我正在做一个指纹图像处理的简单项目。

我正在尝试在处理过程中使用线程,以便UI保持平滑。

当我在尝试处理直方图均衡时尝试显示指纹图像时,我收到一个错误,表示图像仍然被另一个线程使用。

我一直在尝试使用Freeze()方法查找解决方案,但我不知道在哪里放置它。

这是我的代码。

private void btnLoadImage_Click(object sender, RoutedEventArgs e)
    {
        OpenFileDialog openImg = new OpenFileDialog();
        openImg.FileName = "Fingerprint Image"; 
        openImg.DefaultExt = ".tif" ;
        openImg.Filter = "Image File (*.tif)|*.tif*|" +
            "JPEG Files (*.jpg, *.jpeg)|*.jpeg, *.jpeg|" + 
            "PNG Files (*.png)|*.png"; 

        Nullable<bool> result = openImg.ShowDialog();

        if (result == true)
        {
            imgDisp.Source = new BitmapImage(new Uri(openImg.FileName));
        }
    }

    private void btnGenKey_Click(object sender, RoutedEventArgs e)
    {
        if (imgDisp.Source == null)
        {
            MessageBox.Show("Upload Image First!");
        }
        else
        {
            imgDisp.Source.Freeze();
            BackgroundWorker doImg = new BackgroundWorker();
            doImg.DoWork += new DoWorkEventHandler(doImg_DoWork);
            doImg.RunWorkerCompleted += new RunWorkerCompletedEventHandler(doImg_RunWorkerCompleted);
            doImg.RunWorkerAsync(imgDisp.Source);
        }
    }

    void doImg_DoWork(object sender, DoWorkEventArgs e)
    {
        ImageProcessor.BasicImgPro bip = new ImageProcessor.BasicImgPro();
        BitmapImage srcImg = (BitmapImage)imgDisp.Source;
        using (MemoryStream outImg = new MemoryStream())
        {
            BitmapEncoder enc = new BmpBitmapEncoder();
            enc.Frames.Add(BitmapFrame.Create(srcImg));
            enc.Save(outImg);
            Bitmap newBitmap = new Bitmap(outImg);
            Bitmap he = bip.HistoEqualize(newBitmap);
            using (var memory = new MemoryStream())
            {
                he.Save(memory, ImageFormat.Png);
                memory.Position = 0;

                var displayImg = new BitmapImage();
                displayImg.BeginInit();
                displayImg.StreamSource = memory;
                displayImg.CacheOption = BitmapCacheOption.OnLoad;
                displayImg.EndInit();
                e.Result = displayImg;
            }
        }
    }

    void doImg_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Error != null)
        {
            MessageBox.Show(e.Error.Message);
        }
        else
        {
            imgDisp.Source = (ImageSource)e.Result;
        }
    }

1 个答案:

答案 0 :(得分:0)

您可以在将BitmapImage传递给worker之前克隆它,但是使用普通Image(即Bitmap)进行处理会更简单(因为这是图像处理库使用),并仅保留BitmapImage以显示WPF:

private void btnLoadImage_Click(object sender, RoutedEventArgs e)
{
    using (var openImg = new OpenFileDialog())
    {
        ...

        if (openImg.ShowDialog() == DialogResult.Ok)
            LoadImage(openImg.FileName);
    }
}

private Bitmap _bitmap;
void LoadImage(string uri)
{
    // use a BitmapImage for display
    imgDisp.Source = new BitmapImage(new Uri(openImg.FileName));

    // use a Bitmap for processing
    _bitmap = new Bitmap(openImg.FileName);
}

这也意味着您无需将BitmapImage转换为Bitmap内的BackgroundWorker

// simply pass the bitmap instance to the worker
doImg.RunWorkerAsync(_bitmap);

// worker method gets simplified a bit
void doImg_DoWork(object sender, DoWorkEventArgs e)
{
    var bip = new ImageProcessor.BasicImgPro();
    var bitmap = (Bitmap)e.Argument;
    var result = bip.HistoEqualize(bitmap);
    e.Result = result;
}

// convert to an image source when done
void doImg_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Error != null)
    {
        MessageBox.Show(e.Error.Message);
        return;
    }

    imgDisp.Source = ConvertBitmapToImageSource((Bitmap)e.Result);
}