我写了一个小应用程序,用作沙盒,用于测试最终会出现在生产产品中的想法。这个想法很简单;使用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 );
}
答案 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;
}
如果您的工作人员处于处理过程中,则用于缩放的值会发生变化,并且仅适用于仍需要处理的像素。