处理另一个线程时的图像失真

时间:2009-03-12 17:33:36

标签: c# image-processing

我写了一个小应用程序,用作沙盒,用于测试最终会出现在生产产品中的想法。这个想法很简单;使用TrackBar来改变图像的整体亮度。因为这个过程需要相当长的时间,所以我需要在另一个线程中完成(除非你有更好的方法)。我不能使用ColorMatrix类,因为它允许颜色组件值溢出,我无法弄清楚如何将它们夹在255.无论如何,这是问题所在:

当我慢慢移动TrackBar时,一切都很好。如果我在GUI线程上运行它,一切都很好(滞后太多)。当我快速移动TrackBar时,图像会变形。其上出现水平条带,就像使用不同比例因子处理图像一样。

我不知道这是怎么回事,因为我使用基本位图绘制显示位图来获取颜色值,我认为我阻止操作从重新开始直到它完成,但我有< em>非常很少有线程经验。我坚持到这一点,所以你们给予的任何帮助都会非常感激。该项目如下(必须使用文件前端,因为它对于论坛附件来说太大了。)

这是项目的链接,整个程序可以在下面阅读 http://files.filefront.com/13453973

public partial class Form1 : Form
{       
    public Form1( )
    {
        InitializeComponent( );
        testPBox1.Image = Properties.Resources.test;
        trackBar1.Value = 100;
        trackBar1.ValueChanged += trackBar1_ValueChanged;
    }     

    void trackBar1_ValueChanged( object sender, EventArgs e )
    {
        testPBox1.IntensityScale = (float) trackBar1.Value / 100;
    }
}

class TestPBox : Control
{
    private const int MIN_SAT_WARNING = 240;        
    private Bitmap m_srcBitmap;
    private Bitmap m_dispBitmap;
    private float m_scale;        
    BackgroundWorker worker;

    public TestPBox( )
    {
        this.DoubleBuffered = true;                        
        worker = new BackgroundWorker( );
        worker.DoWork += new DoWorkEventHandler( worker_DoWork );
        IntensityScale = 1.0f;
    }       

    public Bitmap Image
    {
        get
        {
            return m_dispBitmap;
        }
        set
        {
            if ( value != null )
            {
                m_srcBitmap = value;
                m_dispBitmap = (Bitmap) value.Clone( );
                Invalidate( );
                OnImageChanged( EventArgs.Empty );
            }
        }
    }

    [DefaultValue( 1.0f )]
    public float IntensityScale
    {
        get
        {
            return m_scale;
        }
        set
        {
            if ( value == 0.0 || m_scale == value )
            {
                return;
            }

            m_scale = value;
            if ( !this.DesignMode && StartImageProcThread( ) )
            {
                OnIntensityscaleChanged( EventArgs.Empty );
            }                
        }
    }

    private bool StartImageProcThread( )
    {                        
        if ( !worker.IsBusy )
        {                     
            worker.RunWorkerAsync( );
            return true;
        }

        return false;
    }

    private void worker_DoWork( object sender, DoWorkEventArgs e )
    {
        ChangeIntensity( );
    }

    private unsafe void ChangeIntensity( )
    {
        if ( Image != null )
        {                
            BitmapData srcData = m_srcBitmap.LockBits
                    ( new Rectangle( new Point( 0, 0 ), m_srcBitmap.Size ), ImageLockMode.ReadWrite, PixelFormat.Format32bppRgb );
            BitmapData dspData = m_dispBitmap.LockBits
                    ( new Rectangle( new Point( 0, 0 ), m_dispBitmap.Size ), ImageLockMode.ReadWrite, PixelFormat.Format32bppRgb );
            byte* pSrc = (byte*) srcData.Scan0;
            byte* pDsp = (byte*) dspData.Scan0;

            for ( int y = 0; y < m_dispBitmap.Height; ++y )
            {
                for ( int x = 0; x < m_dispBitmap.Width; ++x )
                {
                    // we are dealing with a monochrome image, so r = g = b.
                    // We only need to get one value to use for all r, g, and b.
                    byte b = (byte) CompMinMax( 0, 255, (int) ( pSrc[0] * m_scale ) );
                    Color c = ( b > MIN_SAT_WARNING ) ? Color.FromArgb( b, Color.Red ) : Color.FromArgb( 255, b, b, b );

                    pDsp[3] = (byte) c.A;
                    pDsp[2] = (byte) c.R;
                    pDsp[1] = (byte) c.G;
                    pDsp[0] = (byte) c.B;

                    pSrc += 4;
                    pDsp += 4;
                }
            }

            m_srcBitmap.UnlockBits( srcData );
            m_dispBitmap.UnlockBits( dspData );
            this.Invalidate( );           
        }
    }

    private int CompMinMax( int min, int max, int value )
    {
        if ( value > max ) return max;
        if ( value < min ) return min;
        return value;
    }

    protected override void OnPaint( PaintEventArgs e )
    {
        if ( Image != null )
        {               
            Graphics g = e.Graphics;
            Rectangle drawingRect = PaintUtils.CenterInRect( ClientRectangle, PaintUtils.ScaleRect( ClientRectangle, Image.Size ).Size );
            g.DrawImage( Image, drawingRect, 0, 0, Image.Width, Image.Height, GraphicsUnit.Pixel );         
        }

        base.OnPaint( e );
    }

1 个答案:

答案 0 :(得分:1)

我认为您可以在m_scale正在运行的中间更改ChangeIntensity的值。

    // ...
    m_scale = value; 
    if ( !this.DesignMode && StartImageProcThread( ) )
    {
        OnIntensityscaleChanged( EventArgs.Empty );
    }  

    // ...
    private bool StartImageProcThread( )
    {                        
        if ( !worker.IsBusy )
        {                     
            worker.RunWorkerAsync( );
            return true;
        }

        return false;
    }

如果您的工作人员处于处理过程中,则用于缩放的值会发生变化,并且仅适用于仍需要处理的像素。