国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

基于.NET數字處理程序的框架設計

2019-11-18 17:01:09
字體:
來源:轉載
供稿:網友

        接觸數字圖像處理最早是在高中,那時候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 );

            // 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.survivalescaperooms.com/phono/archive/2006/09/07/phono.html


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 寻甸| 古蔺县| 衡水市| 汝阳县| 韶山市| 突泉县| 右玉县| 任丘市| 伊川县| 剑河县| 高青县| 香河县| 虎林市| 汉源县| 波密县| 越西县| 湟中县| 沙雅县| 应用必备| 锡林浩特市| 邵武市| 什邡市| 兴文县| 商水县| 柳林县| 衡阳县| 天峨县| 门头沟区| 金堂县| 昌平区| 城市| 沭阳县| 南部县| 潮州市| 竹溪县| 乌拉特中旗| 闽侯县| 房产| 浮梁县| 沾益县| 水城县|