2016-07-04 4 views
24

7月4日を祝して、私はプログラムでアメリカの国旗を検出するプログラム的な方法を見つけることに興味がありました。私は、彼らが写真でアメリカの国旗を見つける?

  1. 旗が風になびく旗ためのために働くだろうということはよく分からないので、(非線形変形そのものを閉塞またはその他のかもしれませんが、その問題のために良いの多くの技術を説明するearlier and popular question about finding Coca-Cola cans in imagesありSIFTのようなテクニックを使うのが少し難しくなります)、
  2. コカ・コーラ缶とは異なり、アメリカ旗の星条旗はアメリカの旗にはユニークではなく、例えばflag of Liberiaの一部である可能性があります"ライン署名"技術。

このタスクに特に適した標準的な画像処理または認識技術はありますか?

+3

あなたが訓練のための大規模なデータセットを持っている場合は、を検索:深い学習画像分類。近年、この面で大きな進歩がありました。 – Photon

+1

私はあなたがSOの有名なメンバーであることを知っていますが、1)試行されていないようです。 2)質問が広すぎる。 –

+0

@サルバドールダリ、彼は彼自身の質問に答えました。良い答えも(私はちょうどそれを16番目のupvotesを作った)。私はAskerがより多くの答え/アプローチにオープンしていると思う。 –

答えて

33

私のアプローチは問題を一般化し、実際には青色の領域に近い赤色と白色のストリップパターン(水平または垂直)を探します。したがって、それはアメリカの旗だけがこのパターンを持っているシーンのために働く。

私のアプローチはJavaで開発され、Marvin Frameworkを使用します。

アルゴリズム:

  1. アメリカンフラグの同じ色で画素のみを保持するカラーフィルタ。
  2. このパターンは、青色領域に囲まれているかどうかをチェック
  3. セグメントを小領域(ノイズ)のパターンを削除垂直赤と白のストリップパターン
  4. の検索エリアを水平赤と白のストリップパターン
  5. を探します。

入力:

enter image description here

カラーフィルター:

enter image description here

フラグ:

enter image description here

もっと興味深いのは、多くのフラグがある場合のパフォーマンスです。

入力

enter image description here

カラーフィルタ:

enter image description here

パターンマッチング:

enter image description here

旗:

enter image description here

ソースコード:

import static marvin.MarvinPluginCollection.*; 

public class AmericanFlag { 

    public AmericanFlag(){ 
     process("./res/flags/", "flag_0", Color.yellow); 
     process("./res/flags/", "flag_1", Color.yellow); 
     process("./res/flags/", "flag_2", Color.yellow); 
     process("./res/flags/", "flag_3", Color.yellow); 
     process("./res/flags/", "flag_4", Color.blue); 
    } 

    private void process(String dir, String fileName, Color color){ 
     MarvinImage originalImage = MarvinImageIO.loadImage(dir+fileName+".jpg"); 
     MarvinImage image = originalImage.clone(); 
     colorFilter(image); 
     MarvinImageIO.saveImage(image, dir+fileName+"_color.png"); 

     MarvinImage output = new MarvinImage(image.getWidth(), image.getHeight()); 
     output.clear(0xFFFFFFFF); 
     findStripsH(image, output); 
     findStripsV(image, output); 
     MarvinImageIO.saveImage(output, dir+fileName+"_1.png"); 

     MarvinImage bin = MarvinColorModelConverter.rgbToBinary(output, 127); 
     morphologicalErosion(bin.clone(), bin, MarvinMath.getTrueMatrix(5, 5)); 
     morphologicalDilation(bin.clone(), bin, MarvinMath.getTrueMatrix(15, 15)); 
     MarvinImageIO.saveImage(bin, dir+fileName+"_2.png"); 

     int[] centroid = getCentroid(bin); 
     image.fillRect(centroid[0], centroid[1], 30, 30, Color.yellow); 

     int area = getMass(bin); 
     boolean blueNeighbors = hasBlueNeighbors(image, bin, centroid[0], centroid[1], area); 

     if(blueNeighbors){ 
      int[] seg = getSegment(bin); 
      for(int i=0; i<4; i++){ 
       originalImage.drawRect(seg[0]+i, seg[1]+i, seg[2]-seg[0], seg[3]-seg[1], color); 
      } 
      MarvinImageIO.saveImage(originalImage, dir+fileName+"_final.png"); 
     } 
    } 

    private boolean hasBlueNeighbors(MarvinImage image, MarvinImage bin, int centerX, int centerY, int area){ 
     int totalBlue=0; 
     int r,g,b; 
     int maxDistance = (int)(Math.sqrt(area)*1.2); 
     for(int y=0; y<image.getHeight(); y++){ 
      for(int x=0; x<image.getWidth(); x++){ 
       r = image.getIntComponent0(x, y); 
       g = image.getIntComponent1(x, y); 
       b = image.getIntComponent2(x, y); 

       if(
        (b == 255 && r == 0 && g == 0) && 
        (MarvinMath.euclideanDistance(x, y, centerX, centerY) < maxDistance) 
       ){ 
        totalBlue++; 
        bin.setBinaryColor(x, y, true); 
       } 
      } 
     } 

     if(totalBlue > area/5){ 
      return true; 
     } 
     return false; 
    } 

    private int[] getCentroid(MarvinImage bin){ 
     long totalX=0, totalY=0, totalPixels=0; 
     for(int y=0; y<bin.getHeight(); y++){ 
      for(int x=0; x<bin.getWidth(); x++){ 

       if(bin.getBinaryColor(x, y)){ 
        totalX += x; 
        totalY += y; 
        totalPixels++; 
       } 
      } 
     } 

     totalPixels = Math.max(1, totalPixels); 
     return new int[]{(int)(totalX/totalPixels), (int)(totalY/totalPixels)}; 
    } 

    private int getMass(MarvinImage bin){ 
     int totalPixels=0; 
     for(int y=0; y<bin.getHeight(); y++){ 
      for(int x=0; x<bin.getWidth(); x++){ 
       if(bin.getBinaryColor(x, y)){ 
        totalPixels++; 
       } 
      } 
     } 

     return totalPixels; 
    } 

    private int[] getSegment(MarvinImage bin){ 
     int x1=-1, x2=-1, y1=-1, y2=-1; 
     for(int y=0; y<bin.getHeight(); y++){ 
      for(int x=0; x<bin.getWidth(); x++){ 
       if(bin.getBinaryColor(x, y)){ 

        if(x1 == -1 || x < x1){ x1 = x; } 
        if(x2 == -1 || x > x2){ x2 = x; } 
        if(y1 == -1 || y < y1){ y1 = y; } 
        if(y2 == -1 || y > y2){ y2 = y; } 
       } 
      } 
     } 
     return new int[]{x1,y1,x2,y2}; 
    } 

    private void findStripsH(MarvinImage imageIn, MarvinImage imageOut){ 

     int strips=0; 
     int totalPixels=0; 
     int r,g,b; 
     int patternStart; 
     boolean cR=true; 
     int patternLength = -1; 
     for(int y=0; y<imageIn.getHeight(); y++){ 
      patternStart = -1; 
      strips = 0; 
      patternLength=-1; 
      for(int x=0; x<imageIn.getWidth(); x++){ 
       r = imageIn.getIntComponent0(x, y); 
       g = imageIn.getIntComponent1(x, y); 
       b = imageIn.getIntComponent2(x, y); 

       if(cR){ 
        if(r == 255 && g == 0 && b == 0){ 
         if(patternStart == -1){ patternStart = x;} 
         totalPixels++; 
        } else{ 
         if(patternLength == -1){ 
          if(totalPixels >=3 && totalPixels <= 100){ 
           patternLength = (int)(totalPixels); 
          } else{ 
           totalPixels=0; patternStart=-1; strips=0; patternLength=-1; 
          } 
         } else{ 
          if(totalPixels >= Math.max(patternLength*0.5,3) && totalPixels <= patternLength * 2){ 
           strips++; 
           totalPixels=1; 
           cR = false; 
          } else{ 
           totalPixels=0; patternStart=-1; strips=0; patternLength=-1; 
          } 
         } 
        } 
       } 
       else{ 
        if(r == 255 && g == 255 && b == 255){ 
         totalPixels++; 
        } else{ 
         if(totalPixels >= Math.max(patternLength*0.5,3) && totalPixels <= patternLength * 2){ 
          strips++; 
          totalPixels=1; 
          cR = true; 
         } else{ 
          totalPixels=0; patternStart=-1; strips=0; patternLength=-1; cR=true; 
         } 
        } 
       } 


       if(strips >= 4){ 
        imageOut.fillRect(patternStart, y, x-patternStart, 2, Color.black); 
        totalPixels=0; patternStart=-1; strips=0; patternLength=-1; cR=true; 
       } 
      } 
     } 
    } 

    private void findStripsV(MarvinImage imageIn, MarvinImage imageOut){ 

     int strips=0; 
     int totalPixels=0; 
     int r,g,b; 
     int patternStart; 
     boolean cR=true; 
     int patternLength = -1; 
     for(int x=0; x<imageIn.getWidth(); x++){ 
      patternStart = -1; 
      strips = 0; 
      patternLength=-1; 
      for(int y=0; y<imageIn.getHeight(); y++){ 
       r = imageIn.getIntComponent0(x, y); 
       g = imageIn.getIntComponent1(x, y); 
       b = imageIn.getIntComponent2(x, y); 

       if(cR){ 
        if(r == 255 && g == 0 && b == 0){ 
         if(patternStart == -1){ patternStart = y;} 
         totalPixels++; 
        } else{ 
         if(patternLength == -1){ 
          if(totalPixels >=3 && totalPixels <= 100){ 
           patternLength = (int)(totalPixels); 
          } else{ 
           totalPixels=0; patternStart=-1; strips=0; patternLength=-1; 
          } 
         } else{ 
          if(totalPixels >= Math.max(patternLength*0.5,3) && totalPixels <= patternLength * 2){ 
           strips++; 
           totalPixels=1; 
           cR = false; 
          } else{ 
           totalPixels=0; patternStart=-1; strips=0; patternLength=-1; 
          } 
         } 
        } 

//     if(maxL != -1 && totalPixels > maxL){ 
//      totalPixels=0; patternStart=-1; strips=0; maxL=-1; 
//     } 
       } 
       else{ 
        if(r == 255 && g == 255 && b == 255){ 
         totalPixels++; 
        } else{ 
         if(totalPixels >= Math.max(patternLength*0.5,3) && totalPixels <= patternLength * 2){ 
          strips++; 
          totalPixels=1; 
          cR = true; 
         } else{ 
          totalPixels=0; patternStart=-1; strips=0; patternLength=-1; cR=true; 
         } 
        } 

//     if(maxL != -1 && totalPixels > maxL){ 
//      totalPixels=0; patternStart=-1; strips=0; maxL=-1; 
//      cR=true; 
//     } 
       } 


       if(strips >= 4){ 
        imageOut.fillRect(x, patternStart, 2, y-patternStart, Color.black); 
        totalPixels=0; patternStart=-1; strips=0; patternLength=-1; cR=true; 
       } 
      } 
     } 
    } 

    private void colorFilter(MarvinImage image){ 

     int r,g,b; 
     boolean isR, isB; 
     for(int y=0; y<image.getHeight(); y++){ 
      for(int x=0; x<image.getWidth(); x++){ 
       r = image.getIntComponent0(x, y); 
       g = image.getIntComponent1(x, y); 
       b = image.getIntComponent2(x, y); 

       isR = (r > 120 && r > g * 1.3 && r > b * 1.3); 
       isB = (b > 30 && b < 150 && b > r * 1.3 && b > g * 1.3); 

       if(isR){ 
        image.setIntColor(x, y, 255,0,0); 
       } else if(isB){ 
        image.setIntColor(x, y, 0,0,255); 
       } else{ 
        image.setIntColor(x, y, 255,255,255); 
       } 
      } 
     } 
    } 

    public static void main(String[] args) { 
     new AmericanFlag(); 
    } 
} 

その他結果:

enter image description here

enter image description here

enter image description here

+1

しかし、あなたは "リベリアの旗"でそれをテストしなかった...それとも新しい挑戦ですか? –

+1

ほとんどの例は、アルゴリズムによって記述された水平線も垂直線もないようです。これはちょうどあなたがあなたのアルゴリズムに言い聞かせした方法では矛盾ですか?あなたは本当に水平または垂直の縞、または任意の方向を具体的に探していますか?または、どういうわけか、水平と垂直をマージして対角を見つけるのですか? – pabrams

+1

実際にはそれらがあります。このパターンを別の方法で定義しましょう:水平方向または垂直方向の赤色と白色の色の交互点。例えば、45度回転されたフラグは、縦と横の両方の縞パターンを有する。ストライプにNOT PARALLELの線でアメリカの旗を渡ると、赤と白の交互が見えます。しかし、この線がストライプと直交しているとパターンがより強くなります。はい、横と縦の結果をマージしました。 –

1

あなたは、OpenCVのライブラリを介して、 'テンプレートマッチング' を使用することができます。ここ

アプローチの背後にある理論である:

テンプレートマッチングは、より大きな画像におけるテンプレート画像の位置 を検索し、発見するための方法です。 OpenCVには、この目的のために関数 cv2.matchTemplate()が付属しています。入力画像上にテンプレート の画像を単純にスライドさせ(2D畳み込みのように)、テンプレート画像の テンプレートと入力画像のパッチを比較します。

コード例および実装の説明はここで見つけることができます: http://docs.opencv.org/master/d4/dc6/tutorial_py_template_matching.html#gsc.tab=0

関連する問題