2016-10-30 8 views
2

私は以下の質問hereを尋ねましたが、良い解決策を得ましたが、性能はそれほど遅くないことが分かっています(640x480画像で2-300 ms)。今私はどのように最適化することができるか検討したいと思います。台形のパーセンテージマッチングを計算する最速の方法

問題:
与えられた2つのポリゴン(常にX軸に平行な台形)がある場合、どの程度一致するかを計算したいと思います。これによって、オーバーラップ領域は十分ではありません。一つのポリゴンに余分な領域があると、何らかの形でそれに対抗する必要があるからです。最適には、両方のポリゴンによって作成される面積の何パーセントが共通であるかを知りたいと思います。例えば、希望のものとして画像を参照してください。

Example

作業(しかし遅い)溶液:
- 空の画像上にポリゴンいずれかを描画し(CV :: fillConvexPoly)
- 空の画像(CV :: fillConvexPoly)にポリゴン2を描画
- ビットを実行し、
重複全画素の画像を作成するために - すべての非ゼロピクセルをカウント - >オーバーラップピクセル
- 最初の画像を反転および非反転秒で繰り返し - >過剰画素
- Inv第二の画像ERTと非反転された第1と繰り返し - >より過大なピクセル
- あなたは現在のソリューションは、計算集約的である見ることができるように「過度のピクセルの

の合計を超える「重複ピクセル」を取ります画像の1ピクセルごとに12倍程度の評価をしているためです。私はむしろ、いくつかの画像の退屈な構成と評価を行うこの領域を計算するソリューションを望んでいます。

既存のコード:

#define POLYGONSCALING 0.05 
typedef std::array<cv::Point, 4> Polygon; 

float PercentMatch(const Polygon& polygon, 
        const cv::Mat optimalmat) 
{ 
    //Create blank mats 
    cv::Mat polygonmat{ cv::Mat(optimalmat.rows, optimalmat.cols, CV_8UC1, cv::Scalar(0)) }; 
    cv::Mat resultmat{ cv::Mat(optimalmat.rows, optimalmat.cols, CV_8UC1, cv::Scalar(0)) }; 

    //Draw polygon 
    cv::Point cvpointarray[4]; 
    for (int i =0; i < 4; i++) { 
     cvpointarray[i] = cv::Point(POLYGONSCALING * polygon[i].x, POLYGONSCALING * 
      polygon[i].y); 
    } 
    cv::fillConvexPoly(polygonmat, cvpointarray, 4, cv::Scalar(255)); 

    //Find overlapped pixels 
    cv::bitwise_and(polygonmat, optimalmat, resultmat); 
    int overlappedpixels { countNonZero(resultmat) }; 

    //Find excessive pixels 
    cv::bitwise_not(optimalmat, resultmat); 
    cv::bitwise_and(polygonmat, resultmat, resultmat); 
    int excessivepixels { countNonZero(resultmat) }; 
    cv::bitwise_not(polygonmat, resultmat); 
    cv::bitwise_and(optimalmat, resultmat, resultmat); 
    excessivepixels += countNonZero(resultmat); 

    return (100.0 * overlappedpixels)/(overlappedpixels + excessivepixels); 
} 

現在、私はそれが(それは他の多くのポリゴンに比べます)再描画ではありませんので、関数の外で「optimalmat」を描いている考案した唯一のパフォーマンスの向上、ポリゴンのサイズを変更して解像度を落としますが、パフォーマンスを向上させるためにPOLYGONSCALINGを追加しました。まだ遅すぎる。

+0

[モンテカルロ( https://en.wikipedia.org/wiki/Monte_Carlo_inteおそらく? –

+0

または、重複領域を計算するための数式を考え出すことができます。あなたは必要なすべての情報を持っています:台形の各点。 –

+0

[ポリゴンブール演算](http://doc.cgal.org/latest/Boolean_set_operations_2/index.html#Boolean_set_operations_2ASimpleExample) –

答えて

2

私はあなたが欲しいものを誤解しているかもしれませんが、私はあなたがより速く、このようにそれを行うことができるはずだと思う...

  • はゼロの背景に1つのとあなたの最初の台形を入力します。
  • ゼロの背景に2の台形を2で塗りつぶします。
  • 2つのマットを一緒に追加します。

次に、各画素が4つの要素を持つ配列を作成0、1、2または3のいずれかでなければならず、すべての要素上の単一パスで、無ifステートメントで、単に値に応じて対応する配列要素をインクリメント各ピクセルの

次に、配列の最初のインデックスのピクセルの合計は、台形が存在しない場合、インデックス1と2の要素は台形1または2が存在し、インデックス3の要素は重複します。

また、2つの台形の洪水塗りつぶしをベンチマークすることもできます。時間がある場合は相当な割合で、2番目の台形を埋める2番目のスレッドがあるかもしれません。

enter image description here

ベンチマーク

私は上記の理論を試すためにいくつかのコードを書いた、と640×480の画像でそれを取る:

  • 181マイクロ秒は最初のポリゴンを描画する
  • 第2ポリゴンを描画するのに84マイクロ秒
  • 481マイクロ秒オーバーラップを計算するために実行します。

したがって、iMacの合計時間は740マイクロ秒です。

2番目のポリゴンを最初のポリゴンと平行に描くことができますが、スレッドの作成と結合の時間は約20マイクロ秒ですので、わずか60マイクロ秒しか節約できません。

コードのほとんどは、タイミングおよびデバッグされる:

#include "opencv2/highgui.hpp" 
#include "opencv2/imgproc/imgproc.hpp" 
#include <iostream> 
#include <stdio.h> 
#include <stdlib.h> 
#include <chrono> 

using namespace cv; 
using namespace std; 

const int COLS=640; 
const int ROWS=480; 

typedef std::chrono::high_resolution_clock hrclock; 
hrclock::time_point t1,t2; 
std::chrono::nanoseconds elapsed; 
int e; 

int 
main(int argc,char*argv[]){ 

    Mat canvas1(ROWS,COLS,CV_8UC1,Scalar(0)); 
    Mat canvas2(ROWS,COLS,CV_8UC1,Scalar(0)); 
    Mat sum(ROWS,COLS,CV_8UC1,Scalar(0)); 

    //Draw polygons on canvases 
    Point vertices1[4]={Point(10,10),Point(400,10),Point(400,460),Point(10,460)}; 
    Point vertices2[4]={Point(300,50),Point(600,50),Point(600,400),Point(300,400)}; 

    t1 = hrclock::now(); 
    // FilConvexPoly takes around 150 microseconds here 
    fillConvexPoly(canvas1,vertices1,4,cv::Scalar(1)); 
    t2 = hrclock::now(); 
    elapsed = t2-t1; 
    e=elapsed.count(); 
    cout << "fillConvexPoly: " << e << "ns" << std::endl; 

    imwrite("canvas1.png",canvas1); 

    t1 = hrclock::now(); 
    // FilConvexPoly takes around 80 microseconds here 
    fillConvexPoly(canvas2,vertices2,4,cv::Scalar(2)); 
    t2 = hrclock::now(); 
    elapsed = t2-t1; 
    e=elapsed.count(); 
    cout << "fillConvexPoly: " << e << "ns" << std::endl; 
    imwrite("canvas2.png",canvas2); 
    sum=canvas1+canvas2; 
    imwrite("sum.png",sum); 

    long totals[4]={0,0,0,0}; 
    uchar* p1=sum.data; 
    t1 = hrclock::now(); 
    for(int j=0;j<ROWS;j++){ 
     uchar* data= sum.ptr<uchar>(j); 
     for(int i=0;i<COLS;i++) { 
     totals[data[i]]++; 
     } 
    } 
    t2 = hrclock::now(); 
    elapsed = t2-t1; 
    e=elapsed.count(); 
    cout << "Count overlap: " << e << "ns" << std::endl; 
    for(int i=0;i<4;i++){ 
     cout << "totals[" << i << "]=" << totals[i] << std::endl; 
    } 
} 

サンプルラン

fillConvexPoly: 181338ns 
fillConvexPoly: 84759ns 
Count overlap: 481830ns 
totals[0]=60659 
totals[1]=140890 
totals[2]=70200 
totals[3]=35451 

次のようにImageMagickのを使用して検証:

identify -verbose sum.png | grep -A4 Histogram: 

Histogram: 
60659: ( 0, 0, 0) #000000 gray(0) 
140890: ( 1, 1, 1) #010101 gray(1) 
70200: ( 2, 2, 2) #020202 gray(2) 
35451: ( 3, 3, 3) #030303 gray(3) 
+0

2つのすばらしい提案、マーク!それが私の正確な解決策ではない場合は、ピクセルの非ブール性を利用してステップを節約することをお勧めします。私はそれを試して、どれくらいの時間を節約し、マルチスレッドが実際にそれを最適化できるかをベンチマークします。おかげで – DrTarr

+0

うわー、さらに良い。私は実際に昨晩働いていたコードがありました。ベンチマークをしていないだけです。優れた答え、あなたの助けに感謝! – DrTarr

関連する問題