Aquí podría ser tu PUBLICIDAD


Distorsiones de imagen al procesar en otro hilo

votos
0

Escribí una pequeña aplicación para usar como un sandbox para probar ideas que terminarán en un producto de producción. La idea es simple; use una barra de seguimiento para cambiar el brillo general de una imagen. Debido a que este proceso lleva bastante tiempo, necesito hacerlo en otro hilo (a menos que tenga una mejor manera). No puedo usar la clase ColorMatrix porque permite desbordar los valores de los componentes de color y no puedo encontrar la manera de fijarlos en 255. De todos modos, aquí está el problema:

Cuando muevo el TrackBar lentamente, todo funciona bien. Si ejecuto esto en el hilo de la GUI, todo funciona bien (hay demasiada demora). Cuando muevo el TrackBar rápidamente, la imagen se distorsiona. Aparecen bandas horizontales a través de él, como si la imagen se procesara utilizando diferentes factores de escala.

No sé cómo podría ser esto, ya que estoy dibujando en un mapa de bits de visualización usando un mapa de bits base para obtener los valores de color, y creo que estoy bloqueando la operación para que comience de nuevo hasta que se complete, pero tengo muy poca experiencia con enhebrado. Estoy atascado en este punto, por lo que cualquier ayuda que ustedes puedan dar sería muy apreciada. El proyecto está a continuación (tuvo que usar filefront ya que es demasiado grande para un archivo adjunto del foro).

Aquí hay un enlace al proyecto, el programa completo se puede leer a continuación.
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 );
    }
Publicado el 12/03/2009 a las 18:33
fuente por usuario Ed S.
En otros idiomas...        العربية       

1 respuestas

votos
1

Me parece que puedes cambiar el valor de m_scaleen medio de una ChangeIntensitycorrida.

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

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

        return false;
    }

Si su trabajador se encuentra en el medio del procesamiento, el valor que está utilizando para escalar cambia y solo se aplica a los píxeles que aún deben procesarse.

Respondida el 12/03/2009 a las 06:39
fuente por usuario Daniel LeCheminant


Aquí podría ser tu PUBLICIDAD