1

この SURF コードを使用して、画像内のロゴを検出しています。正常に動作していますが、非常に遅いです。どうすれば最適化できるかについて何か考えはありますか?

- (void)findObject
{
    //NSLog(@"%@ %@", self, NSStringFromSelector(_cmd));

    width = 0;

    CvMemStorage* storage = cvCreateMemStorage(0);
    static CvScalar colors[] = 
    {
        {{0,0,255}},
        {{0,128,255}},
        {{0,255,255}},
        {{0,255,0}},
        {{255,128,0}},
        {{255,255,0}},
        {{255,0,0}},
        {{255,0,255}},
        {{255,255,255}}
    };

    if( !objectToFind || !image )
    {
        NSLog(@"Missing object or image");
        return;
    }

    CvSize objSize = cvGetSize(objectToFind);
    IplImage* object_color = cvCreateImage(objSize, 8, 3);
    cvCvtColor( objectToFind, object_color, CV_GRAY2BGR );

    CvSeq *objectKeypoints = 0, *objectDescriptors = 0;
    CvSeq *imageKeypoints = 0, *imageDescriptors = 0;
    int i;
    CvSURFParams params = cvSURFParams(500, 1);

    double tt = (double)cvGetTickCount();
    NSLog(@"Finding object descriptors");
    cvExtractSURF( objectToFind, 0, &objectKeypoints, &objectDescriptors, storage, params );

    NSLog(@"Object Descriptors: %d", objectDescriptors->total);
    cvExtractSURF( image, 0, &imageKeypoints, &imageDescriptors, storage, params );

    NSLog(@"Image Descriptors: %d", imageDescriptors->total);
    tt = (double)cvGetTickCount() - tt;

    NSLog(@"Extraction time = %gms", tt/(cvGetTickFrequency()*1000.));
    CvPoint src_corners[4] = {{0,0}, {objectToFind->width,0}, {objectToFind->width, objectToFind->height}, {0, objectToFind->height}};
    CvPoint dst_corners[4];
    CvSize size = cvSize(image->width > objectToFind->width ? image->width : objectToFind->width,
                         objectToFind->height+image->height);
    output = cvCreateImage(size,  8,  1 );
    cvSetImageROI( output, cvRect( 0, 0, objectToFind->width, objectToFind->height ) );
    //cvCopy( objectToFind, output );
    cvResetImageROI( output );
    cvSetImageROI( output, cvRect( 0, objectToFind->height, output->width, output->height ) );
    cvCopy( image, output );
    cvResetImageROI( output );

    NSLog(@"Locating Planar Object");
#ifdef USE_FLANN
    NSLog(@"Using approximate nearest neighbor search");
#endif
    if( locatePlanarObject( objectKeypoints, objectDescriptors, imageKeypoints,
                           imageDescriptors, src_corners, dst_corners ))
    {
        for( i = 0; i < 4; i++ )
        {
            CvPoint r1 = dst_corners[i%4];
            CvPoint r2 = dst_corners[(i+1)%4];
            //cvLine( output, cvPoint(r1.x, r1.y+objectToFind->height ),
                   //cvPoint(r2.x, r2.y+objectToFind->height ), colors[6] );
            cvLine( output, cvPoint(r1.x, r1.y+objectToFind->height ),
                   cvPoint(r2.x, r2.y+objectToFind->height ), colors[6],4 );
            //if(i==0)
                width = sqrt(((r1.x-r2.x)*(r1.x-r2.x))+((r1.y-r2.y)*(r1.y-r2.y)));
        }
    }
    vector<int> ptpairs;
    NSLog(@"finding Pairs");
#ifdef USE_FLANN
    flannFindPairs( objectKeypoints, objectDescriptors, imageKeypoints, imageDescriptors, ptpairs );
#else
    findPairs( objectKeypoints, objectDescriptors, imageKeypoints, imageDescriptors, ptpairs );
#endif
   /* for( i = 0; i < (int)ptpairs.size(); i += 2 )
    {
        CvSURFPoint* r1 = (CvSURFPoint*)cvGetSeqElem( objectKeypoints, ptpairs[i] );
        CvSURFPoint* r2 = (CvSURFPoint*)cvGetSeqElem( imageKeypoints, ptpairs[i+1] );
        cvLine( output, cvPointFrom32f(r1->pt),
               cvPoint(cvRound(r2->pt.x), cvRound(r2->pt.y+objectToFind->height)), colors[8] );
    }*/

    float dist = 629.0/width;
    [distanceLabel setText:[NSString stringWithFormat:@"%.2f",dist]];


    NSLog(@"Converting Output");
    UIImage *convertedOutput = [OpenCVUtilities UIImageFromGRAYIplImage:output];

    NSLog(@"Opening Stuff");
    [imageView setImage:convertedOutput];
    cvReleaseImage(&object_color);

    [activityView stopAnimating];

}

上記のコードimageは私の元の画像でobjectToFindあり、検出したいロゴです。

私の質問が明確でない場合はお知らせください。

4

1 に答える 1

1

プロファイリングを使用して、コードのどの部分が最も遅いかを判断する必要があります。
XCode を使用しているため、すぐに組み込みのプロファイラーを使用できます。

  1. 左上隅にある「実行」ボタンを押したままにして、「プロファイル」を選択します。
  2. [プロファイル] をクリックし、[タイム プロファイラー] を選択します。
  3. しばらくしてから、プロファイラーで「停止」を押し、「見つからないシンボルを非表示」、「システム ライブラリを非表示」、「上位関数」を選択し、「スレッドごとに分離」の選択を解除します。
  4. 関数 main を調べると、その後に右矢印が隠されています。その矢印をクリックすると、時間をパーセントで表示し、呼び出しツリーごとに統計を呼び出すことができます。

これがあなたが始める方法です。

一般に、プロファイリングなしで次の提案があります。

  • できるだけ新しいイメージとメモリ ストレージを作成しないようにします。(一時的に使用するために画像を関数に渡し、それらの画像を後で再利用できるように外部に保存することができます。)
  • 画像 (およびロゴ) を縮小して、画像の主要部分をロールアウトします。
  • より少ない記述子を使用する

2 つの経験則:

  • プロファイリングは驚くべき結果をもたらすことが多いため、プロファイリング後に何を改善するかを決定する必要があります。
  • 改善しようとする部分が早ければ早いほど、得られる潜在的な利益は少なくなります。
于 2012-12-18T13:26:20.380 に答える