1. 程式人生 > >種子點生長演算法上——二維種子點生長

種子點生長演算法上——二維種子點生長

下文提到的種子點生長演算法,包括泛洪法,掃描線法,區段法三種。文字先從最簡單的泛洪法入手介紹種子點生長演算法的相關概念。之後進一步討論了掃描線法和區段法,同時提供了實驗資料驗證其中的一些結論。本文按照如下的結構來介紹:

  1. 泛洪法
  2. 掃描線法
  3. 區段法
  4. 演算法分析對比以及實驗

一、泛洪法

  1.簡介

  泛洪法,又叫Floodfill演算法,屬於影象處理演算法,是從影象中尋找連通區域的經典演算法。因其思路類似洪水從一個區域擴散到所有能到達的區域而得名。可能很多人都有接觸過這個演算法,因為大多數人都使用過Windows自帶的畫圖工具或者Photoshop,知道里裡面有一種工具叫做“油漆桶”。實際上這個油漆桶在使用的時候,他的背後就是執行了二維的泛洪法。使用油漆桶的時候,你所需要做的事,首先是選擇一個你需要的顏色,然後通過你的肉眼在你想要填充的區域選擇(點選)一個點,這個點就是所謂的“種子點”,然後這些影象處理軟體就會自動幫你把所有和這個種子點在一個“聯通區域”的點都塗成你需要的顏色。

  泛洪法有幾個重要的要素如下:

1.領域選擇策略。即四鄰域還是八鄰域,亦或是使用者自定義的鄰域。

2.包含策略。即一個點是否能納入當前聯通區域?是要求顏色等於某值,還是在某個範圍內?也可以採用補集即“拒絕策略”,決定什麼樣的點不能加入。

3.生長方式。深度優先還是廣度優先。

  2.關於鄰域

  平面二維泛洪法一般是用兩種領域選擇策略,一種是四領域,一種是八領域。首先要說明一下鄰域的概念。鄰域的概念是相對於一個點而言的,對於影象上的一個畫素P,跟它相關的屬性有他的橫縱位置XY,畫素值V,鄰域SS也是畫素的集合,S裡面是和P位置相鄰的畫素,相鄰有很多的定義方法,如下文涉及的四鄰域和八鄰域。

  P的四鄰域可以表示為:

    S=Adj4(P)=P0(P.X-1,P.Y)P1(P.X+1,P.Y)P2(P.X,P.Y-1)P3(P.X,P.Y+1)}。

  即四個鄰域分別表示當前畫素上下左右的相鄰畫素(若當前畫素為邊界畫素,則應從中去掉超出邊界的畫素)。

  P的八鄰域可以表示為:

    S=Adj8(P)=P0(P.X-1,P.Y)P1(P.X+1,P.Y)P2(P.X,P.Y-1)P3(P.X,P.Y+1)P4(P.X-1,P.Y-1)P5(P.X+1,P.Y+1)P6(P.X+1,P.Y-1)P7(P.X-1,P.Y+1)

}。

  相對四鄰域多了斜相鄰的左上、右上、左下、右下畫素。

  使用泛洪法尋找聯通區域時,採用四鄰域和八鄰域的策略結果往往會有所不同,一般來講,採用八鄰域的泛洪法找到的區域會比四鄰域的大。原因是在不同的鄰域策略下,對“聯通區域”的定義是不同的。八領域的聯通區域在生長的時候,包含條件更寬鬆(因為斜對面有同色畫素也認為是相鄰,在同一個區域裡),所以區域也會更大。當然兩種策略也可以產生一樣大的區域,這要看具體的影象。

  下圖是泛洪法選擇四個方向擴散的例子:

 

  還需要注意的是:其實鄰域也不止這兩種,還可以自己定義。比如也可以定義一個2鄰域,只有一個畫素左右兩個畫素才算做“鄰居”這樣也是可以的。至於這樣的鄰域什麼時候能派上用場,那就得看應用場合了。
  3.關於生長方式
  泛洪法最簡單的實現方法是採用深度優先搜尋的遞迴方法,也可以採用廣度優先搜尋的迭代來實現。

FloodFill(P,bitmap,replaceColor,targetColor)
  foreach point T in Adj(P)
      if color at T is equal to targetColor
      set color at T to replaceColor
      FloodFill(T,bitmap,replaceColor,targetColor)
  end

  如果不希望使用遞迴的演算法:可以使用棧或者佇列的結構,相關的虛擬碼如下:

複製程式碼
FloodFill(seed,bitmap,replaceColor)
    get targetColor from bitmap using seed position
    set color at seed point to replaceColor
    set queue Q to empty
    push seed into Q
    while Q is not empty
        pop a point P from Q
        foreach point T in Adj(P)
            if color at T is equal to targetColor
                set color at T to replaceColor
                push T into Q
    end 
複製程式碼

  上面的虛擬碼使用的是佇列Q作為容器,這就是所謂的廣度搜索策略。而若是將上面的Q宣告為LIFO的棧S,實際上演算法執行的過程就和遞迴的演算法一樣了。下圖分別是採用佇列和棧的結構,演算法執行過程的演示,從圖中可以很好的看出,佇列式的泛洪法更加與“泛洪”相像,是向四周洪水一樣擴散;而棧式的泛洪法就是“一路走到黑,沒路再回頭”式的擴散,就像仙劍裡走迷宮一樣。

 
佇列式生長 棧式生長

  4.使用點陣圖標記表拓展的更一般的泛洪法

  在實際做影象處理的演算法中,有時目的並不是為了對影象進行修改,而是為了獲取影象的資訊,影象本身必須保證不能被修改,這時就有引入更具一般性的泛洪法的必要。從上面的介紹知道,經典的泛洪法,其實是對原影象的填充,執行過程中明顯的修改了影象,每找到一個點就把這個點染上新顏色。拓展的泛洪法的演算法思路和上文所說的泛洪法是一樣的,但為了在不修改原始圖片的情況下尋找連通區域(這樣的應用可能只是把聯通區域的點集求出來或者統計區域點數,並不是要填充區域),所以必須引入標記的機制來判斷當前點是否已經被包含入區域,這個機制是必須的。因為仔細分析泛洪法的執行過程就可以知道,一個點可能被考察不止一次,同一個點可能會被不同方向的鄰居來的“水”給衝到。在經典泛洪法中,當一個點被塗為目標顏色時,即表明它已被納入聯通區域。但當在不能夠修改原始影象的場合,想要求出從一個種子點出發的聯通區域,除了使用原始影象的副本之外,往往更好的辦法是使用“標記位圖表”。
  標記位圖表可以理解為長寬和原始影象一樣,元素值為bool的二維陣列,它是用於對應原影象的相同位置的畫素的,在泛洪法執行的過程中,通過標記已經納入聯通區域的點,使得新考察的點可以通過訪問這標記的值來判斷是否已被納入聯通區域。這個位圖表的實現可以有比較靈活的方式,若空間緊張,可以使用按bit表示的陣列,如std::vector就是標準庫實現好的一個動態大小的點陣圖結構,他的一個bool元素在記憶體中實際上只佔了1位(注意c++的std::vector和其他的模版例項化的類std::vector不同,具體資訊請查詢相關資料),使用這樣的結構作為標記位圖表的實現,使得表只需要佔據 1/8n的原圖片空間(n是圖片的位數除以8)。C#語言也提供了BitArray類實現位陣列,和std::vector一樣。至於如何使用一維陣列對應二維影象中的點,這個技巧是影象處理鄰域的常識,就是所謂的“i+j*width”方式,詳情參考第一篇“影象資料的組織方式”。
  那麼,把泛洪法的概念括寬之後,其實,可以將泛洪法的虛擬碼用以下方式來描述:

複製程式碼
FloodFill(seed,bitmap,includePredicate,process)
 set all postions of flagMap to false
 set container Q to empty.
 push seed into Q
 set seed position in flagMap to true
 process(seed)
 while Q is not empty
  pop a point P from Q
  foreach point T in Adj(P)
     if includePredicate(T) is true
     set position of T in flagMap to true
     push T into Q
     process(T)
 end
複製程式碼

  其中includePredicate是判斷新點能否加入當前區域的函式。演算法把這種類似函式的東西當引數,所以可以理解其為C++中的函式指標、c#中的委託這樣的引數形式。對於一般的泛洪法,就是畫素點在影象邊界之內的顏色相等。Process是處理當前新加入的畫素的函式,就是對當前畫素的處理,對於一般泛洪法就是把這個畫素的顏色改為目標顏色。之所以把includePredicate和Process當作引數傳遞,是為了方便拓展,因為演算法的使用者可能不需要預設的生長策略(如畫素值相等)和納入處理(如染色),而是要自己定義自己的生長策略和納入處理,所以這兩個函式讓使用者去寫更為合適。
  使用這樣的形式拓展經典的泛洪法,使得泛洪法的演算法思想可以推廣到很多應用上去。比如影象分割中的區域生長演算法,實際上就是泛洪法的變形。他的includePedicate是判斷新點在影象邊界之內且新點T的畫素值和為了找到它所出發的舊點P的畫素值之差小於一個給定值。同時,這個演算法思想也可以聯絡到很多非影象處理領域的演算法思想。比如對資料結構中“圖”結構的遍歷,實際上無論是深度還是廣度遍歷,演算法的思想都和拓展的的泛洪法類似。為了方便,再往下的泛洪法,都是指這種方式拓展後的演算法。

  5.實現
  還需要指出的是:為方便起見,下文以後所說的影象,都是指8點陣圖像,也就是用一個byte表示一個畫素的影象。下面的程式碼是用C#實現的泛洪法所需要的基礎結構,一共是三個,點結構,點陣圖類,點陣圖標記表類。點陣圖標記表的實現採用了.NET自帶的BitArray型別,這個型別是一個位數組,和C++的std::vector類似。它比用一般的bool陣列少佔7/8的空間:
  點結構:

複製程式碼
public struct Int16Double
{
        public int X;
        public int Y;
        public Int16Double(int x, int y)
        {
            X=x;
            Y=y;
        }
}//點結構,用於儲存畫素點的XY座標
複製程式碼

  點陣圖類(嚴格說應該叫8位點陣圖類):

複製程式碼
public class BitMap2d
{
        public const byte WHITE = 255;
        public const byte BLACK = 0;
        public byte[] data;
        public int width;
        public int height;
        public BitMap2d(int width, int height, byte v)
        {
            this.width = width;
            this.height = height;
            data = new byte[width * height ];
            for (int i = 0; i < width * height; i++)
                data[i] = v;
        }
        public BitMap2d(byte[] data, int width, int height)
        {
            this.data = data;
            this.width = width;
            this.height = height;
        }
        public void SetPixel(int x, int y, byte v)
        {
            data[x + y * width] = v;
        }
        public byte GetPixel(int x, int y)
        {
            return data[x + y * width];
        }
}//表示2維影象的結構,儲存影象資料在data中並提供存取畫素的方法。
複製程式碼

  點陣圖標記表類:

複製程式碼
public class FlagMap2d
{
        public int width;
        public int height;
        BitArray flags;
        public FlagMap2d(int width, int height)
        {
            this.width = width;
            this.height = height;
            flags = new BitArray(width * height , false);
        }
        public void SetFlagOn(int x, int y, bool v)
        {
            flags[x + y * width] = v;
        }
        public bool GetFlagOn(int x, int y)
        {
            return flags[x + y * width];
        }
 }//表示2維影象的點陣圖標記表,和影象的位置一一對應,值為bool,表示該點對應畫素的狀態。
複製程式碼

  下面的c#程式碼是泛洪法的實現主體:

複製程式碼
class FloodFill2d
{
        protected BitMap2d bmp;
        protected FlagMap2d flagsMap;
        protected Container_Queue<Int16Double> queue;
        protected int count = 0;
        public virtual bool IncludePredicate(Int16Double p)
        {
            return bmp.GetPixel(p.X, p.Y) == BitMap2d.WHITE;
        }//加入區域的判斷,本程式碼採用的加入條件為畫素值等於WHITE(255)
        public virtual void Process(Int16Double p)
        {
            count++;
            return;
        }//對新加入的點的處理,本程式碼的處理只是簡單計數,應根據應用需要選擇不同處理
        public void ExcuteFloodFill(BitMap2d data,Int16Double seed)
        {
            this.bmp = data;
            flagsMap = new FlagMap2d(data.width, data.height);
            queue = new Container_Queue<Int16Double>();
            Int16Double[] adjPoints4 = new Int16Double[6];
            flagsMap.SetFlagOn(seed.X, seed.Y, true);
            queue.Push(seed);
            Process(seed);
            while (!queue.Empty())
            {
                Int16Double p = queue.Pop();
                InitAdj4(ref adjPoints4, ref p);
                for (int adjIndex = 0; adjIndex < 4; adjIndex++)
                {
                    Int16Double t = adjPoints4[adjIndex];
                    if (t.X < data.width && t.X >= 0 && t.Y < data.height && t.Y >= 0)
                    {
                        if (!flagsMap.GetFlagOn(t.X, t.Y) && IncludePredicate(t))
                        {
                            flagsMap.SetFlagOn(t.X, t.Y, true);
                            queue.Push(t);
                            Process(t);
                        }
                    }
                }
            }
            return;
        }//泛洪法執行主程式,注意本程式碼採用佇列,用棧也能達到目的,兩者的區別在後文會涉及
        private void InitAdj4(ref Int16Double[] adjPoints4, ref Int16Double p)
        {
            adjPoints4[0].X = p.X - 1; adjPoints4[0].Y = p.Y ;
            adjPoints4[1].X = p.X + 1;adjPoints4[1].Y = p.Y;
            adjPoints4[2].X = p.X ;adjPoints4[2].Y = p.Y - 1;
            adjPoints4[3].X = p.X ;adjPoints4[3].Y = p.Y + 1;
        }//初始化鄰域的函式,若想改為8鄰域,只需修改這個函式
}
複製程式碼

  可以看出這裡定義了一個類,includePredicate和Process定義為虛擬函式便於擴充套件。ExcuteFloodFill包含泛洪法主要邏輯。

二、掃描線演算法

  1.介紹

  泛洪法的效率問題一直是相關領域的研究重點,之前所描述的方法其實並不是尋找聯通區域的最快的辦法。實際上,業界在尋找影象聯通區域這個問題上有很多效率上優於經典泛洪法的實現。
  掃描線演算法(Scanline)是最為著名的泛洪法的改進演算法,掃描線種子填充演算法的基本思想是:首先填充當前掃描線上的位於給定區域內的一區段,然後確定與這一區段相鄰的上下兩條掃描線上位於該區段內是否存在需要填充的新區段,如果存在,則依次把它們儲存起來。反覆這個過程,直到所儲存的各區段都填充完畢。演算法執行如下的過程:

  • 初始化堆疊
  • 種子壓入堆疊
  • while(堆疊非空)
    • 從堆疊彈出種子象素。
    • 求出種子區段:xleft、xright 並填充整個區段。
    • 檢查相鄰的上掃描線的xleft≤x≤xright區間內,是否存在需要填充的新區段,如果存在的話,則把每個新區段在xleft≤x≤xright範圍內的最右邊的象素,作為新的種子象素依次壓入堆疊。
    • 檢查相鄰的下掃描線的xleft≤x≤xright區間內,是否存在需要填充的新區段,如果存在的話,則把每個新區段在xleft≤x≤xright範圍內的最右邊的象素,作為新的種子象素依次壓入堆疊。
  • 演算法結束

  演算法用虛擬碼描述如下,其中演算法採用了和上文泛洪法相同的表述方式,includePredicate判斷待考察點是否能納入區域中,process是對新加入的點的有關處理。

複製程式碼
ScanLineFill(seed,bmp,includePredicate,process)
  initialize container Q to empty
  set all flags in flagMap to false
  push seed into Q
  while Q is not empty 
      pop point P from Q
      find out xleft from P
      find out xright from P
      check the line range from (xleft,P.Y-1) to (xright,P.Y-1)
      check the line range from (xleft,P.Y+1) to (xright,P.Y+1)
  end
複製程式碼

  其中的尋找xleft和xright步驟以及檢查兩側掃描線的子程式虛擬碼如下所示:

複製程式碼
Findxleft(p,flagMap,Q,includePredicate,process)
  initialize xleft to p.X-1
  while (true)
      if xleft reaches 0 or flag at point(xleft,p.Y) is true
          break the circle
      else then if  includePredicate(xleft,p.Y) is true
          set flag at (xleft,p.Y) to true
          process point(xleft,p.Y)
          xleft decrease by 1
      else
          break the circle
  return xleft+1
  end
複製程式碼 複製程式碼
Findxright(p,flagMap,Q,includePredicate,process)
  initialize xright to p.X+1
  while (true)
      if xright reaches bmp.width or flag at point(xright,p.Y) is true
          break the circle
      else then if  includePredicate(xright,p.Y) is true
          set flag at (xright,p.Y) to true
          process point(xright,p.Y)
          xright decrease by 1
      else
          break the circle
  return xright-1
  end
複製程式碼

  Findxleft和Findxright的操作從p點出發,向各自的方向尋找連續的未被標記且符合加入區域條件的點,直到遇到邊界或者不滿足條件的點停止。每找到合適的點,即做上標記並進行所需的處理,最後返回在相應的方向所到達的最遠位置。

複製程式碼
CheckRange(xleft,xright,y,flagMap,Q,includePredicate,process)
  initialize index to xleft
  while index is less than or equal to xright
      if flag at (index,y) is false and includePredicate(index,y) is true
          initialize rb to index+1
          while rb is less than xright and flag at (index,y) is false and includePredicate(index,y) is true
              rb increase by 1
          rb decrease by 1
          set flag at (rb,y) to true
          push (rb,y) to Q
          process(rb,y)
          set index to rb+1
      else then
          index increase by 1
  end
複製程式碼

  CheckRange函式對縱座標為Y、橫座標在範圍[xleft,xright]內的點進行考察,這個考察過程實際上是需要識別出在這個大區段上所有未被填充的子區段然後把這些子區段中的一個點(其實可以是區段左、右頂點或者其中任意一點)加入堆疊,下圖所示說明這個大區段中的小區段,淺藍色的部分是這個大區段上不能被加入的畫素(不符合加入區域的條件或者已經被標記),他們把這個大區段分成了若干小區段。其中rb就是每個區段的最右畫素,並被標記上後加入堆疊。

  這些被加入堆疊的點,會在之後的過程中從棧中彈出然後再對他們進行Findxleft和Findxright操作,這樣這些點所在的區段的所有點也就被加入了。用C#實現的掃描線演算法的程式碼如下,其中相應的基本結構和泛洪法一致,可以看出掃描線演算法的三個主要操作就是Findxleft,Findxright和CheckRange。

  2.程式碼實現

複製程式碼
class ScanlineFill2d
    {
        protected int count = 0;
        protected Container<Int16Double> container;//這個容器可以是Queue和Stack中任意一種,這裡抽象成一個Container
        protected BitMap2d bmp;
        public FlagMap2d flagsMap;
        protected virtual void ExcuteScanlineFill(BitMap2d data, Int16Double seed)
        {
            this.bmp = data;
            data.ResetVisitCount();
            flagsMap = new FlagMap2d(data.width, data.height);
            flagsMap.SetFlagOn(seed.X, seed.Y, true);
            container.Push(seed);
            Process(seed);
            while (!container.Empty())
            {
                Int16Double p = container.Pop();
                int xleft = FindXLeft(p);
                int xright = FindXRight(p);
                if (p.Y - 1 >= 0)
                    CheckRange(xleft, xright, p.Y - 1);
                if (p.Y + 1 < data.height)
                    CheckRange(xleft, xright, p.Y + 1);
            }
        }//該函式為掃描線法主體
        protected void CheckRange(int xleft, int xright, int y)
        {
            for (int i = xleft; i <= xright; )
            {
                if ((!flagsMap.GetFlagOn(i, y)) && IncludePredicate(i, y))
                {
                    int rb = i + 1;
                    while (rb <= xright && (!flagsMap.GetFlagOn(rb, y)) && IncludePredicate(rb, y))
                    {
                        rb++;
                    }
                    rb--;
                    Int16Double t = new
            
           

相關推薦

種子生長演算法——種子生長

下文提到的種子點生長演算法,包括泛洪法,掃描線法,區段法三種。文字先從最簡單的泛洪法入手介紹種子點生長演算法的相關概念。之後進一步討論了掃描線法和區段法,同時提供了實驗資料驗證其中的一些結論。本文按照如下的結構來介紹: 泛洪法掃描線法區段法演算法分析對比以及實驗

EM演算法逼近GMM引數針對資料的python實現

GMM即高斯混合模型,是將資料集看成是由多個高斯分佈線性組合而成,即資料滿足多個高斯分佈。EM演算法用來以迭代的方式尋找GMM中個高斯分佈的引數以及權值。GMM可以用來做k分類,而混合的高斯分佈個數也就是分類數K。 當資料Y都是一維的時候,我們假設由兩個高斯分佈組成 就有概

餐系統開發app

公眾 打開 解決方案 營銷 門店 賬號 體驗 采集 平臺 二維碼點餐系統開發(陳琦:138-2848-7919可微)二維碼點餐模式開發,二維碼點餐系統平臺,二維碼點餐平臺APP,二維碼點餐定制開發,二維碼點餐軟件APP,二維碼點餐定制模式,二維碼點餐商城平臺。 微信自助點餐

演算法-遞增陣列的查詢

題目: 已知一個二維陣列,從左到右遞增,從上到下遞增,如下 [ [2,4,6,8,10], [3,5,7,9,11], [4,6,8,10,12], [5,7,9,11,13] ] 查詢元素x是否在二維陣列中 思路: 從左向右遞增,從上到下遞增,那麼可以認為是從右到左遞減,從上到下遞增,所以二維陣列中

noip資料結構與演算法 之 基礎小演算法 4 差值維護

noip資料結構與演算法 之 基礎小演算法 4 二維差值維護 二維差值維護問題實際上是對一維差值維護問題的擴充套件,相信來看二維差值維護的各位都已經對一維差值維護問題有足夠的認識了。下面先看一下二維差值維護的問題。  問題描述: 已知一個n*n的矩陣a,有m次操作,每次

選電腦圖示,顯示電腦介面。選相同的碼圖示,顯示碼介面(四)

有時候,在一個地方,放置不同的圖示,可以隨時切換圖示。在切換圖示的時候,實際上會相應切換底下的不同的介面。 一 前端基本表單介面 生成二維碼,引入了qrcode.js庫 <!DOCTYPE html> <html lang="en">

幾何-和直線

這篇文章講的是二維幾何中點和直線的相關問題。 直線的引數表示。直線可以用直線上的一點P0和方向向量v表示(雖然這個向量的大小沒什麼用處)。直線上所有點P滿足P=P0+tv。其中t稱為引數。如果已知直線上的兩個不同點A和B,則方向向量為B-A,所以引數方程為A+(B-A)t。

迪斯尼新影象演算法照片轉三模型

【感謝@袁欣_Jason 的熱心翻譯。如果其他朋友也有不錯的原創或譯文,可以嘗試推薦給伯樂線上。】 迪斯尼蘇黎世研究團隊開發出了一種新程式,它可以利用二維(2D)照片做三維(3D)建模。使用數百張攝影照片和一種特殊設計的演算法,該程式可以給電影、電視和遊戲做複雜且真

一天一演算法 day1--陣列中查詢

二維陣列中查詢 致2019 題目 題目分析 程式碼實現 測試用例 測試結果 致2019 2018年就這樣匆匆過去,這一

異常檢測演算法)矩陣分解

前面一篇文章《異常點檢測演算法(一)》簡要的介紹瞭如何使用概率統計的方法來計算異常點,本文將會介紹一種基於矩陣分解的異常點檢測方法。在介紹這種方法之前,先回顧一下主成分分析(Principle Component Analysis)這一基本的降維方法。 (一)主成分分析(Principle Componen

如何用Matlab將資料繞Z軸即(0,0)旋轉

在Matlab中鍵入以下程式碼: clear  clc x=[0 1 1 0 0]; y=[0 0 1 1 0]; plot(x,y,'r');%繪製正方形 hold on axis equal%將兩座標設為相等 axis([-1 2 -1 2])%設定顯示

演算法練習--陣列中的查詢

在一個二維陣列中,每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。請完成一個函式,輸入這樣的一個二維陣列和一個整數,判斷陣列中是否含有該整數。提交的程式碼語言:Python執行時間:345ms佔用記憶體:5852K狀態:答案正確123456789101

空間到直線垂足計算公式推導及Java實現——學習筆記

二維空間點到直線垂足計算公式推導及Java實現前言公式推導程式碼實現畫蛇添足 前言 簡單的公式推導,大概是高中程度的知識了。不管以前學的好不好,很久不用的東西,一上手還是有點懵的。推導一遍也是為了加深記憶。 公式推導 首先我們知道直線上兩點p1,p2: p1:(

【openCV筆記2】使用特徵(Features2D)和單對映(Homography)尋找已知物體

#include <stdio.h> #include <iostream> #include "opencv2/core/core.hpp" #include "opencv2/features2d/features2d.hpp" #includ

Opencv2D特徵框架---使用特徵和單對映尋找已知物體

程式碼 #include <stdio.h> #include <iostream> #include "opencv2/core/core.hpp" #include "opencv2/features2d/features2d.hpp" #inc

Kmeans、Kmeans++、Birch和KNN四種聚類演算法座標點的聚類分析對比實驗

0 寫在前面(資料集和原始碼)本文章涉及到的資料集合所有程式碼均上傳在此處:https://download.csdn.net/download/zhouzhuo_csuft/10494273;點選此處直接開啟連結;一共有四個程式碼檔案,分別是Kmeans、Kmeans++、

C++找出一個陣列中的鞍,即該位置的元素在該行最大,在該列最小(也可能沒有鞍

今日正式用csdn部落格記錄,回顧我所學到的知識,分享一些我的人生感悟和自身經歷。也希望未來通夠過此平臺和更多喜愛程式設計的人交流學習。 道聽途說再加上自己的感悟,認為程式設計最重要的是思想,而不是語言本身,語言只是個工具。所以我們得先學思想。遇到問題,應該先想如果是自己去做會怎麼處理,但我們不

最近對問題(平面)分治法

#include<iostream> #include<ctime> #include<cmath> #include<algorithm> using namespace std; #define number 100000

給定一個平面,平面有 n 個,求最多有多少個在同一條直線上。

需求:給定一個二維平面,平面上有 n 個點,求最多有多少個點在同一條直線上。 分析思路: 1、將所有點二維座標化,即定義出所有點的x,y座標值 2、遍歷出所有取出兩點的情況(不考慮先後順序),根據任意兩點都確定一條直線,直線引數為k斜率,b與y軸交點的縱座標(此時x=0),將他們放入一個

POJ1195:Mobile phones 樹狀陣列 矩陣的區間和(查詢更新均為

Description Suppose that the fourth generation mobile phone base stations in the Tampere area operate as follows. The area is divided int