標籤: 銷售文案

  • 2. 背包,隊列和棧

    2. 背包,隊列和棧

      許多基礎數據類型都和對象的集合有關。數據類型的值就是一組對象的集合,所有操作都是關於添加,刪除或是訪問集合中的對象。背包(Bag),隊列(Quene)和棧(Stack) 它們的不同之處在於刪除或者訪問對象的順序不同。

      

      1. API

      

      Stack 和 Quene 都含有一個能夠刪除集合中特定元素的方法。

      實現上面API需要高級語言的特性:泛型,裝箱拆箱,可迭代(實現 IEnumerable 接口)。

      

      1. 背包

      背包是一種不支持從中刪除元素的集合類型——它的目的就是幫助用例收集元素并迭代遍歷所有元素。用例也可以使用棧或者隊列,但使用 Bag 可以說明元素的處理順序不重要。

      

      2.先進先出隊列

      隊列是基於先進先出(FIFO)策略的集合類型。

     

      3. 下壓棧

      下壓棧(簡稱棧)是一種基於後進先出(LIFO)策略的集合類型。

      應用例子:計算輸入字符串  (1+((2+3)*(4*5)))表達式的值。

      使用雙棧解決:

        1. 將操作數壓入操作數棧;

        2. 將運算符壓入運算符棧;

        3. 忽略做括號;

        4. 在遇到右括號時,彈出一個運算符,彈出所需數量的操作數,並將運算符和操作數的運算結果壓入操作數棧。

     

      2.用數組實現

      實現下壓棧:

        //想要數據類型可迭代,需要實現IEnumerable
        public class ResizingStack<Item> : IEnumerable<Item>
        {
            private Item[] a = new Item[1];
            private int N = 0;
            public bool IsEmpty{ get {
                    return N == 0;
                } }
            public int Size { get {
                    return N;
                } }
            public int Count { get; set; }
    
            /// <summary>
            /// 使數組處於半滿
            /// </summary>
            /// <param name="max"></param>
            private void Resize(int max)
            {
                Count = 0;
                Item[] temp = new Item[max];
                for(var i = 0;i<N;i++)
                {
                    temp[i] = a[i];
                    Count++;
                }
                a = temp;
            }
    
            public void push(Item item)
            {
                if (N == a.Length)
                    Resize(a.Length * 2);
                a[N++] = item;
            }
    
            public Item Pop()
            {
                Item item = a[--N];
                a[N] = default(Item); //避免對象遊離
                if (N > 0 && N == a.Length / 4)
                    Resize(a.Length/2);
                return item;
            }
    
            IEnumerator<Item> IEnumerable<Item>.GetEnumerator()
            {
                return new ResizingStackEnumerator<Item>(a);
            }
    
            public IEnumerator GetEnumerator()
            {
                return new ResizingStackEnumerator<Item>(a);
            }
    
        }
        class ResizingStackEnumerator<Item> : IEnumerator<Item>
        {
            private Item[] a;
            private int N = 0;
            public ResizingStackEnumerator(Item[] _a)
            {
                a = _a;
                N = a.Length-1;
            }
    
            public object Current => a[N--];
    
            Item IEnumerator<Item>.Current => a[N--];
    
            public void Dispose()
            {
                throw new NotImplementedException();
            }
    
            public bool MoveNext()
            {
                return N > 0;
            }
    
            public void Reset()
            {
                throw new NotImplementedException();
            }
        }

      

      3.鏈表

      鏈表是在集合類的抽象數據類型實現中表示數據的另一種基礎數據結構。

      定義:鏈表是一種遞歸的數據結構,它或者指向空,或者指向另一個節點的引用,該節點含有一個泛型元素和一個指向另一個鏈表的引用。

        class Node<Item>
        {
            public Item item { get; set; }
            public Node<Item> Next { get; set; }
        }

      1.構造鏈表

      鏈表表示的是一列元素。

      根據遞歸的定義,只需要一個 Node 類型的變量就能表示一條鏈表,只要保證它的 Next 值是 null 或指向另一個 Node 對象,該對象的 Next 指向另一條鏈表。

      

     

      2.在表頭插入結點

      在鏈表列表中插入新節點的最簡單位置是開始。要在首結點為 first 的給定鏈表開頭插入字符串 not ,先將 first 保存在 oldfirst 中,然後將一個新結點賦予 first ,並將 first 的 item 設為 not, Next  設置為 oldfirst 。

      

      在鏈表開頭插入一個結點所需的時間和鏈表長度無關。

     

      3.從表頭刪除結點

      只需將 first 指向 first.next 即可。first 原來指向的對象變成了一個孤兒,垃圾回收機制會將其回收。

     

      同樣,該操作所需的時間和鏈表長度無關。

     

      4.在表尾插入結點

      當鏈表不止有一個結點時,需要一個指向鏈表最後結點的鏈接 oldlast,創建新的結點,last 指向新的最後結點。然後 oldlast.next  指向 last。

      當鏈表只有一個結點時,首結點又是尾結點。只需將 last 指向新的結點,然後 first.next 指向 last。

     

      5.其他位置的插入和刪除操作

      上述操作可以很容易的實現,但是下面的操作比較複雜:

        1. 刪除指定的結點

        2. 在指定結點前插入一個新結點

      這些操作需要我們遍歷鏈表,它所需的時間和鏈表的長度成正比。想要實現任意插入和刪除結點需要使用雙向鏈表,其中每個結點都含有兩個鏈接,分別指向上一個和下一個結點。

     

      6. 遍歷

      簡單實現:

        public class Bag<Item>
        {
            private Node<Item> first;
            public void Add(Item item)
            {
                Node<Item> oldFirst = first;
                first = new Node<Item>() { 
                    item = item,
                    Next = oldFirst
                };
    
            }
        }
                Bag<int> bags = new Bag<int>();
                for (var i = 0; i < 10; i++)
                {
                    bags.Add(i);
                }
    
                for (var x = bags.first; x != null; x = x.Next)
                {
                    Console.WriteLine(x.item);
                }

      

      實現 IEnumerable 接口 實現遍歷:

        public class Bag<Item>: IEnumerable<Item>
        {
            public Node<Item> first;
            public void Add(Item item)
            {
                Node<Item> oldFirst = first;
                first = new Node<Item>() { 
                    item = item,
                    Next = oldFirst
                };
    
            }
    
            public IEnumerator<Item> GetEnumerator()
            {
                return new LineEnumerator<Item>(first);
            }
    
            IEnumerator IEnumerable.GetEnumerator()
            {
                return new LineEnumerator<Item>(first);
            }
        }
    
        public class LineEnumerator<Item> : IEnumerator<Item>
        {
            public Node<Item> first;
            public LineEnumerator(Node<Item> _first)
            {
                first = _first;
            }
            public Item Current { get {
                    var oldfirst = first;
                    first = first.Next;
                    return oldfirst.item;
                } }
    
            object IEnumerator.Current => first;
    
            public void Dispose()
            {
                return;
            }
    
            public bool MoveNext()
            {
                if (first != null)
                    return true;
                return false;
            }
    
            public void Reset()
            {
                throw new NotImplementedException();
            }
        }
            public static void LineTest()
            {
                Bag<int> bags = new Bag<int>();
                for (var i = 0; i < 10; i++)
                {
                    bags.Add(i);
                }
    
                foreach(var bag in bags)
                {
                    Console.WriteLine(bag);
                }
            }

     

      4. 用鏈表實現背包

      見上述代碼。

     

      5. 用鏈表實現棧

      Stack API 中 Pop() 刪除一個元素,按照前面的從表頭刪除結點實現,Push() 添加一個元素,按照前面在表頭插入結點。 

        public class Stack<Item> : IEnumerable<Item>
        {
            public Node<Item> first;
            private int N;
    
    
            public bool IsEmpty()
            {
                return first == null; //或 N == 0
            }
    
            public int Size()
            {
                return N;
            }
    
            public void Push(Item item)
            {
                Node<Item> oldfirst = first;
                first = new Node<Item>() { 
                    item = item,
                    Next = oldfirst
                };
                N++;
            }
    
            public Item Pop()
            {
                Item item = first.item;
                first = first.Next;
                N--;
                return item;
            }
    
            public IEnumerator<Item> GetEnumerator()
            {
                return new StackLineIEnumerator<Item>(first);
            }
    
            IEnumerator IEnumerable.GetEnumerator()
            {
                return new StackLineIEnumerator<Item>(first);
            }
        }
    
        public class StackLineIEnumerator<Item> : IEnumerator<Item>
        {
            private Node<Item> first;
            public StackLineIEnumerator(Node<Item> _first)
            {
                first = _first;
            }
            public Item Current { get {
                    var oldfirst = first;
                    first = first.Next;
                    return oldfirst.item;
                } }
    
            object IEnumerator.Current => throw new NotImplementedException();
    
            public void Dispose()
            {
                return;
            }
    
            public bool MoveNext()
            {
                return first != null;
            }
    
            public void Reset()
            {
                throw new NotImplementedException();
            }
        }

      鏈表的使用達到了最優設計目標:

        1. 可以處理任意類型的數據;

        2. 所需的空間總是和集合的大小成正比;

        3. 操作所需的時間總是和集合的大小無關;

      

       6. 用鏈表實現隊列

      需要兩個實例變量,first 指向隊列的開頭,last 指向隊列的表尾。添加一個元素 Enquene() ,將結點添加到表尾(鏈表為空時,first 和 last 都指向新結點)。刪除一個元素 Dequene() ,刪除表頭的結點(刪除后,當隊列為空時,將 last 更新為 null)。

        public class Quene<Item> : IEnumerable<Item>
        {
            public Node<Item> first;
            public Node<Item> last;
            private int N;
    
            public bool IsEmpty()
            {
                return first == null;
            }
    
            public int Size()
            {
                return N;
            }
    
            public void Enquene(Item item)
            {
                var oldlast = last;
                last = new Node<Item>() { 
                    item = item,
                    Next = null
                };
    
                if (IsEmpty())
                    first = last;
                else
                    oldlast.Next = last;
                N++;
            }
    
            public Item Dequene()
            {
                if (IsEmpty())
                    throw new Exception();
                Item item = first.item;
                first = first.Next;
                if (IsEmpty())
                    last = null;
                N--;
                return item;
            }
    
            public IEnumerator<Item> GetEnumerator()
            {
                return new QueneLineEnumerator<Item>(first);
            }
    
            IEnumerator IEnumerable.GetEnumerator()
            {
                return new QueneLineEnumerator<Item>(first);
            }
        }
        public class QueneLineEnumerator<Item> : IEnumerator<Item>
        {
            private Node<Item> first;
            public QueneLineEnumerator(Node<Item> _first)
            {
                first = _first;
            }
            public Item Current { get {
                    var oldfirst = first;
                    first = first.Next;
                    return oldfirst.item;
                } }
    
            object IEnumerator.Current => throw new NotImplementedException();
    
            public void Dispose()
            {
                return;
            }
    
            public bool MoveNext()
            {
                return first != null ;
            }
    
            public void Reset()
            {
                throw new NotImplementedException();
            }
        }

       

      7. 總結

      在結構化存儲數據集時,鏈表是數組的一種重要的替代方式。

      數組和鏈表這兩種數據類型為研究算法和更高級的數據結構打下了基礎。

      基礎數據結構:

    數據結構 優點 缺點
    數組 通過索引可以直接訪問任意元素 在初始化時就需要知道元素的數量
    鏈表 使用的空間大小和元素數量成正比 需要同引用訪問任意元素

      

      在研究一個新的應用領域時,可以按照以下步驟識別目標,定義問題和使用數據抽象解決問題:

      1. 定義 API

      2. 根據特定的應用場景開發用例代碼

      3. 描述一種數據結構(即一組值的表示),並在 API 的實現中根據它定義類的實例變量。

      4. 描述算法,即實現 API,並根據它應用於用例

      5. 分析算法的性能

     

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    新北清潔公司,居家、辦公、裝潢細清專業服務

    ※別再煩惱如何寫文案,掌握八大原則!

    ※教你寫出一流的銷售文案?

    ※超省錢租車方案

  • MongoDB副本集replica set (二)–副本集環境搭建

    (一)主機信息

    操作系統版本:centos7 64-bit

    數據庫版本   :MongoDB 4.2 社區版

    ip hostname
    192.168.10.41 mongoserver1
    192.168.10.42 mongoserver2
    192.168.10.43 mongoserver3

    (二)副本集搭建過程

    首先需要在3台服務器上安裝MongoDB軟件,安裝過程見:https://www.cnblogs.com/lijiaman/p/12983589.html。安裝完成之後,即可進行後續的配置,具體操作如下:

    (1)在一台機器上創建keyfile

    openssl rand -base64 756 > /mongo/mongo-keyfile
    chmod 400 /mongo/mongo-keyfile

    (2)拷貝feyfile到所有節點

    scp /mongo/mongo-keyfile root@192.168.10.42:/mongo/
    scp /mongo/mongo-keyfile root@192.168.10.43:/mongo/

    (3)以啟用身份驗證的方式開啟所有節點
    這裏將所有參數設置到配置文件裏面,方便管理,配置文件如下:

    [root@mongodbserver1 mongo]# cat /etc/mongod.conf
    # mongod.conf
    
    # for documentation of all options, see:
    # http://docs.mongodb.org/manual/reference/configuration-options/
    
    # where to write logging data.
    systemLog:
    destination: file
    logAppend: true
    path: /mongo/mongod.log
    
    # Where and how to store data.
    storage:
    dbPath: /mongo/data
    journal:
    enabled: true
    # engine:
    # mmapv1:
    # wiredTiger:
    
    # how the process runs
    processManagement:
    fork: true # fork and run in background
    pidFilePath: /mongo/mongod.pid # location of pidfile
    
    # network interfaces
    net:
    port: 27017
    bindIp: 0.0.0.0 # Listen to local interface only, comment to listen on all interfaces.
    
    security:
    authorization: enabled                 # 啟用身份驗證
    keyFile: /mongo/mongo-keyfile         # 配置keyfile文件
     
    replication:
    replSetName: rstest                    # 設置副本集名稱

    然後啟動所有節點,以節點1為例:

    [root@mongodbserver1 mongo]# mongod -f /etc/mongod.conf

    (4)初始化副本集
    在其中一個節點執行以下腳本初始化副本集,只需在一個節點上執行即可。

    rs.initiate(
    {
    _id : "rstest",
    members: [
    { _id : 0, host : "192.168.10.41:27017" },
    { _id : 1, host : "192.168.10.42:27017" },
    { _id : 2, host : "192.168.10.43:27017" }
    ]
    }
    )

    參數含義:
    _id          :副本集的名稱
    members :副本集的成員信息

    在初始化時,會觸發投票選舉一個主節點,可以使用rs.status()來確定主節點成員

    rstest:SECONDARY> rs.status()
    ...
    "members" : [
    {
    "_id" : 0,
    "name" : "192.168.10.41:27017",
    "health" : 1,
    "state" : 1,
    "stateStr" : "PRIMARY",
    "uptime" : 280,
    "optime" : {
    "ts" : Timestamp(1592897767, 1),
    "t" : NumberLong(1)
    },
    "optimeDate" : ISODate("2020-06-23T07:36:07Z"),
    "syncingTo" : "",
    "syncSourceHost" : "",
    "syncSourceId" : -1,
    "infoMessage" : "",
    "electionTime" : Timestamp(1592897607, 1),
    "electionDate" : ISODate("2020-06-23T07:33:27Z"),
    "configVersion" : 1,
    "self" : true,
    "lastHeartbeatMessage" : ""
    },
    ...

    (5)創建管理員用戶
    第一個用戶必須要有創建其它用戶的權限,例如需要有userAdminAnyDatabase權限,並且需要創建在admin數據庫中。
    因為是在副本集上創建用戶,故要在主節點上執行。如創建root用戶

    use admin;
    
    db.createUser(
    {
    user:"root",
    pwd:"123456",
    roles:[{role:"userAdminAnyDatabase",db:"admin"}]
    }
    )

    (6)以管理員身份登錄數據庫
    通過以下方式以管理員身份登錄到數據庫

    mongo -u root -p 123456 --authenticationDatabase admin

    (7)創建一個集群管理員賬戶
    clusterAdmin角色被授予副本集操作的權限,如配置副本集。在admin數據庫中創建一個集群管理員並授予clusterAdmin角色。

    use admin
    
    db.createUser(
    {
    "user" : "replica",
    "pwd" : "replica",
    roles: [ { "role" : "clusterAdmin", "db" : "admin" } ]
    }
    )

    (8)要啟用身份驗證,需要重啟數據庫
    重啟完成后,就需要以用戶密碼方式登錄數據庫了,假如不使用用戶名密碼,可以登錄數據庫,但是無法訪問數據

    [root@mongodbserver2 mongo]# mongo
    MongoDB shell version v4.2.7
    connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
    Implicit session: session { "id" : UUID("d49b410b-a7af-4550-a455-faa82885517b") }
    MongoDB server version: 4.2.7
    rstest:PRIMARY> show dbs
    rstest:PRIMARY> 
    rstest:PRIMARY> db
    test

    只有使用了用戶名密碼,才能查到數據:

    [root@mongodbserver2 mongo]# mongo -u root -p 123456 --authenticationDatabase admin 
    MongoDB shell version v4.2.7
    connecting to: mongodb://127.0.0.1:27017/?authSource=admin&compressors=disabled&gssapiServiceName=mongodb
    Implicit session: session { "id" : UUID("a1f0da48-1266-4766-a9e4-32b97a46c3ec") }
    MongoDB server version: 4.2.7
    rstest:PRIMARY> 
    rstest:PRIMARY> show dbs
    admin 0.000GB
    config 0.000GB
    local 0.000GB

    【完】

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    新北清潔公司,居家、辦公、裝潢細清專業服務

    ※別再煩惱如何寫文案,掌握八大原則!

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※超省錢租車方案

    ※教你寫出一流的銷售文案?

  • OpenCV開發筆記(六十五):紅胖子8分鐘帶你深入了解ORB特徵點(圖文並茂+淺顯易懂+程序源碼)

    OpenCV開發筆記(六十五):紅胖子8分鐘帶你深入了解ORB特徵點(圖文並茂+淺顯易懂+程序源碼)

    若該文為原創文章,未經允許不得轉載
    原博主博客地址:https://blog.csdn.net/qq21497936
    原博主博客導航:https://blog.csdn.net/qq21497936/article/details/102478062
    本文章博客地址:https://blog.csdn.net/qq21497936/article/details/106926496
    各位讀者,知識無窮而人力有窮,要麼改需求,要麼找專業人士,要麼自己研究
    紅胖子(紅模仿)的博文大全:開發技術集合(包含Qt實用技術、樹莓派、三維、OpenCV、OpenGL、ffmpeg、OSG、單片機、軟硬結合等等)持續更新中…(點擊傳送門)

    OpenCV開發專欄(點擊傳送門)

    上一篇:《OpenCV開發筆記(六十四):紅胖子8分鐘帶你深入了解SURF特徵點(圖文並茂+淺顯易懂+程序源碼)》
    下一篇:持續補充中…

     

    前言

      紅胖子,來也!
      識別除了傳統的模板匹配之外就是體征點了,前面介紹了Suft特徵點,還有一個傳統的就會ORB特徵點了。
      其實識別的特徵點多種多樣,既可以自己寫也可以使用opencv為我們提供的,一般來說根據特徵點的特性和效率,選擇適合我們場景的特徵就可以了。
      本篇,介紹ORB特徵提取。

     

    Demo

      
      
      
      

     

    ORB特徵點

    概述

      ORB是ORiented Brief的簡稱,是briedf算法的改進版,於2011年在《ORB:an fficient alternative to SIFT or SURF》中提出。
    ORB算法分為兩部分,分別是特徵點提取和特徵點描述:

    • 特徵提取:由FAST(Features from Accelerated Segment Test)算法發展來的;
    • 特徵點描述:根據BRIEF(Binary Robust IndependentElementary Features)特徵描述算法改進的。

      ORB特徵是將FAST特徵點的檢測方法與BRIEF特徵描述子結合起來,並在它們原來的基礎上做了改進與優化。據說,ORB算法的速度是sift的100倍,是surf的10倍。

    Brief描述子

      該特徵描述子是在特徵點附近隨機選取若干點對,將這些點對的灰度值的大小,組合成一個二進制串,組合成一個二進制傳,並將這個二進制串作為該特徵點的特徵描述子。
      Brief的速度快,但是使用灰度值作為描述字計算的源頭,毫無疑問會有一些顯而易見的問題:

    • 旋轉后灰度變了導致無法識別,因其不具備旋轉不變形;
    • 由於是計算灰度,噪聲灰度化則無法去噪,所以對噪聲敏感;
    • 尺度不同影響灰度計算,所以也不具備尺度不變形;
      ORB是試圖使其具備旋轉不變性和降低噪聲敏感度而提出的。

    特徵檢測步驟

    步驟一:使用brief算子的方式初步提取。

      該步能夠提取大量的特徵點,但是有很大一部分的特徵點的質量不高。從圖像中選取一點P,以P為圓心畫一個半徑為N像素半徑的圓。圓周上如果有連續n個像素點的灰度值比P點的灰度值大或者小,則認為P為特徵點。
      

    步驟二:機器學習的方法篩選最優特徵點。

      通俗來說就是使用ID3算法訓練一個決策樹,將特徵點圓周上的16個像素輸入決策樹中,以此來篩選出最優的FAST特徵點。

    步驟三:非極大值抑制去除局部較密集特徵點。

      使用非極大值抑制算法去除臨近位置多個特徵點的問題。為每一個特徵點計算出其響應大小。計算方式是特徵點P和其周圍16個特徵點偏差的絕對值和。在比較臨近的特徵點中,保留響應值較大的特徵點,刪除其餘的特徵點。

    步驟四:使用金字塔來實現多尺度不變形。

    步驟五:使用圖像的矩判斷特徵點的旋轉不變性

      ORB算法提出使用矩(moment)法來確定FAST特徵點的方向。也就是說通過矩來計算特徵點以r為半徑範圍內的質心,特徵點坐標到質心形成一個向量作為該特徵點的方向。

    ORB類的使用

    cv::Ptr<cv::ORB> _pOrb = cv::ORB::create();
    std::vector<cv::KeyPoint> keyPoints1;
    //特徵點檢測
    _pOrb->detect(srcMat, keyPoints1);
    

    ORB相關函數原型

    static Ptr<ORB> create(int nfeatures=500,
                           float scaleFactor=1.2f,
                           int nlevels=8,
                           int edgeThreshold=31,
                           int firstLevel=0,
                           int WTA_K=2,
                           int scoreType=ORB::HARRIS_SCORE,
                           int patchSize=31,
                           int fastThreshold=20);
    
    • 參數一:int類型的nfeatures,用於ORB的,保留最大的關鍵點數,默認值500;
    • 參數二:float類型的scaleFactor,比例因子,大於1時為金字塔抽取比。的等於2表示經典的金字塔,每一個下一層的像素比上一層少4倍,但是比例係數太大了將顯著降低特徵匹配分數。另一方面,太接近1個比例因子這意味着要覆蓋一定的範圍,你需要更多的金字塔級別,所以速度會受影響的,默認值1.2f;
    • 參數三:int類型的nlevels,nlevels金字塔級別的數目。最小級別的線性大小等於輸入圖像線性大小/功率(縮放因子,nlevels-第一級),默認值為8;
    • 參數四:int類型的edgeThreshold,edgeThreshold這是未檢測到功能的邊框大小。它應該大致匹配patchSize參數。;
    • 參數五:int類型的firstLevel,要將源圖像放置到的金字塔級別。以前的圖層已填充使用放大的源圖像;
    • 參數六:int類型的WTA_K,生成定向簡短描述符的每個元素的點數。這個默認值2是指取一個隨機點對並比較它們的亮度,所以我們得到0/1的響應。其他可能的值是3和4。例如,3表示我們取3隨機點(當然,這些點坐標是隨機的,但是它們是由預定義的種子,因此簡短描述符的每個元素都是從像素確定地計算出來的矩形),找到最大亮度點和獲勝者的輸出索引(0、1或2)。如此輸出將佔用2位,因此需要一個特殊的漢明距離變量,表示為NORM_HAMMING2(每箱2位)。當WTA_K=4時,我們取4個隨機點計算每個點bin(也將佔用可能值為0、1、2或3的2位)。;
    • 參數七:int類型的scoreType,HARRIS_SCORES表示使用HARRIS算法對特徵進行排序(分數寫入KeyPoint::score,用於保留最佳nfeatures功能);FAST_SCORE是產生稍微不穩定關鍵點的參數的替代值,但計算起來要快一點;
    • 參數八:int類型的patchSize,定向簡短描述符使用的修補程序的大小。當然,在較小的金字塔層特徵覆蓋的感知圖像區域將更大;
    • 參數九:int類型的fastThreshold,快速閾值;
    void xfeatures2d::SURT::detect( InputArray image,
                                    std::vector<KeyPoint>& keypoints,
                                    InputArray mask=noArray() );
    
    • 參數一:InputArray類型的image,輸入cv::Mat;
    • 參數二:std::Vector類型的keypoints,檢測到的關鍵點;
    • 參數三:InputArray類型的mask,默認為空,指定在何處查找關鍵點的掩碼(可選)。它必須是8位整數感興趣區域中具有非零值的矩陣。;
    void xfeatures2d::SURT::compute( InputArray image,
                                     std::vector<KeyPoint>& keypoints,
                                     OutputArray descriptors );
    
    • 參數一:InputArray類型的image,輸入cv::Mat;
    • 參數二:std::Vector類型的keypoints,描述符不能為其已刪除計算的。有時可以添加新的關鍵點,例如:SIFT duplicates keypoint有幾個主要的方向(每個方向);
    • 參數三:OutputArray類型的descriptors,計算描述符;
    // 該函數結合了detect和compute,參照detect和compute函數參數
    void xfeatures2d::SURT::detectAndCompute( InputArray image,
                                              InputArray mask,
                                              std::vector<KeyPoint>& keypoints,
                                              OutputArray descriptors,
                                              bool useProvidedKeypoints=false );
    

    繪製關鍵點函數原型

    void drawKeypoints( InputArray image,
                        const std::vector<KeyPoint>& keypoints,
                        InputOutputArray outImage,
                        const Scalar& color=Scalar::all(-1),
                        int flags=DrawMatchesFlags::DEFAULT );
    
    • 參數一:InputArray類型的image,;
    • 參數二:std::Vector類型的keypoints,原圖的關鍵點;
    • 參數三:InputOutputArray類型的outImage,其內容取決於定義在輸出圖像。請參閱參數五的標誌flag);
    • 參數四:cv::Scalar類型的color,繪製關鍵點的顏色,默認為Scalar::all(-1)隨機顏色,每個點都是這個顏色,那麼隨機時,每個點都是隨機的;
    • 參數五:int類型的flags,默認為DEFAULT,具體參照DrawMatchesFlags枚舉如下:

     

    相關博客

      本源碼中包含了“透視變換”,請參照博文《OpenCV開發筆記(五十一):紅胖子8分鐘帶你深入了解透視變換(圖文並茂+淺顯易懂+程序源碼)》

     

    特徵點總結

      根據前面連續三篇的特徵點,我們其實可以猜到了所有的匹配都是這樣提取特徵點,然後使用一些算法來匹配,至於使用什麼特徵點提取就是需要開發者根據實際的經驗去選取,單一的特徵點/多種特徵點提取混合/自己寫特徵點等等多種方式去提取特徵點,為後一步的特徵點匹配做準備,特徵點通用的就到此篇,後續會根據實際開發項目中使用的到隨時以新的篇章博文去補充。
      《OpenCV開發筆記(六十三):紅胖子8分鐘帶你深入了解SIFT特徵點(圖文並茂+淺顯易懂+程序源碼)》
      《OpenCV開發筆記(六十四):紅胖子8分鐘帶你深入了解SURF特徵點(圖文並茂+淺顯易懂+程序源碼》
      《OpenCV開發筆記(六十五):紅胖子8分鐘帶你深入了解ORB特徵點(圖文並茂+淺顯易懂+程序源碼)》

     

    Demo源碼

    void OpenCVManager::testOrbFeatureDetector()
    {
        QString fileName1 = "13.jpg";
        int width = 400;
        int height = 300;
    
        cv::Mat srcMat = cv::imread(fileName1.toStdString());
        cv::resize(srcMat, srcMat, cv::Size(width, height));
    
        cv::String windowName = _windowTitle.toStdString();
        cvui::init(windowName);
    
        cv::Mat windowMat = cv::Mat(cv::Size(srcMat.cols * 2, srcMat.rows * 3),
                                    srcMat.type());
        cv::Ptr<cv::ORB> _pObr = cv::ORB::create();
    
        int k1x = 0;
        int k1y = 0;
        int k2x = 100;
        int k2y = 0;
        int k3x = 100;
        int k3y = 100;
        int k4x = 0;
        int k4y = 100;
        while(true)
        {
            windowMat = cv::Scalar(0, 0, 0);
    
            cv::Mat mat;
    
            // 原圖先copy到左邊
            mat = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 2),
                            cv::Range(srcMat.cols * 0, srcMat.cols * 1));
            cv::addWeighted(mat, 0.0f, srcMat, 1.0f, 0.0f, mat);
    
            {
                std::vector<cv::KeyPoint> keyPoints1;
                std::vector<cv::KeyPoint> keyPoints2;
    
                cvui::printf(windowMat, 0 + width * 1, 10 + height * 0, "k1x");
                cvui::trackbar(windowMat, 0 + width * 1, 20 + height * 0, 165, &k1x, 0, 100);
                cvui::printf(windowMat, 0 + width * 1, 70 + height * 0, "k1y");
                cvui::trackbar(windowMat, 0 + width * 1, 80 + height * 0, 165, &k1y, 0, 100);
    
                cvui::printf(windowMat, width / 2 + width * 1, 10 + height * 0, "k2x");
                cvui::trackbar(windowMat, width / 2 + width * 1, 20 + height * 0, 165, &k2x, 0, 100);
                cvui::printf(windowMat, width / 2 + width * 1, 70 + height * 0, "k2y");
                cvui::trackbar(windowMat, width / 2 + width * 1, 80 + height * 0, 165, &k2y, 0, 100);
    
                cvui::printf(windowMat, 0 + width * 1, 10 + height * 0 + height / 2, "k3x");
                cvui::trackbar(windowMat, 0 + width * 1, 20 + height * 0 + height / 2, 165, &k3x, 0, 100);
                cvui::printf(windowMat, 0 + width * 1, 70 + height * 0 + height / 2, "k3y");
                cvui::trackbar(windowMat, 0 + width * 1, 80 + height * 0 + height / 2, 165, &k3y, 0, 100);
    
                cvui::printf(windowMat, width / 2 + width * 1, 10 + height * 0 + height / 2, "k4x");
                cvui::trackbar(windowMat, width / 2 + width * 1, 20 + height * 0 + height / 2, 165, &k4x, 0, 100);
                cvui::printf(windowMat, width / 2 + width * 1, 70 + height * 0 + height / 2, "k4y");
                cvui::trackbar(windowMat, width / 2 + width * 1, 80 + height * 0 + height / 2, 165, &k4y, 0, 100);
    
                std::vector<cv::Point2f> srcPoints;
                std::vector<cv::Point2f> dstPoints;
    
                srcPoints.push_back(cv::Point2f(0.0f, 0.0f));
                srcPoints.push_back(cv::Point2f(srcMat.cols - 1, 0.0f));
                srcPoints.push_back(cv::Point2f(srcMat.cols - 1, srcMat.rows - 1));
                srcPoints.push_back(cv::Point2f(0.0f, srcMat.rows - 1));
    
                dstPoints.push_back(cv::Point2f(srcMat.cols * k1x / 100.0f, srcMat.rows * k1y / 100.0f));
                dstPoints.push_back(cv::Point2f(srcMat.cols * k2x / 100.0f, srcMat.rows * k2y / 100.0f));
                dstPoints.push_back(cv::Point2f(srcMat.cols * k3x / 100.0f, srcMat.rows * k3y / 100.0f));
                dstPoints.push_back(cv::Point2f(srcMat.cols * k4x / 100.0f, srcMat.rows * k4y / 100.0f));
    
                cv::Mat M = cv::getPerspectiveTransform(srcPoints, dstPoints);
                cv::Mat srcMat2;
                cv::warpPerspective(srcMat,
                                    srcMat2,
                                    M,
                                    cv::Size(srcMat.cols, srcMat.rows),
                                    cv::INTER_LINEAR,
                                    cv::BORDER_CONSTANT,
                                    cv::Scalar::all(0));
    
                mat = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 2),
                                cv::Range(srcMat.cols * 1, srcMat.cols * 2));
                cv::addWeighted(mat, 0.0f, srcMat2, 1.0f, 0.0f, mat);
    
                //特徵點檢測
                _pObr->detect(srcMat, keyPoints1);
                //繪製特徵點(關鍵點)
                cv::Mat resultShowMat;
                cv::drawKeypoints(srcMat,
                                 keyPoints1,
                                 resultShowMat,
                                 cv::Scalar(0, 0, 255),
                                 cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
                mat = windowMat(cv::Range(srcMat.rows * 2, srcMat.rows * 3),
                                cv::Range(srcMat.cols * 0, srcMat.cols * 1));
                cv::addWeighted(mat, 0.0f, resultShowMat, 1.0f, 0.0f, mat);
    
                //特徵點檢測
                _pObr->detect(srcMat2, keyPoints2);
                //繪製特徵點(關鍵點)
                cv::Mat resultShowMat2;
                cv::drawKeypoints(srcMat2,
                                 keyPoints2,
                                 resultShowMat2,
                                 cv::Scalar(0, 0, 255),
                                 cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
                mat = windowMat(cv::Range(srcMat.rows * 2, srcMat.rows * 3),
                               cv::Range(srcMat.cols * 1, srcMat.cols * 2));
                cv::addWeighted(mat, 0.0f, resultShowMat2, 1.0f, 0.0f, mat);
    
                cv::imshow(windowName, windowMat);
            }
            // 更新
            cvui::update();
            // 显示
            // esc鍵退出
            if(cv::waitKey(25) == 27)
            {
                break;
            }
        }
    }
    

     

    工程模板:對應版本號v1.59.0

      對應版本號v1.59.0

     

    上一篇:《OpenCV開發筆記(六十四):紅胖子8分鐘帶你深入了解SURF特徵點(圖文並茂+淺顯易懂+程序源碼)》
    下一篇:持續補充中…

     

    原博主博客地址:https://blog.csdn.net/qq21497936
    原博主博客導航:https://blog.csdn.net/qq21497936/article/details/102478062
    本文章博客地址:https://blog.csdn.net/qq21497936/article/details/106926496

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※教你寫出一流的銷售文案?

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※回頭車貨運收費標準

    ※別再煩惱如何寫文案,掌握八大原則!

    ※超省錢租車方案

  • FreeSql.Generator命令行代碼生成器是如何實現的

    FreeSql.Generator命令行代碼生成器是如何實現的

    目錄

    • FreeSql介紹
    • FreeSql.Generator
    • RazorEngine.NetCore
    • 源碼解析
    • FreeSql.Tools

    FreeSql

    FreeSql 是功能強大的對象關係映射技術(O/RM),支持 .NETCore 2.1+ 或 .NETFramework 4.0+ 或 Xamarin。

    有一個強大的ORM,也方便我們開發一個代碼生成器。

    一般情況下,我們開發數據庫相關的應用,主要分為三種code first、db first、model first

    我只用過前二種,

    • code first,代碼優先,數據庫都是根據實體類生成,所有的關係,可以是邏輯關聯,也可以是物理關聯。
    • DB First: 數據庫優先,直接設計表結構,用設計工具生成表,設計主鍵,外鍵、索引,關聯關係等。

    當我們使用DB First時,設計好的數據庫,我們怎麼生成一些實體類、通用的代碼、控制器、服務層、Dto呢。今天我來給大家介紹一下FreeSql項目中的一些工具。當然,不使用此ORM的小夥伴也能使用此工具,因為他是通用。

    FreeSql.Generator 命令行方式

    通過幾行命令,就可實現生成項目中通用的代碼結構,不需要複製一段代碼后修改,加快開發速度,減少重複勞動,少用一根頭髮。

    由於每個人的項目結構,代碼位置各不相同,對於ORM來說,不同的業務邏輯各不相同,所以該項目沒有相應的模板,相信使用過Razor的同學一定能實現自己的模板。

    1-2年前,我和一個學長也寫過代碼生成器,這裏分享一下當時做項目時的一些模板,https://github.com/i542873057/SJNScaffolding/tree/master/SJNScaffolding.RazorPage/Templates,該項目是基於 . NET Core+Razor Page,由於已離職,所以沒有繼續維護,這些模板都和ABP相關,當時提取了一些通用的功能,單表操作,可以直接生成前後端功能,只需要在word中按統一的格式寫好數據字典的文檔,直接複製到系統,即可根據空格,定義類型等方式解析字段。

    回到FreeSql.Generator 命令行

    • 對於此工具的使用可參考 https://github.com/dotnetcore/FreeSql/wiki/DbFirst
    • 源碼位置 https://github.com/dotnetcore/FreeSql/tree/master/Extensions/FreeSql.Generator
    • 前提是本地安裝了.net core 3.1 的sdk.

    怎麼使用呢。

    1. 安裝 dotnet-tool 生成實體類
    dotnet tool install -g FreeSql.Generator
    
    1. 新建目錄,在地址欄輸入 cmd 快速打開命令窗口,輸入命令:
    FreeSql.Generator --help
    

    我們可以看到

    C:\Users\igeekfan\Desktop\code>FreeSql.Generator --help
            ____                   ____         __
           / __/  ____ ___  ___   / __/ ___ _  / /
          / _/   / __// -_)/ -_) _\ \  / _ `/ / /
         /_/    /_/   \__/ \__/ /___/  \_, / /_/
                                        /_/
    
    
      # Github # https://github.com/2881099/FreeSql v1.5.0
    
        使用 FreeSql 快速生成數據庫的實體類
    
        更新工具:dotnet tool update -g FreeSql.Generator
    
    
      # 快速開始 #
    
      > FreeSql.Generator -Razor 1 -NameOptions 0,0,0,0 -NameSpace MyProject -DB "MySql,Data Source=127.0.0.1;..."
    
         -Razor 1                  * 選擇模板:實體類+特性
    
         -Razor 2                  * 選擇模板:實體類+特性+導航屬性
    
         -Razor "d:\diy.cshtml"    * 自定義模板文件
    
         -NameOptions              * 總共4個布爾值,分別對應:
                                   # 首字母大寫
                                   # 首字母大寫,其他小寫
                                   # 全部小寫
                                   # 下劃線轉駝峰
    
         -NameSpace                * 命名空間
    
         -DB "MySql,Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=數據庫;Charset=utf8;SslMode=none;Max pool size=2"
    
         -DB "SqlServer,Data Source=.;Integrated Security=True;Initial Catalog=數據庫;Pooling=true;Max Pool Size=2"
    
         -DB "PostgreSQL,Host=192.168.164.10;Port=5432;Username=postgres;Password=123456;Database=數據庫;Pooling=true;Maximum Pool Size=2"
    
         -DB "Oracle,user id=user1;password=123456;data source=//127.0.0.1:1521/XE;Pooling=true;Max Pool Size=2"
    
         -DB "Sqlite,Data Source=document.db"
    
         -DB "Dameng,server=127.0.0.1;port=5236;user id=2user;password=123456789;database=2user;poolsize=2"
                                   Dameng 是國產達夢數據庫
    
         -Filter                   Table+View+StoreProcedure
                                   默認生成:表+視圖+存儲過程
                                   如果不想生成視圖和存儲過程 -Filter View+StoreProcedure
    
         -Match                    正則表達式,只生成匹配的表,如:dbo\.TB_.+
    
         -FileName                 文件名,默認:{name}.cs
    
         -Output                   保存路徑,默認為當前 shell 所在目錄
                                   推薦在實體類目錄創建 gen.bat,雙擊它重新所有實體類
    
    • 更新命令行
    dotnet tool update -g FreeSql.Generator
    
    1. 這裏lin-cms-dotnetcore這個項目來測試。

    • 數據庫表名是下劃線,字段也是下劃線方式。
    • -Razor 指定 第一個模板
    • -NameOptions 0,0,0,1 最後一個1,代表 下劃線轉駝峰,滿足C#命名規則
    • -NameSpace 指定了命名空間 LinCms.Core.Entities
    • -DB 就是數據庫的相關配置
    • mysql 本地地址 127.0.0.1 3306端口 用戶名 root 密碼123456 數據庫 lin-cms
    • -Match book 這樣就能只生成book,支持正則表達式,如 -Math lin_user 就會生成以lin_user開頭的表。如dbo.TB_.+,會生成以TB開頭的表。即只生成匹配的表
    1. 執行此命令。
    FreeSql.Generator -Razor 1  -NameOptions 0,0,0,1 -NameSpace LinCms.Core.Entities -DB "MySql,Data Source=127.0.0.1;Port=3306;User ID=root;Password=123456;Initial Catalog=lincms;Charset=utf8;SslMode=none;Max pool size=2"
    

    這時候代碼已經生成了

    其中一個代碼 生成如下。這些類是partial ,熟悉C#的同學,應該知道,類的定義使用此關鍵字,我們能在不同的地方為該類擴展。以防止重新同步數據庫的結構時,丟失改動的字段。

    namespace LinCms.Core.Entities {
    
    	[JsonObject(MemberSerialization.OptIn), Table(Name = "book")]
    	public partial class Book {
    
    		/// <summary>
    		/// 主鍵Id
    		/// </summary>
    		[JsonProperty, Column(Name = "id", IsPrimary = true, IsIdentity = true)]
    		public long Id { get; set; }
    
    		[JsonProperty, Column(Name = "author", DbType = "varchar(20)")]
    		public string Author { get; set; } = string.Empty;
    
    		[JsonProperty, Column(Name = "image", DbType = "varchar(50)")]
    		public string Image { get; set; } = string.Empty;
    
            //更多xxx
    	}
    
    }
    
    
    • 最終效果圖如下

    此時會生成二個文件
    __重新生成.bat,下次重新點擊他就能重新生成實體類了。

    FreeSql.Generator -Razor "__razor.cshtml.txt" -NameOptions 1,1,0,1 -NameSpace MyProject -DB "MySql,Data Source=127.0.0.1;Port=3306;User ID=root;Password=123456;Initial Catalog=lincms;Charset=utf8;SslMode=none;Max pool size=2" -FileName "{name}.cs"
    

    上面的命令-Razor 指定了這個txt文件 __razor.cshtml.txt

    我們可以定義自己的模板,以生成符合自已業務的的代碼,從而實現快速開發。

    我們可以看下模板中的文件內容,他就是asp.net下的mvc 結構下的razor後端模板渲染,把這個.txt後綴去掉,就很明了了。對於asp.net mvc的razor,我們可以將控制器下方法的值替換掉cshtml中的值。這個過程是有一個類庫在幫我們實現的,叫RazorEngine,不過那個是.net framework下的實踐。.NET Framework 下的RazorEngine代碼生成介紹

    @using FreeSql.DatabaseModel;@{
    var gen = Model as RazorModel;
    
    Func<string, string> GetAttributeString = attr => {
    	if (string.IsNullOrEmpty(attr)) return null;
    	return string.Concat(", ", attr.Trim('[', ']'));
    };
    Func<DbColumnInfo, string> GetDefaultValue = col => {
        if (col.CsType == typeof(string)) return " = string.Empty;";
        return "";
    };
    }
    //xxx
    namespace @gen.NameSpace {
    
    @if (string.IsNullOrEmpty(gen.table.Comment) == false) {
    	@:/// <summary>
    	@:/// @gen.table.Comment.Replace("\r\n", "\n").Replace("\n", "\r\n		/// ")
    	@:/// </summary>
    }
    	[JsonObject(MemberSerialization.OptIn)@GetAttributeString(gen.GetTableAttribute())]
    	public partial class @gen.GetCsName(gen.FullTableName) {
    
    	@foreach (var col in gen.columns) {
    
    		if (string.IsNullOrEmpty(col.Coment) == false) {
    		@:/// <summary>
    		@:/// @col.Coment.Replace("\r\n", "\n").Replace("\n", "\r\n		/// ")
    		@:/// </summary>
    		}
    		@:@("[JsonProperty" + GetAttributeString(gen.GetColumnAttribute(col)) + "]")
    		@:public @gen.GetCsType(col) @gen.GetCsName(col.Name) { get; set; }@GetDefaultValue(col)
    @:
    	}
    	}
    @gen.GetMySqlEnumSetDefine()
    }
    

    RazorEngine.NetCore

    到了.NET Core時代,我看了下FreeSql.Generator用的這個類庫RazorEngine.NetCore,實現動態操作cshtml,生成需要的文本。

    Razor Engine是基於微軟Razor解析的模板引擎,它允許你使用Razor語法構建動態模板,你只需要使用Engine的靜態方法,Engine.Razor.RunCompile等。

    創建一個控制台應用,然後安裝包。

    Install-Package RazorEngine.NetCore
    
    using RazorEngine;
    using RazorEngine.Templating; // For extension methods.
    
    
    string template = "Hello @Model.Name, welcome to RazorEngine!";
    var result = Engine.Razor.RunCompile(template, "templateKey", null, new { Name = "World" });
    
    Console.WriteLine(result);
    
    • 輸出如下內容
    Hello World, welcome to RazorEngine!
    

    此處使用的RunCompile方法是擴展方法,您需要引用RazorEngine.Templating命名空間。

    The “templateKey” 保持唯一值,比如使用guid值。字符串,並且你可以根據此字符串key重新運行緩存的模板。

    如果再次根據此key,可使用原本的模板。

    var result = Engine.Razor.Run("templateKey", null, new { Name = "Max" });
    
    • 會輸出如下內容
    Hello Max, welcome to RazorEngine!
    

    上面中的RunCompile第三個參數,傳null,因為我們第四個參數使用的是匿名類,

    根目錄創建一個HelloWord.cshtml,要選擇屬性,->如果較新則複製 內容,

    Hello @Model.Name, welcome to RazorEngine!
    

    控制台如下代碼。

    string templateFilePath = "HelloWorld.cshtml";
    var templateFile = File.ReadAllText(templateFilePath);
    string templateFileResult = Engine.Razor.RunCompile(templateFile, Guid.NewGuid().ToString(), null, new
    {
        Name = "World"
    });
    
    Console.WriteLine(templateFileResult);
    
    • 控制台輸出
    Hello World, welcome to RazorEngine!
    
    • 使用強類型 CopyRightUserInfo.cs生成一個版權所有
    using System;
    namespace OvOv.Razor
    {
        public class CopyRightUserInfo
        {
            public string UserName { get; set; }
            public string EmailAddress { get; set; }
            public DateTime CreateTime { get; set; }
            public string FileRemark { get; set; }
        }
    
    }
    

    根目錄創建一個CopyRightTemplate.cshtml,要選擇屬性,->如果較新則複製 內容,

    @{
        var gen = Model as OvOv.Razor.CopyRightUserInfo;
    }
    //=============================================================
    // 創建人:            @gen.UserName
    // 創建時間:          @gen.CreateTime
    // 郵箱:             @gen.EmailAddress
    //==============================================================
    
    

    控制台如下代碼。

    string copyRightTemplatePath = "CopyRightTemplate.cshtml";
    var copyRightTemplate = File.ReadAllText(copyRightTemplatePath);
    string copyRightResult = Engine.Razor.RunCompile(copyRightTemplate, Guid.NewGuid().ToString(), typeof(CopyRightUserInfo), new CopyRightUserInfo
    {
        CreateTime = DateTime.Now,
        EmailAddress = "710277267@qq.com",
        UserName = "IGeekFan"
    });
    Console.WriteLine(copyRightResult);
    
    Console.ReadKey();
    
    • 控制台輸出
    //=============================================================
    // 創建人:            IGeekFan
    // 創建時間:          2020/6/23 18:14:08
    // 郵箱:             710277267@qq.com
    //==============================================================
    

    全放到控制台下,輸出如下結果。代碼生成器最重要的一點解決了,我們就能實現自己的代碼生成器,先構建自己的模板,實現輸入(命令行,WPF,WEB端及更多),輸出(生成文件)。

    • 以上源碼已放到示例代碼中 https://github.com/luoyunchong/dotnetcore-examples/blob/master/aspnetcore-freesql/OvOv.Razor/Program.cs

    源碼解析

    首先這是一個控制台應用,Main(string[] args)可接收多個參數。

    1. 處理無參數,–help
    2. 處理args數組,解析出所有的參數,如果沒有設置,則為默認值。(處理一些參數異常問題)最重要的是根據-Razor,選定對應的模板。
    ArgsRazor=""//根據-Razor  1 不是2 還是模板的路徑,取出的模板文本值。
    var razorId = Guid.NewGuid().ToString("N");
    RazorEngine.Engine.Razor.Compile(ArgsRazor, razorId);
    
    1. 根據數據庫連接串,取出參數過濾后的表,視圖,存儲過程
    2. 循環數據庫的表等,
    • model為模板中需要的數據
    • razorId與上文的razorId相同,
    • sw為生成后的文本保存的值。
    var sw = new StringWriter();
    var model = new RazorModel(fsql, ArgsNameSpace, ArgsNameOptions, tables, table);
    RazorEngine.Engine.Razor.Run(razorId, sw, null, model);
    
    1. 將sw字符串保存生成類.cs文件(根據參數配置生成文件名)
    2. 另外生成一個__重新生成.bat,__razor.cshtml.txt,方便後續用戶重新生成實體類。

    FreeSql.Tools

    這是 FreeSql 衍生出來的輔助工具包,內含生成器等功能;作者:mypeng1985
    因為這個不兼容mac,linux,所以作者建議使用dotnet-tool 命令行工具生成實體類,從而支持MAC/Linux系統。對於不是使用FreeSql的開發者,也能使用此工具,你只需要修改對應的模板即可。

    使用方式:不多介紹。

    • https://github.com/2881099/Freesql.tools
    • 分為WPF ,WinForm + DSkin 版本(套網頁)
    • 看了下代碼,底層生成代碼邏輯也是用的RazorEngine .NET Framework 下的RazorEngine代碼生成介紹

    FreeSql官方群 4336577

    預覽圖

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※超省錢租車方案

    ※別再煩惱如何寫文案,掌握八大原則!

    ※回頭車貨運收費標準

    ※教你寫出一流的銷售文案?

  • 緬甸小象成功獲救 凸顯盜獵危機仍在

    摘錄自2019年10月2日自由時報報導

    據《路透》報導,緬甸Wingabaw大象庇護營上個月在該國西南部森林,拯救了一隻誤入盜獵者陷阱的4個月大幼象,她的左前腿遭陷阱夾傷,父母推測也慘遭盜獵者殺害。

    現在這隻被命名為艾雅‧賽恩(Ayeyar Sein),雖然腳上還戴著以竹子和繃帶做成的夾板,但在定期清理傷口之下,賽恩的恢復狀況良好,食慾也逐漸恢復正常。

    據專家2018年統計報告指出,目前緬甸僅存1400至2000頭野生象,並有5000頭大象遭囚禁,凸顯出緬甸所面臨的盜獵危機。

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※帶您來了解什麼是 USB CONNECTOR  ?

    ※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

    ※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

    ※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※教你寫出一流的銷售文案?

  • 沒有廁所的大廈──日本核廢燃料棒處理概況

    文:宋瑞文

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

    南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

    ※教你寫出一流的銷售文案?

    ※超省錢租車方案

  • 中國新鑽井平台是否進入南海 越南密切關注

    摘錄自2019年10月3日中央社報導

    中國新鑽井平台「海洋石油982」傳出在海上準備運作,或許會在南海使用。越南政府今天表示,正在查證這個消息,強調各方在南海的任何行動都要遵守1982年聯合國海洋法公約。

    越南外交部今天在河內舉行例行記者會,發言人黎氏秋恆(Le Thi Thu Hang)回答記者提問時表示,越南相關部門密切關注且正在查證中華人民共和國可能將「海洋石油982」鑽井平台駛入南海海域(越稱東海)的消息。

    黎氏秋恆說:「越南認為,(各方)在東海的任何行動都要遵守1982年聯合國海洋法公約,包括遵守沿海國家主權、主權權利和管轄權在內,為維護區域和平與穩定做出切實貢獻。」

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

    南投搬家公司費用需注意的眉眉角角,別等搬了再說!

    新北清潔公司,居家、辦公、裝潢細清專業服務

    ※教你寫出一流的銷售文案?

  • 南北韓非軍事區 驚見野豬患有非洲豬瘟

    摘錄自2019年10月4日自由時報報導

    據報導,北韓於5月份出現首起非洲豬瘟病例,韓國則努力地避免疫情擴散過來,甚至在邊界建起圍欄。韓國各處養豬場已確認有13起病例,不過,長4公里、佈滿地雷、守衛嚴密的南北韓非軍事區(DMZ)更發現患有非洲豬瘟的野豬,目前推測韓國的疫情可能是被帶原的野豬給傳染過來的。

    DMZ向來避免擦槍走火,但韓國軍方已被授權殺死穿越DMZ的野豬。

     

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    新北清潔公司,居家、辦公、裝潢細清專業服務

    ※別再煩惱如何寫文案,掌握八大原則!

    ※教你寫出一流的銷售文案?

    ※超省錢租車方案

  • 米塔颱風襲南韓已釀9死 日本高知暴雨淹大水

    摘錄自2019年10月3日自由時報報導

    米塔颱風在週三晚間襲擊南韓南部,南韓南部港口城市釜山發生土石流,南韓行政安全部3日表示,截至下午,全國共有9人喪生,但傷亡人數預計會在攀升,因為還有數人下落不明。

    南韓國防部表示,米塔風災造成1000多棟房屋損壞,超過1500人提前被撤離。

    米塔離開朝鮮半島後,已往日本西部前進,同樣帶來驚人雨量,日本氣象廳警告,儘管米塔颱風可能在4日減弱為溫帶氣旋,但朝著日本北部前進時,強風豪雨可能引發洪水、土石流等災情。

    【動画】高知県内で大雨 道路冠水も

    — 高知新聞 (公式)Kochinews (@Kochi_news)

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    新北清潔公司,居家、辦公、裝潢細清專業服務

    ※別再煩惱如何寫文案,掌握八大原則!

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※超省錢租車方案

    ※教你寫出一流的銷售文案?

  • 世界最毒蕈類 澳洲首度發現「火焰茸」

    摘錄自2019年10月3日自由時報報導

    澳洲詹姆士庫克大學(James Cook University)3日宣布,當地攝影師在凱恩斯(Cairns)的郊區拍到「火焰茸」,經科學家確定是一種又被稱為毒火珊瑚(Poison Fire Coral)的真菌。

    外媒稱,火焰茸的原生棲地在日本和南韓的山區,這種鮮紅色的真菌經常被誤認為是可食用的紅珊瑚菌(Clavulinopsis miyabeana)、冬蟲夏草,誤食而中毒甚至死亡。

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※教你寫出一流的銷售文案?

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※回頭車貨運收費標準

    ※別再煩惱如何寫文案,掌握八大原則!

    ※超省錢租車方案