AR paper outline

학술 2010. 8. 17. 15:58 Posted by 양고

Camera zoom has not been considered in most AR systems. Since our algorithm targets an AR system for broadcasting, the broadcast-level camera with a zoom lens must be considered.

The target is detected by SURF, ferns, or GPU-SIFT.

PatchTracker with linear motion model.
motion blur model (locate the last point of the motion blur).

Online camera calibration by Zhang → R, t, f estimated.
f is restricted to vary smoothly.

photometric calibration (lightsource estimation)

OpenCV 2.1 Ferns 테스트

학술 2010. 8. 12. 15:55 Posted by 양고
OpenCV 2.1의 find_obj_ferns.cpp를 살짝 바꿔서 capture 영상과 함께 사용할 수 있게 했다.
tracking-by-detection에 초당 3프레임 정도 나오는 듯하다.


출연:
내 손
갤S
유선전화기
USB 케이블

[소스코드 추가]
#include <cv.h>
#include <cvaux.h>
#include <highgui.h>
#include <algorithm>
#include <iostream>
#include <vector>
#pragma comment(lib, "cv210.lib")
#pragma comment(lib, "cvaux210.lib")
#pragma comment(lib, "highgui210.lib")
#pragma comment(lib, "cxcore210.lib")
using namespace cv;
int main(int argc, char** argv)
{
 const char* object_filename = argc > 1 ? argv[1] : "box.png";
 const char* scene_filename = argc > 2 ? argv[2] : "box_in_scene.png";
 int i;
   
 cvNamedWindow("Object", 1);
 cvNamedWindow("Image", 1);
 cvNamedWindow("Object Correspondence", 1);
   
 Mat object = imread( object_filename, CV_LOAD_IMAGE_GRAYSCALE );
 Mat image;
   
    double imgscale = 1;
//  Mat _image = imread( scene_filename, CV_LOAD_IMAGE_GRAYSCALE );
//  resize(_image, image, Size(), 1./imgscale, 1./imgscale, INTER_CUBIC);
    if( !object.data ) // || !image.data )
    {
        fprintf( stderr, "Can not load %s and/or %s\n"
                "Usage: find_obj [<object_filename> <scene_filename>]\n",
                object_filename, scene_filename );
        exit(-1);
    }
    Size patchSize(32, 32);
    LDetector ldetector(7, 20, 2, 2000, patchSize.width, 2);
    ldetector.setVerbose(true);
    PlanarObjectDetector detector;
   
    vector<Mat> objpyr, imgpyr;
    int blurKSize = 3;
    double sigma = 0;
    GaussianBlur(object, object, Size(blurKSize, blurKSize), sigma, sigma);
    //GaussianBlur(image, image, Size(blurKSize, blurKSize), sigma, sigma);
    buildPyramid(object, objpyr, ldetector.nOctaves-1);
    //buildPyramid(image, imgpyr, ldetector.nOctaves-1);
   
    vector<KeyPoint> objKeypoints, imgKeypoints;
 PatchGenerator gen(0,256,5,true,0.8,1.2,-CV_PI/2,CV_PI/2,-CV_PI/2,CV_PI/2);
   
    string model_filename = format("%s_model.xml.gz", object_filename);
    printf("Trying to load %s ...\n", model_filename.c_str());
    FileStorage fs(model_filename, FileStorage::READ);
    if( fs.isOpened() )
    {
        detector.read(fs.getFirstTopLevelNode());
        printf("Successfully loaded %s.\n", model_filename.c_str());
    }
    else
    {
        printf("The file not found and can not be read. Let's train the model.\n");
        printf("Step 1. Finding the robust keypoints ...\n");
        ldetector.setVerbose(true);
        ldetector.getMostStable2D(object, objKeypoints, 100, gen);
        printf("Done.\nStep 2. Training ferns-based planar object detector ...\n");
        detector.setVerbose(true);
   
        detector.train(objpyr, objKeypoints, patchSize.width, 100, 11, 10000, ldetector, gen);
        printf("Done.\nStep 3. Saving the model to %s ...\n", model_filename.c_str());
        if( fs.open(model_filename, FileStorage::WRITE) )
            detector.write(fs, "ferns_model");
    }
    printf("Now find the keypoints in the image, try recognize them and compute the homography matrix\n");
    fs.release();
 CvCapture* cap = cvCreateCameraCapture(CV_CAP_DSHOW+1); // (CV_CAP_ANY);
 IplImage* iCap = cvQueryFrame(cap);
 Mat _image = Mat(iCap->width, iCap->height, CV_32FC1);
 while(1)
 {
  iCap = cvQueryFrame(cap);
  cvtColor(iCap, _image, CV_BGR2GRAY);
  //Mat _image = imread( scene_filename, CV_LOAD_IMAGE_GRAYSCALE );
  resize(_image, image, Size(), 1./imgscale, 1./imgscale, INTER_CUBIC);
  GaussianBlur(image, image, Size(blurKSize, blurKSize), sigma, sigma);
  buildPyramid(image, imgpyr, ldetector.nOctaves-1);
    vector<Point2f> dst_corners;
    Mat correspond( object.rows + image.rows, std::max(object.cols, image.cols), CV_8UC3);
    correspond = Scalar(0.);
    Mat part(correspond, Rect(0, 0, object.cols, object.rows));
    cvtColor(object, part, CV_GRAY2BGR);
    part = Mat(correspond, Rect(0, object.rows, image.cols, image.rows));
    cvtColor(image, part, CV_GRAY2BGR);
 
    vector<int> pairs;
    Mat H;
   
    double t = (double)getTickCount();
    objKeypoints = detector.getModelPoints();
    ldetector(imgpyr, imgKeypoints, 300);
   
    std::cout << "Object keypoints: " << objKeypoints.size() << "\n";
    std::cout << "Image keypoints: " << imgKeypoints.size() << "\n";
    bool found = detector(imgpyr, imgKeypoints, H, dst_corners, &pairs);
    t = (double)getTickCount() - t;
    printf("%gms\n", t*1000/getTickFrequency());
   
    if( found )
    {
        for( i = 0; i < 4; i++ )
        {
            Point r1 = dst_corners[i%4];
            Point r2 = dst_corners[(i+1)%4];
            line( correspond, Point(r1.x, r1.y+object.rows),
                 Point(r2.x, r2.y+object.rows), Scalar(0,0,255) );
        }
    }
   
    for( i = 0; i < (int)pairs.size(); i += 2 )
    {
        line( correspond, objKeypoints[pairs[i]].pt,
             imgKeypoints[pairs[i+1]].pt + Point2f(0,object.rows),
             Scalar(0,255,0) );
    }
   
    imshow( "Object Correspondence", correspond );
    Mat objectColor;
    cvtColor(object, objectColor, CV_GRAY2BGR);
    for( i = 0; i < (int)objKeypoints.size(); i++ )
    {
        circle( objectColor, objKeypoints[i].pt, 2, Scalar(0,0,255), -1 );
        circle( objectColor, objKeypoints[i].pt, (1 << objKeypoints[i].octave)*15, Scalar(0,255,0), 1 );
    }
    Mat imageColor;
    cvtColor(image, imageColor, CV_GRAY2BGR);
    for( i = 0; i < (int)imgKeypoints.size(); i++ )
    {
        circle( imageColor, imgKeypoints[i].pt, 2, Scalar(0,0,255), -1 );
        circle( imageColor, imgKeypoints[i].pt, (1 << imgKeypoints[i].octave)*15, Scalar(0,255,0), 1 );
    }
    imwrite("correspond.png", correspond );
    imshow( "Object", objectColor );
    imshow( "Image", imageColor );
  if(cvWaitKey(1) == 27)
   break;
 }
    waitKey(0);
    return 0;
}



OpenCV SURF 버그 해결

학술 2010. 8. 4. 18:04 Posted by 양고
문제
SURF를 몇 번 돌리다 보면 만나는 메시지,
Run-time check failure #3 - The variable 'k' is being used without being initialized.


솔루션
1. 그냥 '계속(C)' 버튼을 눌러서 계속한다. -_-
2. 해당 cvsurf.cpp 파일을 맞게 수정한다.
3. 버그 수정된 OpenCV 2.1을 설치한다.

2.0에 이것 말고도 버그가 많다고 해서 과감하게 2.1로 업그레이드했다.
다음은 2.0 cvsurf.cpp의 해당 부분.

    /* remove keypoints that were marked for deletion */
    for ( i = 0; i < N; i++ )
    {
        CvSURFPoint* kp = (CvSURFPoint*)cvGetSeqElem( keypoints, i );
        if ( kp->size == -1 )
        {
            cvSeqRemove( keypoints, i );
            if ( _descriptors )
                cvSeqRemove( descriptors, i );
            k--;    // i--; 로 수정하면 됨
N--;
        }
    }

물론 위와 같이 cvsurf.cpp를 수정했다면 해당 라이브러리(cv인가?)를 빌드해야 할 것이다.
실은 그게 귀찮아서 2.1로 달렸다는...!

bwdist tested! - Matlab의 distance transform

학술 2010. 6. 24. 18:23 Posted by 양고
Image Processing Toolbox에 있는 bwdist.
이것이 2D 이미지만을 위한 함수인 줄 알고있다가 3D 데이터에도 적용 가능하다는 사실을 알고 실험해보았다.


img1 = imread('test.png');
[width,height] = size(img1);
bw = zeros(width, height, 256);
for x = 1:width
    for y = 1:height
        bw(x,y, img1(x,y)+1) = 1;
    end
end
D1 = bwdist(bw);
isosurface(D1,2), axis equal, view(3)
camlight, lighting gouraud, title('Euclidean')

Isosurface, distance values 모두 제대로 구해진 것 같다.
빠르고 괜찮은 듯.

[MATLAB] optimization toolbox tested...!

학술 2010. 6. 18. 22:45 Posted by 양고

Rosenbrock 함수의 최소점을 찾는 예제를 돌려 봄.

% rosenbrock.m
function f = rosenbrock(x)
f = 100*(x(2) - x(1)^2)^2 + (1 - x(1))^2;

% unitdisk.m
function [c, ceq] = unitdisk(x)
c = x(1)^2 + x(2)^2 - 1;
ceq = [ ];



Below is the ICP registration pseudo code.
read model image
fill distance volume D (--> Jacobian 계산 가능할듯)

read input image --> make 3D vertices
Objective function
  function e = objective(h)
  for all image (3D) points,
    (x y w)T = H(x y 1)T
    e += D(x,y,z)       (interpolated)

PRICAI 2000
Robert Hanek
Technische Universitat Miinchen, Germany

우선 이 논문을 보게 된 것은 다음의 결과 이미지 때문이다.

model-based edge localization이 가능하기 때문이다.
그림을 보면 search direction이 궁금한데, 논문 말미에 vertical search만 했다고 밝히고 있다 (약간 실망).

여러 가지 테크닉이 사용되고 있지만, 단순하게 요약하면 다음과 같다.
search range 내의 i번째 pixel에 대해 [i-D, i+D] 구간을 고려한다.
이 픽셀에서 color vector Yi를 observe할 확률(likelihood)은 pi(Yi) = p(Yi|mi(e), Ci(e)) = Gaussian distribution with mean = mi, covariance = Ci.
일단 mi, Ci를 알고 있는 경우(ch.2)에는 pi(Yi)를 maximize하면 된다. pixel이 여러 개이므로 ∏pi를 maximize하는 edge e를 찾는다.
가장 단순하게 설명하자면 edge e가 위치하는 [i-D, i+D] 구간은 edge (estimate) e에 따라 두 개 (lower, upper) 구간으로 나뉠 것이다. 모든 경우의 e에 대해서, lower 구간은 p(Yi|ml,Cl), upper 구간은 p(Yi|mu,Cu)를 계산해서 확률이 최대가 되는(ML) e를 정한다.
본 논문은 sub-pixel estimation을 목표로 하기 때문에 pixel-by-pixel로(즉 low-resolution global optimum이 되겠지) 계산하지 않고, 어떤 초기치에 대해 Newtown iteration으로 local minimum을 구한다.

여기까지가 기본 아이디어이고, 실제로는 에지를 중심으로 두 color distribution의 linear mixture를 사용한다 (why?). smooth objective function을 위한 것으로 생각했지만, 이를 위해서는 별도의 Gaussian smoothing (with stddev σ) 을 step function d에 사용하고 있다.

그리고 lower, upper 구간에 대해 m과 C를 각각 추정할 수 있다 (ch.3).
기본 iteration step에서 ^e와 ^σ가 주어지면, ^e로부터 충분히 떨어져 있는 픽셀들만 사용하여 means와 covariances를 다시 계산하여 업데이트한다 (이것도 좀 실망). → 위 그림과 같은 결과를 얻기 위해서는 초기치가 매우 중요할 것 같으나 언급이 없다. ㅜㅜ
...라기보단, 사용자가 찍어준 점을 중심으로 lower와 upper 구간의 color distribution (mean과 cov.) 을 계산하여 사용했을 것으로 보인다.

camera matrix - gl modelview matrix 변환

학술 2010. 3. 31. 15:23 Posted by 양고
R,t는
m <-- R,t로 이루어진 4x4 행렬을 column-major로 serialize.
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMultMatrixf(m);

이러면 Lookat 안 쓰고도 되는 듯?

프로젝션 행렬은,
void gluPerspective( GLdouble   fovy,
  GLdouble   aspect,
  GLdouble   zNear,
  GLdouble   zFar);
이니 그냥 fovy만 계산해서 넣자는...
아 이것도 해야되지:
void glViewport( GLint   x,
  GLint   y,
  GLsizei   width,
  GLsizei   height);

model-based edge localization

학술 2010. 3. 23. 23:39 Posted by 양고
noise-free input image


Gaussian noise (5%)

일단 edge 식별(Blue - Light Blue)에는 성공하고 confidence까지 정확히 뽑아냈으나, noisy image에서는 망하는 것을 알 수 있다.
search range 내 모든 픽셀 정보를 고려해야 할 듯.

<추가>
구현이 틀렸다! Eh와 Ev에 Dh와 Dv가 들어감. Epsilon에는 desired value와의 차이가 들어가야 한다.

<4.5 추가>
model image와 input image의 correlation을 이용한 edge localization 결과. 그래도 틀리는 곳이 많다 (안쪽 왼쪽).
CVPR 2007
Univ. of Nice-Sophia Antipolis, France
아이디어 점검용으로 대충 봄

2.2. Geometry-free similarity measures
histograms, PDFs

2.3. similarity measure with strict geometry
SSD, SAD

2.4. similarity measure with soft geometry
similar to what I wanted
그러나 kNN에 드는 계산량은 어쩔거냐... GPU면 다 해결?




Probabilistic Tracking in Joint Feature-Spatial Spaces
CVPR 2003

kernerl size가 0이면 SSD, ∞이면 histogram tracking이 된다.
뒤쪽의 likelihood maximization과 entropy maximization은 잘 모르겠다.




감상
일단 기본 아이디어는, color + spatial (max. 5D) 공간에서 거리를 최소화하는 것과 일치하는 것 같다.
TPAMI 2010에 실리는 EPFL 쪽 논문을 봐도 아직 grey level에서 matching 중인데, color가 native하게 반영된다는 점에서 매우 바람직한 접근으로 생각된다.
그리고 SSD tracking의 non-smooth objective function을 보완해줄 중요한 카드로 생각된다.
그러나 point-to-pixel의 엄청난 계산량이 예상되는 것이 가장 큰 문제.
Nvidia의 SDI capture board를 기다릴 것인가?
CVPR 2007
Technical University Munich

2.3. Mutual Information
[10] assume an underlying normal distribution to be able to directly compute the joint entropy of an arbitrary number d of inputs simultaneously from their covariance matrix Covd (식6)

2.5. Optimization
gradient-based가 아닌, 서로 정보를 주고 받으며 먹이가 많은 곳을 찾아가는 동물 떼를 simulation한 Particle Swarm Optimization (PSO) 기법을 사용함.
gradient를 explicitly 구하기 힘든 상황에서는 역시 이런 evolutionary optimization이 적합한지도. 그러나 프레임 당 2초는 너무 느리다.
이 느림은 PSO라기보단 MI 때문인 것 같기는 하다. 다른 MI 논문도 1초 정도였으니까.

References
[10] D. Russakoff, C. Tomasi, T. Rohlfing, and C. Maurer. Image similarity using mutual information of regions. In Proc. Europ. Conf. on Comp. Vision, pages 596–607, 2004.