基于.NET数字处理程序的框架设计

2016-02-19 17:57 9 1 收藏

下面是个基于.NET数字处理程序的框架设计教程,撑握了其技术要点,学起来就简单多了。赶紧跟着图老师小编一起来看看吧!

【 tulaoshi.com - Web开发 】

          接触数字图像处理最早是在高中,那时候PHOTOSHOP还是4.0,可能是因为先入为主的关系,到现在都没有学3DMAX之类的兴趣,2D到3D的飞跃估计是没我什么事了,舍不得那平方到立方的高薪....呵呵。
  在上大学的时候,就和同学一起写过一些图像处理的程序,那个时候编程还很随意,考虑的只是如何实现,现在看来真正的技术是把握全局的能力,而不是灵光一现的神奇。前些日子接触了一些国外的图像处理程序,在这里算是作个总结,估计以后不会再针对性的研究图像处理方面的东西了。
          以前的一个同学曾经跟我说过.net没有指针,现在很多培训课好像也是这么讲的,其实这是一个谬误。只是framework不推荐使用指针,尤其是在webservise,remoting等跨进程操作中,指针都是不安全的。但用过TC的各位都应该对指针的执行效率又深刻的印象,在批量运算大规模数据的需求下,指针是不二的选择。因而.net聪明的保留的保留了指针,并将其列入不安全方法集中。合理的使用指针将大幅度提高执行效率,我曾做过试验,对640*480的图像进行逐点运算,非指针运算要执行数分钟,而指针运算几乎是瞬间完成的。所以不要害怕使用指针。
          其次就是数学,奉劝大家一定要弄明白了再写程序,数学课不是闹着玩的......想不明白就要躺在床上反复的想,我总觉得数学能预防老年痴呆。
          言归正传,说说程序结构吧  :
                                                                  Imaging项目(滤镜,纹理,图像模式)
                                                                  Math项目(算法,边界,定制。及常用计算方法)
                                                                  主程序项目
          各举个例子来说明,我也来一回面向接口编程 ,

  public interface IFilter
   {
    Bitmap Apply( Bitmap img );
   }

  举例来说明,我也来一回面向接口编程 ,各滤镜都要实现这个接口,接口定义还包括一个不生成实际图像,只生成二进制对象的借口定义,在这里暂不作考虑。以取反色滤镜为例
  public Bitmap Apply( Bitmap srcImg )
          {
              // get source image size
              int width = srcImg.Width;
              int height = srcImg.Height;
             
              PixelFormat fmt = ( srcImg.PixelFormat == PixelFormat.Format8bppIndexed ) ?
                          PixelFormat.Format8bppIndexed : PixelFormat.Format24bppRgb;

              // lock source bitmap data
              BitmapData srcData = srcImg.LockBits(
                  new Rectangle( 0, 0, width, height ),
                  ImageLockMode.ReadOnly, fmt );

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com/webkaifa/)

              // create new image
              Bitmap dstImg = ( fmt == PixelFormat.Format8bppIndexed ) ?
                          AForge.Imaging.Image.CreateGrayscaleImage( width, height ) :
                          new Bitmap( width, height, fmt );

              // lock destination bitmap data
              BitmapData dstData = dstImg.LockBits(
                  new Rectangle( 0, 0, width, height ),
                  ImageLockMode.ReadWrite, fmt );

              // copy image
              Win32.memcpy( dstData.Scan0, srcData.Scan0, srcData.Stride * height );

              // process the filter
              ProcessFilter( dstData, fmt );

              // unlock both images
              dstImg.UnlockBits( dstData );
              srcImg.UnlockBits( srcData );

              return dstImg;
          }

  
  是该滤镜方法的入口,完成了处理前的准备工作,ProcessFilter同时调用每个滤镜类中共有的ProcessFilter方法,而这个ProcessFilter就是实现功能的关键所在了逐点运算或模版运算。
  // Process the filter
          private unsafe void ProcessFilter( BitmapData data, PixelFormat fmt )
          {
              int width    = data.Width;
              int height    = data.Height;

              int lineSize = width * ( ( fmt == PixelFormat.Format8bppIndexed ) ? 1 : 3 );
              int offset = data.Stride - lineSize;

              // do the job
              byte * ptr = (byte *) data.Scan0.ToPointer( );

              // invert
              for ( int y = 0; y height; y++ )
              {
                  for ( int x = 0; x lineSize; x++, ptr ++ )
                  {
                      // ivert each pixel
                      *ptr = (byte)( 255 - *ptr );
                  }
                  ptr += offset;
              }
          }

  其中Format8bppIndexed是不必太关心的,个人认为设计初期可以不用考虑兼容它的问题。
  下面来说说纹理,这个以前考虑得还不太多,但发现老外很喜欢玩这个,因为纹理在数学方面发挥的空间更大,我也不知道他们是怎么想出来的,凭空想可能还真是有难度,可能是他们谁在玩数学建模软件的时候发现这个玩法的,于是高数老师谁也不服谁,把算法玩的火火的。反正我觉得是这么回事。。。
      public interface ITextureGenerator
      {
          /**//// summary
          /// Generate texture
          /// /summary
          float[,] Generate( int width, int height );

          /**//// summary
          /// Reset - regenerate internal random numbers
          /// /summary
          void Reset( );
      }
  这是纹理生成器的实现接口,为了保证每次的纹理不同,还要更新随机数以作为计算参数
          private Math.PerlinNoise noise = new Math.PerlinNoise( 1.0 / 32, 0.05, 0.5, 8 );
  实现纹理细节还需要靠noise实现,因而需要实现许多种noise。
          // Constructors
          public WoodTexture( ) : this( 12.0 ) { }
          public WoodTexture( double rings )
          {
              this.rings = rings;
              Reset( );
          }

  构造函数提供了默认值的设置,也就是对单位纹理大小的限定。
          // Generate texture
          public float[,] Generate( int width, int height )
          {
              float[,]    texture = new float[height, width];
              int            w2 = width / 2;
              int            h2 = height / 2;

              for ( int y = 0; y height; y++ )
              {
                  for ( int x = 0; x width; x++ )
                  {
                      double xv = (double) ( x - w2 ) / width;
                      double yv = (double) ( y - h2 ) / height;

                      texture[y, x] =
                          Math.Max( 0.0f, Math.Min( 1.0f, (float)
                          Math.Abs( Math.Sin(
                              ( Math.Sqrt( xv * xv + yv * yv ) + noise.Function2D( x + r, y + r ) )
                                  * Math.PI * 2 * rings
                          ))
                          ));
                  }
              }
              return texture;
          }
  这就是。。。我数学不好的下场。都不知道她在说什么呢,最小值中选出最大值。算法不难找,关键是要看结构如何将他们整合起来。
          public void Reset( )
          {
              r = rand.Next( 5000 );
          }别忘了这个随机数,数字的图像也需要自然的美。

  Math工程中面向对象的观念不它容易得到贯彻,看一看那个PerlinNoise吧,抛砖引玉。
          public PerlinNoise( double initFrequency, double initAmplitude, double persistance, int octaves )
          {
              this.initFrequency    = initFrequency;
              this.initAmplitude    = initAmplitude;
              this.persistance    = persistance;
              this.octaves        = octaves;
          }
  首先要收集数据,因为图像处理要涉及到一维和二维两种情况,因而像noise这种底层方法要分别对应着两种情况给出对应的方法。
          /**//// summary
          /// 1-D Perlin noise function
          /// /summary
          public double Function( double x )
          {
              double    frequency = initFrequency;
              double    amplitude = initAmplitude;
              double    sum = 0;
             
              // octaves
              for ( int i = 0; i octaves; i++ )
              {
                  sum += SmoothedNoise( x * frequency ) * amplitude;

                  frequency *= 2;
                  amplitude *= persistance;
              }
              return sum;
          }

          /**//// summary
          /// 2-D Perlin noise function
          /// /summary
          public double Function2D( double x, double y )
          {
              double    frequency = initFrequency;
              double    amplitude = initAmplitude;
              double    sum = 0;
             
              // octaves
              for ( int i = 0; i octaves; i++ )
              {
                  sum += SmoothedNoise( x * frequency, y * frequency ) * amplitude;

                  frequency *= 2;
                  amplitude *= persistance;
              }
              return sum;
          }
   一维跟二维的区别是什么,上中学的时候知道了线的运动生成了面,上大学又知道了循环着变化着的线能代表面,但如果做过了边缘识别和锐化以后话,又发现以前小看线了,其实它只是比面少一个参数而已。

  
          /**//// summary
          /// Ordinary noise function
          /// /summary
          protected double Noise( int x )
          {
              int n = ( x 13 ) ^ x;

              return ( 1.0 - ( ( n * ( n * n * 15731 + 789221 ) + 1376312589 ) & 0x7fffffff ) / 1073741824.0 );
          }
          protected double Noise( int x, int y )
          {
              int n = x + y * 57;
              n = ( n 13 ) ^ n ;

              return ( 1.0 - ( ( n * ( n * n * 15731 + 789221 ) + 1376312589 ) & 0x7fffffff ) / 1073741824.0 );
          }又一次证明了前面那段话,个人感觉这个x+y*57有点投影的意思。获取相应的噪点值。但噪点不是直接就能拿来用的
          /**//// summary
          /// Smoothed noise
          /// /summary
          protected double SmoothedNoise( double x )
          {
              int        xInt = (int) x;
              double    xFrac = x - xInt;

              return CosineInterpolate( Noise( xInt ) , Noise( xInt + 1 ), xFrac );
          }
          protected double SmoothedNoise( double x, double y )
          {
              int        xInt = (int) x;
              int        yInt = (int) y;
              double    xFrac = x - xInt;
              double    yFrac = y - yInt;

              // get four noise values
              double    x0y0 = Noise( xInt    , yInt );
              double    x1y0 = Noise( xInt + 1, yInt );
              double    x0y1 = Noise( xInt    , yInt + 1 );
              double    x1y1 = Noise( xInt + 1, yInt + 1) ;

              // x interpolation
              double    v1 = CosineInterpolate( x0y0, x1y0, xFrac );
              double    v2 = CosineInterpolate( x0y1, x1y1, xFrac );
              // y interpolation
              return CosineInterpolate( v1, v2, yFrac );
          }平滑的噪点,这个称呼似乎有点不协调,通过余弦插值,而不是离散余弦来运算。什么是余弦插值呢?         /**//// summary
          /// Cosine interpolation
          /// /summary
          protected double CosineInterpolate( double x1, double x2, double a )
          {
              double f = ( 1 - Math.Cos( a * Math.PI ) ) * 0.5;

              return x1 * ( 1 - f ) + x2 * f;
          }就是这个,有些事情,大师知道就够了,你就照着去做就行了,为什么?因为你可能一辈子也不明白,自然有人会去弄明白的,知识还在传承。就像你不必知道自己的胃酸比例,也可以放心的吃香喝辣一样,也不必担心子孙后代消化不良。有些事情不必强求,有点消极了,呵呵。
  画面并不难,只要把握好调用关系就可以了,另外像photoshop那样的悬浮窗体是最佳的选择我认为,         // Invert image
          private void invertColorFiltersItem_Click(object sender, System.EventArgs e)
          {
              ApplyFilter(new Invert());
          }

          // Apply filter on the image
          private void ApplyFilter(IFilter filter)
          {
              try
              {
                  // set wait cursor
                  this.Cursor = Cursors.WaitCursor;

                  // apply filter to the image
                  Bitmap newImage = filter.Apply(image);

                  if (host.CreateNewDocumentOnChange)
                  {
                      // open new image in new document
                      host.NewDocument(newImage);
                  }
                  else
                  {
                      if (host.RememberOnChange)
                      {
                          // backup current image
                          if (backup != null)
                              backup.Dispose();

                          backup = image;
                      }
                      else
                      {
                          // release current image
                          image.Dispose();
                      }

                      image = newImage;

                      // update
                      UpdateNewImage();
                  }
              }
              catch (ArgumentException)
              {
                  MessageBox.Show("Selected filter can not be applied to the image", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
              }
              finally
              {
                  // restore cursor
                  this.Cursor = Cursors.Default;
              }
          }调用顺畅的话,多少代码都不会觉得乱,对于初学者来说,要善用region。
  这里还有个DocumentsHost的概念,用它来承载图像文件,并将图像和窗体连接起来,很方便     /**//// summary
      /// IDocumentsHost interface
      /// Provides connectione between documents and the main widnow
      /// /summary
      public interface IDocumentsHost
      {
          bool CreateNewDocumentOnChange{get;}
          bool RememberOnChange{get;}

          bool NewDocument(Bitmap image);
          bool NewDocument(ComplexImage image);

          Bitmap GetImage(object sender, String text, Size size, PixelFormat format);
      }欢迎大家跟我讨论

  http://www.cnblogs.com/phono/archive/2006/09/07/phono.html

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com/webkaifa/)

来源:https://www.tulaoshi.com/n/20160219/1616464.html

延伸阅读
Microsoft .NET Romoting 框架简介 Paddy Srinivasan Microsoft Corporation 2001 年 1 月 摘要:本文介绍 Microsoft .NET Romoting 框架的基本原理。除了介绍组成 .NET Romoting 框架的主要组件外,还介绍 .NET Remoting 与分布式对象通信的几种方案。 目录 简介 .NET Remoting 对象 集成 .NET Remoting 对象 .NET Remoting 元数据和...
标签: Web开发
prototype.js是所有的基础 validation.js真正的验证框架文件,badqiu在原来的基础上增加了许多不错的功能 1:引用js文件 script"prototype.js"type="text/javascript"/script script"validation.js"type="text/javascript"/script 2:引用css文件 可以参加style_min.css中...
如果把Java媒体框架(http://java.sun.com/jmf)看作客户端安装的媒体播放机的话,那么这种框架并不是非常激动人心。它只支持少量媒体类型,并且事实上这些媒体类型都被象Windows媒体播放机以及QuickTime等其它的应用程序支持。 但是从内容供应商的观点来看,下面这个事实更加有意义:JMF在所有的Java类型中都可用,这使在客户端上不必...
C#使用的自动内存管理,使用开发者从繁重的手工分配、释放内存的操作解放出来。内存的自动管理是由垃圾回收器来执行。一个对象使用内存的生命周期是这样的: 当对象被创建时,它便分配了一定的内存,当构造器中的代码开始运行时,这个对象就“活”了。 当这个对象或者是它的任何一部分在可以预计的将来已经没有任何作用时,这个对象将不...
标签: Web开发
index.html 代码如下: html head titlejQuery Ajax 实例演示/title /head script src="./js/jquery.js" type="text/javascript"/script script type="text/javascript" $(document).ready(function(){//这个就是jQueryready ,它就像C语言的main 所有操作包含在它里面 $("#button_login").mousedown(function(){ login(); //点击ID...

经验教程

773

收藏

94
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部