Computer Vision2011. 9. 14. 13:33
Using the mean shift algorithm to find an object

 Histogram projection으로 원하는 위치의 Histogram을 바탕으로 움직이는 물체를 추적할 수 있습니다. 이에 대한 대표적인 알고리듬이 Mean Shift Algorithm입니다.  이 절에서는 이것을 이용해서 실제 움직이는 물체를 추적하는 것을 해보겠습니다.

별도의 복잡한 알고리듬을 계속 사용하는 것이 아니라서 추적에 약간의 버그가 있음을 미리 알려드립니다.
- 책에 있는 내용에서 버그를 약간 수정한 버전입니다.


QT에서 QT Console로 프로젝트를 만듭니다. 
- 반드시 Qt일 필요는 없지만, 따로 빌드 스크립트 만드는게 귀찮아서 여기서합니다.
- 까짓거 속도가 좀느려도 어떠냐 라는 생각도 있습니다. ㅋㅋ


코드는 아래 것을 보시기 바라고 코드를 그대로 읽어보면 아래와 같습니다.

STEP 1 일단 이미지를 읽어들여서 관심 영역을 설정합니다.
 여기서는 움직이는 차량을 대상으로 합니다.

안타깝게도, 관심 영역은 자동으로 하지 못하므로 일일이 손으로 지정해야 하는 단점이 있습니다.
GIMP에서 픽셀단위로 위치를 확인합니다.


    // Set ROI
    cv::Mat imageROI = image(cv::Rect(127, 170 , 120 , 80));
    cv::rectangle(image,cv::Rect(127, 170 , 120 , 80),cv::Scalar(0,0,255));

그리고 화면에 보이기 위해서 사각형을 하나 그립니다.

그것이 이 아래의 그림입니다.



Step 2 : Hue의 Saturation을 구합니다. 

코드는 아래와 같습니다.

    // Get HUE histogram
    ColorHistogram hc;
    int minSat = 65;

    //cv::MatND colorhist = hc.getHueHistogram( imageROI ,  minSat );
    cv::MatND colorhist = hc.getHueHistogram( imageROI );


실세로는 Class로 선언된 ColorHistogram class에서 GetHueHistogram을 호출하여 가지고 옵니다.
그리고 그 대상은 관심 영역을 대상으로 합니다.

해당 함수는 아래와 같습니다.

	// Computes the 1D Hue histogram with a mask.
	// BGR source image is converted to HSV
	cv::MatND getHueHistogram(const cv::Mat &image) {

		cv::MatND hist;

		// Convert to Lab color space
		cv::Mat hue;
		cv::cvtColor(image, hue, CV_BGR2HSV);

		// Prepare arguments for a 1D hue histogram
		hranges[0]= 0.0;
		hranges[1]= 180.0;
		channels[0]= 0; // the hue channel 

		// Compute histogram
		cv::calcHist(&hue, 
			1,			// histogram of 1 image only
			channels,	// the channel used
			cv::Mat(),	// no mask is used
			hist,		// the resulting histogram
			1,			// it is a 1D histogram
			histSize,	// number of bins
			ranges		// pixel value range
		);

		return hist;
	}

이미지를 RGB에서 HSV로 바꾼뒤에 이중에서 Hue에 대한 것만 찾아서 Histogram을 만들어갑니다. 
Histogram을 만드는 함수는 다시 OpenCV내에 함수를 사용했습니다.
여하튼 이렇게 해서 Hue에 대한 Histogram을 얻어냅니다.

Step 3  ObjectFinder에서 finder를 선언합니다.
그리고 Search에 필요한 히스토그램 데이터를 설정합니다.
코드는 아래와 같습니다.

    // Object Finder
    ObjectFinder finder;
    finder.setHistogram(colorhist);
    finder.setThreshold(0.2f);


setHistogram은 아래와 같은 함수입니다.

	// Sets the reference histogram
	void setHistogram(const cv::MatND& h) {

		isSparse= false;
		histogram= h;
		cv::normalize(histogram,histogram,1.0);
	}

주어진 histogram데이터를 0~1사이에서  normalize시켜서 보관한다.

finder.setThreshold(0.2f);

은 그냥 내부 변수중 Threshld값을 0.2f로 설정해준다. 이 값은 나중에 연산할 때 사용한다.

Step 4 : 이미지를 HSV로 변경한 후에 이미지를 분할한다. 

    //convert to HSV space
    cv::cvtColor(image, hsv, CV_BGR2HSV);

    //split image
    vector<cv::Mat> v;
    cv::split(hsv,v);

HSV의 image를 다시 각각의 컬러 값들을 V plane으로 분리시켜둡니다.
이는 H값만을 대상으로 작업하기 편하게 만든 것입니다.
v[1]이 H값입니다.

Step 5 : Threshold를 찾아서 마스킹 시킵니다.

    // Identify pixel with low saturation
    cv::threshold(v[1],v[1], minSat, 255,cv::THRESH_BINARY);

이렇게 해서 얻은 이미지는 아래와 같다.



Step 6 HUE에 대한 Backproject을 얻습니다.

    // Let's obtain backrojection of the hue channel
    // Get back-projection of hue histogram
    int ch[1]={0};
    cv::Mat result= finder.find(hsv,0.0f,180.0f,ch,1);
    cv::namedWindow("Result Hue");
    cv::imshow("Result Hue",result);

 

결과 이미지는 아래와 같다.


- 약간 뭔가 이상한 그림이긴 하지만, 하여튼 결과는 위와 같다.

그리고 Low와 Saturation시킨 그림을 마스킹 시켜서 이미지를 다시 얻는다.

    // Eliminate low saturation pixels
    cv::bitwise_and(result,v[1],result);
    cv::namedWindow("Result Hue and");
    cv::imshow("Result Hue and",result);

 이미지는 아래와 같다.

앞서의 이미지보다는 약간 정돈된 느낌을 주지만, 뭐...



Step 8 : 두번째 이미지를 읽어들여서 HSV로 바꾼뒤에 다시 H 값을 얻습니다.
이 코드는 앞서 설명한 코드와 동일한 부분이므로,  그냥 Pass
그리고 나머지 부분도 그대로 앞서와 동일한 코드이므로 그대로 진행합니다.


Step 9 :  마지막으로 MeanShift를 수행합니다.

     cv::TermCriteria criteria(cv::TermCriteria::MAX_ITER,10,0.01);
     cout << "meanshift= " << cv::meanShift(result,rect,criteria) << endl;

이렇게 얻은 사각형을 이미지에 그리고 화면에 출력합니다.
이렇게 얻어낸 이미지는 이 글의 마지막에 있습니다.



완성된 코드는 아래와 같습니다.

#include <iostream>
#include <vector>
using namespace std;
 

#include <QtCore/QCoreApplication>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/contrib/contrib.hpp>

#include "colorhistogram.h"
#include "objectFinder.h"
 



int main(int argc, char *argv[])
{
    cv::Mat hsv;

    QCoreApplication a(argc, argv);

    // Read Data
    cv::Mat image = cv::imread( "./0172.jpg" );
    if (!image.data)
            return 0;
 

    // Set ROI
    cv::Mat imageROI = image(cv::Rect(127, 170 , 120 , 80));
    cv::rectangle(image,cv::Rect(127, 170 , 120 , 80),cv::Scalar(0,0,255));
 

    //Display Origitanl Image
    cv::namedWindow("Image 1 :: Orignal");
    cv::imshow("Image 1 :: Orignal",image);
 


    // Get HUE histogram
    ColorHistogram hc;
    int minSat = 65;
 

    //cv::MatND colorhist = hc.getHueHistogram( imageROI ,  minSat );
    cv::MatND colorhist = hc.getHueHistogram( imageROI );
 


    // Object Finder
    ObjectFinder finder;
    finder.setHistogram(colorhist);
    finder.setThreshold(0.2f);
 


    //convert to HSV space
    cv::cvtColor(image, hsv, CV_BGR2HSV);
 

    //split image
    vector<cv::Mat> v;
    cv::split(hsv,v);
 

    // Identify pixel with low saturation
    cv::threshold(v[1],v[1], minSat, 255,cv::THRESH_BINARY);
    cv::namedWindow("Saturation");
    cv::imshow("Saturation",v[1]);
 

    // Let's obtain backrojection of the hue channel
    // Get back-projection of hue histogram
    int ch[1]={0};
    cv::Mat result= finder.find(hsv,0.0f,180.0f,ch,1);
    cv::namedWindow("Result Hue");
    cv::imshow("Result Hue",result);
 

    // Eliminate low saturation pixels
    cv::bitwise_and(result,v[1],result);
    cv::namedWindow("Result Hue and");
    cv::imshow("Result Hue and",result);
 


    // load second image
    image = cv::imread("./0181.jpg");

    // Display image
     cv::namedWindow("Image 2");
     cv::imshow("Image 2",image);
 

     // Convert to HSV space
     cv::cvtColor(image, hsv, CV_BGR2HSV);

     // Split the image
     cv::split(hsv,v);

     // Eliminate pixels with low saturation
     cv::threshold(v[1],v[1],minSat,255,cv::THRESH_BINARY);
     cv::namedWindow("Saturation");
     cv::imshow("Saturation",v[1]);
 

     // Get back-projection of hue histogram
     result= finder.find(hsv,0.0f,180.0f,ch,1);

     cv::namedWindow("Result Hue");
     cv::imshow("Result Hue",result);
 

     // Eliminate low stauration pixels
     cv::bitwise_and(result,v[1],result);
     cv::namedWindow("Result Hue and");
     cv::imshow("Result Hue and",result);
 

     // Get back-projection of hue histogram
     finder.setThreshold(-1.0f);
     result= finder.find(hsv,0.0f,180.0f,ch,1);
     cv::bitwise_and(result,v[1],result);
     cv::namedWindow("Result Hue and raw");
     cv::imshow("Result Hue and raw",result);
 

     cv::Rect rect(127, 170 , 120 , 80);
     cv::rectangle(image, rect, cv::Scalar(0,0,255));

     cv::TermCriteria criteria(cv::TermCriteria::MAX_ITER,10,0.01);
     cout << "meanshift= " << cv::meanShift(result,rect,criteria) << endl;

     cv::rectangle(image, rect, cv::Scalar(0,255,0));
 

    // Display Image
    cv::namedWindow("Image Result");
    cv::imshow("Image Result",image);
 

    cv::waitKey();
    return 0;


}


트래킹된 결과는 아래와 같습니다.


 위의 두개의 이미지를 가지고 자동차의 움직임을 추적하는 것입니다.




'Computer Vision' 카테고리의 다른 글

OpenCV를 이용한 Face Detection  (0) 2013.05.19
3D Noise Reduction algorithm test  (0) 2011.10.05
OpenCV 2.3 Computer vision (3)  (0) 2011.09.06
OpenCV 2.3 Computer vision (2)  (0) 2011.09.05
OpenCV 2.3 Computer vision (1)  (2) 2011.09.05
Posted by GUNDAM_IM
Computer Vision2011. 9. 6. 10:22
Creating a GUI application using QT

앞절에서는 Qt의 기본적인 내용만 정리한 것이고 , 이번에는 Qt와 OpenCV를 연결하여 좀더 Qt의  GUI를 사용하는 것을 테스트 합니다.   Graphic 관련 데이터를 처리하는데 O/S마다 종속성도 존재하고 귀찮은 GUI를 일일이 만들기도 그렇고 할때 딱 좋은 것이 이 Qt + OpenCV 조합입니다. 필요한 함수는 다 있으므로 이것을 이용해서 알고리듬을 만들어서 테스트 해보고 필요한 부분만 들어 내에서 H/W로 변경하면 됩니다.

이 OpenCV조합을 SystemC로 연결시켜서 테스트 할 수 있고 또 SystemC 조합을 다시 SDL로 연결시켜서 해볼 수 있기 때문에 이런것을 한번 알아 두면 두고두고 조합하면서 써먹을 수 있습니다. - 쉽게 말하면 아주 편하다는 의미입니다. 


이번에는 Create Project에서 QT GUI를 선택합니다.

 
프로젝트 이름은 원하는것으로 정하고 만들면 아래와 같이 만들어집니다.

 
위에서 중요한 것이  GUI 어플을 위한 Form입니다.
Visual base의 Form과 비슷한데 하여튼  GUI Template로 생각하면 됩니다.
GUI Template를 아래와 같이 만듭니다.

 
Push Button을 두개 넣어 두고 이름을 위와 같이 합니다.
버튼의 정식 이름은 오른쪽에 조그마한 창에 나오는데 이 버튼의 이름을
PB_OpenImage와 PB_Process로 정합니다.

 
이제 이벤트를 추가하면 됩니다.
이벤트는 버튼이 Push되었을때 즉  Click되었을때를 추가하면 됩니다.

 QT에서는  Event를 처리하는 개념을  Slot 을 추가한다고 합니다.
Slot을 추가하기 위해서는 마우스의 버튼 혹은 콘트롤 버튼과 함께 클릭하면 아래와 같은 Pop Up 매뉴가 나옵니다.
여기서  Slot 추가 매뉴 Go to Slot을 선택합니다.


 그럼 아래 창이 나타나는데 여기서 clicked를 추가합니다.

 
그럼 코드에 아래와 같이 나옵니다.

void MainWindow::on_PB_OpenImage_clicked()
{
    
}

같은 방법으로 Process도 만듭니다.

시작시에 말했듯이 이 프로그램은 Image를 읽어들여서 작업하는 프로그램입니다. 이미지를 읽어들여서 저장하기 위해서는 별도의 변수가 필요합니다. 엄밀하게는 이미지를 저장할 공간을 필요로 합니다.

다음과 같이 이미지를 저장할 변수를 추가합니다.


private 공간에 cv::Mat image를 추가합니다.
각각의 버튼이 눌려졌을때의 함수는 아래와 같이 추가를 합니다.

#include <QFileDialog>
...
 
void
MainWindow::on_PB_OpenImage_clicked()
{
    QString filename = QFileDialog::getOpenFileName( this, tr("Open Image") , "." , tr("Image Files (*.png *.jpg * jpeg *.bmp)")) ;
    image = cv::imread(filename.toAscii().data());
    cv::namedWindow("Original Image");
    cv::imshow("Original Image", image);
}

 
그리고 컴파일을 하면 아래와 같이 실행됩니다.
- project 파일에 옵션 추가하는 것은 2번째 글을 참고하시기 바랍니다.

 
  OpenImage를 눌러서 파일 다이얼로그를 띄우고 잘 처리하면 됩니다.

  Process에 대한 함수는 아래와 같이 추가합니다.

void MainWindow::on_PB_Process_clicked()
{
 cv::flip(image , image , 1);
 cv::namedWindow("Output Image");
 cv::imshow("Output Image", image);
}
 

위의 코드는 읽어들인  image를 flip시키는 것입니다.

컴파일과 실행하면 아래와 같이 나옵니다.



주) 항상 함수 하나 추가해보고 테스트 해보는 식으로 하는 것이 나중에 디버깅이 쉬워집니다.

이제 좀더 다음 단계로  다이얼로그 박스에 결과를 내보내는 것을 해보겠습니다.

먼저 Qt에서는 그래픽 데이터를 Label로 출력할 수 있으므로 Dialog에 label을 추가 합니다.



그리고 코드를 다음과 같이 수정합니다.


void MainWindow::on_PB_Process_clicked()
{
 cv::flip(image , image , 1);
 // cv::namedWindow("Output Image");
 // cv::imshow("Output Image", image);

 // Qt Image
 QImage img = QImage (( const unsigned char *) (image.data) , image.cols , image.rows, QImage::Format_RGB888);

// display on label
 ui->label->setPixmap( QPixmap::fromImage(img));
 ui->label->resize(ui->label->pixmap()->size());

}

  이제 실행하면 됩니다.

  

'Computer Vision' 카테고리의 다른 글

3D Noise Reduction algorithm test  (0) 2011.10.05
OpenCV 2.3 Computer vision (4)  (4) 2011.09.14
OpenCV 2.3 Computer vision (2)  (0) 2011.09.05
OpenCV 2.3 Computer vision (1)  (2) 2011.09.05
OpenCV 2.1 맥에서 빌드하기  (0) 2010.09.04
Posted by GUNDAM_IM
Computer Vision2011. 9. 5. 13:19
QT에 연결해서 빌드하기

QTCreator를 실행시킨뒤에 Create Project를 선택합니다.

 
Other Project에서 Console Project를 선택합니다.

 
이름은 아래와 같이 결정하다.

 

코드는 아래와 같이 추가해 둡니다.


#include
<QtCore/QCoreApplication>

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    cv::Mat image = cv::imread("baboon.jpg");
    cv::namedWindow("My First QT Window");
    cv::imshow("My First QT Window",image);
    cv::waitKey(5000);
    return a.exec();
}




그리고 Project file에서 아래 부분을 추가합니다.


INCLUDEPATH += /usr/local/include

LIBS+= -L/usr/local/lib \
-lopencv_core\
-lopencv_highgui\
-lopencv_imgproc\
-lopencv_features2d\
-lopencv_calib3d

그리고 컴파일한 뒤에 실행하면 아래와 같은 창이 보입니다.



'Computer Vision' 카테고리의 다른 글

OpenCV 2.3 Computer vision (4)  (4) 2011.09.14
OpenCV 2.3 Computer vision (3)  (0) 2011.09.06
OpenCV 2.3 Computer vision (1)  (2) 2011.09.05
OpenCV 2.1 맥에서 빌드하기  (0) 2010.09.04
SURF Lib  (3) 2010.06.22
Posted by GUNDAM_IM
Computer Vision2011. 9. 5. 13:18
오래간만에 보는 전공 (?) 서적인 OpenCV 2 Computer vision application programming cookbook입니다.

Embedded 혹은 non windows 개발을 위해서 QT와 windows에서는 Visual studio에서 차례로 설명합니다.
내용은 어려운것이 없으니 쉽게 술술 읽어가면서 해볼 수있습니다.

OpenCV를 다운 받을 수 있는 홈페이지는 아래와 같습니다.
http://opencv.willowgarage.com/wiki/

최근에는 Android 버전으로도 Release되고 있는데 BETA입니다.
- 안정성에서는 확인한적이 없습니다.

QT를 다운 받을 수 있는 사이트는 아래와 같습니다.
qt.nokia.com

그리고 OpenCV 현재 버전은 2.3입니다. 2011년 7월에 Release되었습니다.

(MAC인 관계로.. ) QT도 설치하고 OpenCV도 설치합니다.

QT는 설치가 쉬운데 다운받아서 Pkg install만 하면 됩니다. 그럼 아래와 같은 창을 볼 수 있습니다.



OpenCV의 컴파일 및 설치
- OSX 기준

cmake를 사용하면 되는데 일단 소스 코드 폴더에서 cmake를 치면 다음과 같은 메시지를 마지막에 볼 수 있습니다.

Generators

The following generators are available on this platform:
  Unix Makefiles              = Generates standard UNIX makefiles.
  Xcode                       = Generate Xcode project files.
  CodeBlocks - Unix Makefiles = Generates CodeBlocks project files.
  Eclipse CDT4 - Unix Makefiles
                              = Generates Eclipse CDT 4.0 project files.
  KDevelop3                   = Generates KDevelop 3 project files.
  KDevelop3 - Unix Makefiles  = Generates KDevelop 3 project files.
...

위의 것을 기준으로 보면 Unix Makefiles와 XCode등을 해 볼 수 있습니다.
일단 Unix Makefile을 기준으로 한다면 아래와 같습니다.

cmake -G "Unix Makefiles"
 로 하면 makefile이 만들어집니다.

 이후에 
make all
make install
을 하여서 컴파일 및 설치를 완료 합니다.
 

같은 방법으로, XCode를 사용해서 하면 쉽게 컴파일을 할 수 있습니다.

cmake -G Xcode

로 하면 

OpenCV.xcodeproj

파일이 만들어 집니다. 이걸 XCode에서 불러들여서 컴파일하면 됩니다.

그리고,
인텔 IPP나 TBB등을 사용하면 빨라지겠지만 지금은 그냥 Pass
나중에 좀더 빠른게 필요해지면 그때 검토하고 지금은 쉽게 쉽게 갑니다.

Windows용도 Visual Studio에서 컴파일이 가능합니다.


Sample Program 빌드
테스트를 위해서 samples 폴더에서 하나를 빌드해 봅니다.
dft.cpp를 가지고 빌드합니다.

g++을 사용하며 아래와 같이 빌드합니다.

g++ -o dft.elf dft.cpp -L/usr/local/lib -lopencv_core -lopencv_highgui -lopencv_ml -lopencv_imgproc 

실행은 아래와 같습니다.
./dft.elf stuff.jpg




이 책의 소스 코드는 PacktLib에서 다운 받을 수 있습니다.




 

'Computer Vision' 카테고리의 다른 글

OpenCV 2.3 Computer vision (3)  (0) 2011.09.06
OpenCV 2.3 Computer vision (2)  (0) 2011.09.05
OpenCV 2.1 맥에서 빌드하기  (0) 2010.09.04
SURF Lib  (3) 2010.06.22
Rob Hess의 SIFT [8]  (7) 2009.06.21
Posted by GUNDAM_IM
Computer Vision2010. 9. 4. 10:59
오래간만에 시간이 조금 나서 OpenCV 2.1을 빌드해보았습니다.

크게 바뀐점은 이전에는 make로 했지만 지금은 cmake로 한다는 점입니다.

우선 아래사이트에서 소스 코드를 다운 받습니다.

   http://sourceforge.net/projects/opencvlibrary/files/opencv-unix/2.1/

그리고 카피해서 압축을 풉니다.

   GUNDAM-NT:OpenCV kevinim$ cp ~/Downloads/OpenCV-2.1.0.tar.bz2 .
   GUNDAM-NT:OpenCV kevinim$ bzip2 -d OpenCV-2.1.0.tar.bz2
   GUNDAM-NT:OpenCV kevinim$ tar xvf OpenCV-2.1.0.tar  

일단 머신에 cmake가 없다면 설치를 합니다.
    http://www.cmake.org/cmake/resources/software.html
에 가면 소스랑 바이너리가 있는데 일단 귀찮으니까 바이너리를 받아서 설치합니다

빌드는 아래와 같은 순서로 합니다.

mkdir release
cd release
GUNDAM-NT:release kevinim$ cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D BUILD_PYTHON_SUPPORT=ON ..

이후에 make 를 하면 됩니다.

GUNDAM-NT:release kevinim$ make
Scanning dependencies of target zlib
[  0%] Building C object 3rdparty/zlib/CMakeFiles/zlib.dir/adler32.o
[  0%] Building C object 3rdparty/zlib/CMakeFiles/zlib.dir/compress.o
[  0%] Building C object 3rdparty/zlib/CMakeFiles/zlib.dir/crc32.o
[  0%] Building C object 3rdparty/zlib/CMakeFiles/zlib.dir/deflate.o
[  0%] Building C object 3rdparty/zlib/CMakeFiles/zlib.dir/example.o
[  1%] Building C object 3rdparty/zlib/CMakeFiles/zlib.dir/gzio.o
[  1%] Building C object 3rdparty/zlib/CMakeFiles/zlib.dir/infback.o
[  1%] Building C object 3rdparty/zlib/CMakeFiles/zlib.dir/inffast.o
[  1%] Building C object 3rdparty/zlib/CMakeFiles/zlib.dir/inflate.o
[  1%] Building C object 3rdparty/zlib/CMakeFiles/zlib.dir/inftrees.o
[  1%] Building C object 3rdparty/zlib/CMakeFiles/zlib.dir/trees.o
[  1%] Building C object 3rdparty/zlib/CMakeFiles/zlib.dir/uncompr.o
[  2%] Building C object 3rdparty/zlib/CMakeFiles/zlib.dir/zutil.o
Linking C static library ../lib/libzlib.a
[  2%] Built target zlib
Scanning dependencies of target cxcore_pch_dephelp
[  2%] Building CXX object src/cxcore/CMakeFiles/cxcore_pch_dephelp.dir/cxcore_pch_dephelp.o
Linking CXX static library ../../lib/libcxcore_pch_dephelp.a
[  2%] Built target cxcore_pch_dephelp
.......

마지막으로

sudo make install

을 하면 설치 완료

흠.. 이전보다는 쉬워졌습니다.

테스트는 간단한 샘플 프로그램을 실행하면 됩니다.

OpenCV src 폴더에서
cd samples/python

GUNDAM-NT:python kevinim$ python delaunay.py

을 하면 됩니다.

우선 에러가 발생하는데

Traceback (most recent call last):
  File "delaunay.py", line 9, in <module>
    import cv
ImportError: No module named cv

opencv 라이브러리 모듈을 찾지 못해서 발생한 오류입니다.
귀찮으니 소스 코드를 수정해 줍니다.

vi delaunay.py

파일의 시작 부분에 아래 행을 추가합니다.

import sys
sys.path.append("/usr/local/lib/python2.6/site-packages")

그런 뒤에 실행하면 됩니다.

사용자 삽입 이미지
사용자 삽입 이미지



'Computer Vision' 카테고리의 다른 글

OpenCV 2.3 Computer vision (2)  (0) 2011.09.05
OpenCV 2.3 Computer vision (1)  (2) 2011.09.05
SURF Lib  (3) 2010.06.22
Rob Hess의 SIFT [8]  (7) 2009.06.21
Rob Hess의 SIFT [7]  (1) 2009.04.30
Posted by GUNDAM_IM
Computer Vision2010. 6. 22. 01:49
SURF는 2006년 호주의 Garz가 제일 먼저 제안한 알고리즘입니다.
SIFT보다 계산량을 단순화 시키고 (특정 논문에서는 4배 정도 빠르다고 결과를 발표하였습니다)
대신 결과의 퀄리티는 비슷하다고 강조하고 있습니다.


http://www.vision.ee.ethz.ch/~surf/
  비 상업용으로 쓰인다는 전제 하에서 Linux용 C코드와  Windows용 DLL을 제공하고 있습니다.

http://www.chrisevansdev.com/computer-vision-opensurf.html
  Chris evans가 정리한 SURF 관련 자료 및 C++과 C#으로 쓰여진 라이브러리를 제공
  오픈 라이브러리인 만큼 라이브러리에 대한 용법이 설명된 매뉴얼도 제공됩니다

http://www.springerlink.com/content/tg61524386764t2t/
 관련 논문을 참조하기 바라고, (해당 사이트에 있습니다.)
 병렬처리로 빠르게 한다는 기본 개념입니다.

http://labe.felk.cvut.cz/~tkrajnik/fpga-surf/
  FPGA에 SURF를 넣은 자료
  2009년에 발표했으며 관련 논문과 FPGA자료를 오픈하고 있습니다.
  소스코드라고 하지만 실제로는 Netlist이며 (어찌보면 당연한 말씀..)
  논문이 참고할 만한 자료입니다.
  코드로 구현한다면 논문보고 하드웨어로 만드는게 더 빠를듯..


아래는 간단한 동영상




'Computer Vision' 카테고리의 다른 글

OpenCV 2.3 Computer vision (1)  (2) 2011.09.05
OpenCV 2.1 맥에서 빌드하기  (0) 2010.09.04
Rob Hess의 SIFT [8]  (7) 2009.06.21
Rob Hess의 SIFT [7]  (1) 2009.04.30
OpenCV - Alpha Blending cvAddWeighted , cvFillPoly  (2) 2009.04.25
Posted by GUNDAM_IM
Computer Vision2009. 6. 21. 03:40

Rob Hess의 SIFT 8번째


() 글을 읽기 전에
글은 저와 같은  초보자를 위해서 정리하는 것입니다.
전문가시라면 굳이 읽을 필요가 없습니다.
공부하면서 정리하는 글이라서 서툰 부분이 많이 보입니다. 이해하여 주시고

틈틈이 새로운 것을 알게 되면 그때 그때 업데이트 하겠습니다.



(주) 시작하기 전에

실제 코드를 한번 따라가기 전에 SIFT 알고리즘을 간략하게 정리하여둡니다.

코드를 기계적으로 따라가는것 보다는 알고리즘을 이해하고 따라가는 것이 유용하기 때문입니다.

물론 그렇다고 제가 알고리즘을 다 이해하는 것은 아닙니다.

그냥 초보 수준에서 아는 것들만 정리하였습니다.



PPT 발표 자료는 이 페이지를 참조 하세요 : SIFT 정리.PPT



발표자료를 기반으로 하여서 추가적으로 정리한 내용입니다.



1. Harris Corner Detector

특징으로는 다음과 같습니다.

  Rotation 에 대해 검출이 가능하다.

  부분 이미지로도 검출이 가능하다.

{

해석 :

이상의 말을 풀이하면

H.C.Detector는 영상이  회전된 것 그리고 밝기의 변화와 이미지 상에서 노이즈가 있어도

어느정도 이를 견디어 내며 원하는 포인트를 찾아낼 수 있다는 의미가 됩니다.

H.C.Detector는 Local Auto Correlation Function에 기반합니다.

기본적인 아이디어는 전체 이미지를 한방에 뒤지는 것이 아니고

주어진 이미지 영역에서 작은 이미지 영역 (부분 영역)을 설정하여 이 윈도우를 주변 영역과 비교하여

커다란 차이점이 있는 부분을 찾아내는 방식입니다.

설정된 이미지에 대해서 뒤지는 방향은 아무 방향이나 상관이 없습니다. 다만 주어진 부분 영역에 대해서

큰 변화가 생기는 방향으로 이동해야 하곘지요


아래 그림을 보면 쉽게 이해됩니다.

사용자 삽입 이미지


 

제일 왼쪽 그림은 뒤져서 변화가 없으므로 “Flat”으로 보게 됩니다.

가운데 그림은 상하로만 선분이 있다는 것을 알게 됩니다.

- 에지 방향으로 변화가 없다는 것은 에지가 존재한다는 의미가 됩니다.

오른쪽 그림은 모든 방향으로 변화가 존재하기 때문에

“Conor”라고 보는 것 입니다.


- 수학적인 의미는 다음에 하기로 하고 여기선 패스 합니다.

- SIFT가 우선이므로, H.C.Detector는 이정도에서 정리합니다.


매트랩에 대한 코드는 아래를 참고하시기 바랍니다.

http://ipl.cnu.ac.kr/mayadata/harris/harris_corner_detector.htm


}


사용자 삽입 이미지

상기 그림을 실제 H.C.Detector에 걸면 다음과 같은 영상을 얻을 수 있습니다.

사용자 삽입 이미지


그리고 이 그림의 임계치 이상만을 검출하면 다음과 같습니다.


사용자 삽입 이미지


임계치 이상 영역에서 최대값만을 표시하면 다음과 같습니다.



사용자 삽입 이미지

요것이 바로 코너 포인트가 되는 것입니다.


  이 코너포인트를 원본 그림과 매핑하면 다음과 같습니다.


사용자 삽입 이미지


문제점 :

크기 변화에대해 대처하지 못한다.

사용자 삽입 이미지

   위의 그림처럼 원래 EDGE로 인식되는 것이 스케일을 작에 줄이면, 코너로 바뀌는 경우가 발생합니다.

   이처럼 크기가 변하는 것에 따러 검출되는 성분이 변하기 때문에 크기 변화에 대응하지 못하는 것이라고

   합니다. - 당연한 이야기 인듯..



관련 자료는 이페이지에 있습니다.

매트랩등등의 코드를 함께 제공하기 때문에 공부하실 분들은 이 페이지를 참고하여 주세요


http://ipl.cnu.ac.kr/mayadata/harris/harris_corner_detector.htm

그리고 위에 설명에 사용된 그림은

lect9-slides.pdf

을 참고하시기 바랍니다.



'Computer Vision' 카테고리의 다른 글

OpenCV 2.1 맥에서 빌드하기  (0) 2010.09.04
SURF Lib  (3) 2010.06.22
Rob Hess의 SIFT [7]  (1) 2009.04.30
OpenCV - Alpha Blending cvAddWeighted , cvFillPoly  (2) 2009.04.25
JPEG2AVI 를 맥에서 빌드하기  (0) 2009.04.24
Posted by GUNDAM_IM
Computer Vision2009. 4. 30. 00:07


SIFT의 동작은


아래와 같이 호출됩니다.


int sift_features( IplImage* img, struct feature** feat )

{

  return _sift_features( img, feat,

SIFT_INTVLS,

SIFT_SIGMA,

SIFT_CONTR_THR,

                         SIFT_CURV_THR,

SIFT_IMG_DBL,

SIFT_DESCR_WIDTH,

                         SIFT_DESCR_HIST_BINS );

}


영상과 feature는 포인터로 전달되고 나머지는  매크로로 정의되어 있습니다. 이렇게 하면

최상위 함수는 매크로에 따라 파라미터를 줄 수 있고 이하 하위 함수들은 인자들을 기반으로 할 수 있으므로

프로그램 테스트 등이 편리해집니다.


정의된 매크로들은 나중에 코드를 읽어가면서 새로운 그리고 필요한 매크로가 나온다면, 그때마다

하나씩 확인해 가기로 하고 여기서는 건너 뜁니다.


실제 호출은 위의 코드에서 보는 바와 같이 _sift_features를 호출하여 구동합니다.

이 함수는 다음과 같은 순서로 동작합니다.


1. 인자를 검사해서 오류가 있는지 확인을 합니다.

2. 주어진 이미지로 이미지 피라미드를 구축합니다.

3. 구축한 이미지 피라미드에서 DoG를 구축합니다.

4. DoG에서 특징점들을 추출하고

5. 특징점 을 좌표에 매핑하고,

6. 특징점 기술자들을 논문대로 정리한다.


이를 위한 호툴된 함수는 다음과 같습니다.

기계적으로 따라갑니다.


int _sift_features( IplImage* img, struct feature** feat, int intvls,

                    double sigma, double contr_thr, int curv_thr,

                    int img_dbl, int descr_width, int descr_hist_bins )

{

  IplImage* init_img;

  IplImage*** gauss_pyr, *** dog_pyr;

  CvMemStorage* storage;

  CvSeq* features;

  int octvs, i, n = 0;


  /* check arguments  

인자를 검사한다. NULL Pointer이면 에러를 출력한다.*/


  if( ! img )

    fatal_error( "NULL pointer error, %s, line %d",  __FILE__, __LINE__ );

  if( ! feat )

    fatal_error( "NULL pointer error, %s, line %d",  __FILE__, __LINE__ );


  /* build scale space pyramid; smallest dimension of top level is ~4 pixels

      이미지 피라미드를 구축한다.

     최상위 피라미드는 그 크기가 4 픽셀 정도이다.

   */


/* 최초의 이미지를 만들어 냅니다.

   이 이미지는 그레이 스케일로 생성됩니다.. */

  init_img = create_init_img( img, img_dbl, sigma );


  octvs = log( MIN( init_img->width, init_img->height ) ) / log(2) - 2;


/* 이미지를  가지고 가우시안 스케일 피라미드를 구성합니다. */

  gauss_pyr = build_gauss_pyr( init_img, octvs, intvls, sigma );


/* DoG 이미지 피라미드를 구성합니다. */

  dog_pyr = build_dog_pyr( gauss_pyr, octvs, intvls );


  storage = cvCreateMemStorage( 0 );


DoG에서 특징점들을 열심히 추출합니다.

  features = scale_space_extrema(

dog_pyr,

octvs,

intvls,

contr_thr,

                            curv_thr,

storage );


/* 추출된 특징들의 특성들을 계산합니다. */

  calc_feature_scales( features, sigma, intvls );


/*  이미지가 2배로 키워서 특징점들을 추출하였을 경우 이를 다시 조절합니다. */

  if( img_dbl )

    adjust_for_img_dbl( features );


/* 정규 좌표를 계산합니다. */

  calc_feature_oris( features, gauss_pyr );


/* Lowe’s Paper 6절에 따라서 특징점 기술자를 만들어냅니다. */

  compute_descriptors( features, gauss_pyr, descr_width, descr_hist_bins );



  /* sort features by decreasing scale and move from CvSeq to array */


  cvSeqSort( features, (CvCmpFunc)feature_cmp, NULL );


  n = features->total;


  *feat = calloc( n, sizeof(struct feature) );


  *feat = cvCvtSeqToArray( features, *feat, CV_WHOLE_SEQ );


  for( i = 0; i < n; i++ )

    {

      free( (*feat)[i].feature_data );

      (*feat)[i].feature_data = NULL;

    }


  cvReleaseMemStorage( &storage );

  cvReleaseImage( &init_img );

  release_pyr( &gauss_pyr, octvs, intvls + 3 );

  release_pyr( &dog_pyr, octvs, intvls + 2 );

  return n;


}


'Computer Vision' 카테고리의 다른 글

SURF Lib  (3) 2010.06.22
Rob Hess의 SIFT [8]  (7) 2009.06.21
OpenCV - Alpha Blending cvAddWeighted , cvFillPoly  (2) 2009.04.25
JPEG2AVI 를 맥에서 빌드하기  (0) 2009.04.24
OpenCV - cvSmooth  (2) 2009.04.22
Posted by GUNDAM_IM
Computer Vision2009. 4. 25. 15:04

Alpha Blending


알파 블랜딩을 OpenCV에서 하는 것을 구현해 보았습니다.

코드를 읽어가면서 정리하였습니다.


1. 프로그램의 순서


순서는 다음과 같습니다.


(1) 이미지 화일을 읽어들이고

      ...

      cvLoadImage

  ...

(2) 알파블랜딩할 이미지를 만듭니다. - 이경우는 만들었지만 다른 이미지를 사용해도 됩니다.

...

cvFillPoly

...


(3) 원본 이미지와 알파블랜딩할 이미지의 크기가 틀리다면

      ROI로 서로의 크기를 맞추어 줍니다.

.....

cvSetImageROI

....

cvResetImageROI

...


(4) 적절한 비율로 블랜딩합니다.

....

cvAddWeighted

....


(5) 이후에 정리합니다.

  cvSaveImage(argv[2] , imgA );

  .....

      cvReleaseImage(&imgA);

      cvReleaseImage(&imgB);



2. 새로운 함수


2.1 cvFillPoly


여기에서 새로 나온 이미지 처리 함수는 다음과 같습니다.


cvFillPoly


2차원 폴리곤을 만들어서 그 폴리곤을 그리고 내부를 채웁니다.

폴리곤의 꼭지점 개수는 제한이 없습니다. 다만 시작하기 전에 해당 폴리곤의 꼭지점 개수를 알려주어야 합니다.



이 함수를 사용하기 위해서 다음과 같은 순서로 합니다.


(1)  폴리곤을 만듭니다. 이 프로그램에서 코드는 아래와 같습니다.

  ....

  CvPoint imgb_rectangle_pts[4] = { cvPoint( 0, 0) ,

    cvPoint(0,imgb_size.width),

    cvPoint(imgb_size.height,imgb_size.width),

    cvPoint(imgb_size.height,0)

  };

   ...

  CvPoint *PointArray[2] = { & imgb_rectangle_pts[0]  , 0 } ;

  ...


 (2) 폴리곤의 개수와 각 폴리곤의 꼭지점 개수를 정합니다.

       

  int PolyVertexNumber[2] = { 4 , 0 } ;

  int PolyNumber = 1 ;


  지금은 하나뿐이므로, 한개의 폴리곤만을 지정한다.

 

 (3) 그리고 함수를 호출합니다.


  cvFillPoly(imgB ,

    PointArray ,

    PolyVertexNumber ,

    PolyNumber,

    CV_RGB(5,5,5),8,0);



2.2 cvAddWeighted


알파블랜딩을 해주는 함수입니다.

사용은 쉽습니다.

각 이미지 별로 가중치를 곱해서 더하는 것입니다


호출은 아래와 같습니다.

  ......

  double alpha = 0.5 ;

  double beta  = 1.0 - alpha ;

  cvAddWeighted(imgA, alpha , imgB , beta , 0.0 , imgA );

  ......







3. 전체 코드


전체 코드는 아래와 같습니다.


--------------------------------------------------------------------------------------------------


#include <stdio.h>

#include <unistd.h>

#include <string.h>

#include <errno.h>


#include <opencv/cv.h>

#include <opencv/highgui.h>




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


  // 파라미터를 체크합니다.

  // 귀찮으니까 간단하게 개수만 체크합니다.

  if( argc < 2 )

   {

      printf("usage : alpha src dst\n");

      exit(0);

   }


  // 원본 이미지를 읽어들입니다.

  IplImage *imgA = cvLoadImage( argv[1] , 1);

  //알파 블랜딩할 이미지를 만듭니다. 사각형으로 만들기로 하겠습니다.

  //입력되는 이미지의 크기가 정해진 것이 아니므로,

  //입력 이미지의 크기를 갖고 와서 상대적으로 높이를 맞춥니다.

  //넓이는 150 픽셀 정도로 맞춥니다.

  CvSize imga_size = cvGetSize(imgA);

  CvSize imgb_size = cvSize(150,imga_size.height);

  IplImage *imgB = cvCreateImage( imgb_size  , IPL_DEPTH_8U, 3);


  // 이제 내부에 채워지는 4각형을 만듭니다.

  // 사용할 함수는 cvFillPoly 입니다.

  CvPoint imgb_rectangle_pts[4] = { cvPoint( 0, 0) ,

    cvPoint(0,imgb_size.width),

    cvPoint(imgb_size.height,imgb_size.width),

    cvPoint(imgb_size.height,0)

  };



  CvPoint *PointArray[2] = { & imgb_rectangle_pts[0]  , 0 } ;

  int PolyVertexNumber[2] = { 4 , 0 } ;

  int PolyNumber = 1 ;

  cvFillPoly(imgB ,

    PointArray ,

    PolyVertexNumber ,

    PolyNumber,

    CV_RGB(5,5,5),8,0);


  // 원본 이미지와, 채울 이미지의 크기가 틀리기 때문에 원본 이미지에서 관심 대상

  // 영역을 설정합니다.

  cvSetImageROI(imgA, cvRect(0,0,imgb_size.width,imgb_size.height));


  // 드디어 알파블랜딩을 합니다. 

  double alpha = 0.5 ;

  double beta  = 1.0 - alpha ;

  cvAddWeighted(imgA, alpha , imgB , beta , 0.0 , imgA );

 

  // 이제 관심 영역으로 설정된 것을 풉니다.

  cvResetImageROI(imgA);



  // 폰트를 정합니다.

  CvFont font1;

  double hscale = 0.5;

  double vscale = 0.5;

  double shear = 0.0;

  int thickness = 1;

  int line_type = CV_AA;


  cvInitFont(&font1,CV_FONT_HERSHEY_COMPLEX,hscale,vscale,shear,thickness,line_type);


  // 글을 집어 넣습니다.

  cvPutText(imgA,"GUNDAM",cvPoint( 0,100) ,&font1,CV_RGB(255,255,255));

  cvPutText(imgA,"Red Commet",cvPoint( 0,120) ,&font1,CV_RGB(255,255,255));


  // 화면에 출력하고

  cvNamedWindow( "ImageA-1", 1) ;

  cvShowImage( "ImageA-1", imgA );

 

  cvWaitKey(0);

  cvDestroyWindow("ImageA-1");


  // 파일은 따로 저장합니다.

  cvSaveImage(argv[2] , imgA );


  // 그리고 끝냅니다.

  cvReleaseImage(&imgA);

  cvReleaseImage(&imgB);


 

}//end of main


--------------------------------------------------------------------------------------------------


4. 처리 결과


다음 그림은 그 결과입니다.

사용자 삽입 이미지

'Computer Vision' 카테고리의 다른 글

Rob Hess의 SIFT [8]  (7) 2009.06.21
Rob Hess의 SIFT [7]  (1) 2009.04.30
JPEG2AVI 를 맥에서 빌드하기  (0) 2009.04.24
OpenCV - cvSmooth  (2) 2009.04.22
Rob Hess의 SIFT [6]  (0) 2009.04.18
Posted by GUNDAM_IM
Computer Vision2009. 4. 24. 19:19

JPEG2AVI 를 맥에서 빌드하기


소스 코드는 이곳에서 다운로드 하면 됩니다.


http://sourceforge.net/projects/jpegtoavi/



README를 읽어보면 큰 문제는 없습니다. 그냥  make all을 하면 된다고 합니다.


하지만


make all


을 하면 다음과 같은 에러가 발생합니다.


gcc  -O3 -Wall -ansi -g -DLINUX -D__UNIX__ -DVERSION_MIN=5 -DVERSION_MAJ=1 -DVERBOSE=0 -c jpegtoavi.c -o jpegtoavi.o

In file included from jpegtoavi.c:28:

byteswap.h:5:20: error: endian.h: No such file or directory

byteswap.h:10:3: error: #error "Aiee: __BYTE_ORDER not defined\n";

jpegtoavi.c: In function ‘main’:

jpegtoavi.c:204: error: ‘off64_t’ undeclared (first use in this function)

jpegtoavi.c:204: error: (Each undeclared identifier is reported only once

jpegtoavi.c:204: error: for each function it appears in.)

jpegtoavi.c:204: error: syntax error before ‘jpg_sz_64’

jpegtoavi.c:206: error: nested functions are disabled, use -fnested-functions to re-enable

jpegtoavi.c:206: error: syntax error before ‘MAX_RIFF_SZ’

jpegtoavi.c:344: error: ‘jpg_sz_64’ undeclared (first use in this function)

jpegtoavi.c:351: error: ‘riff_sz_64’ undeclared (first use in this function)

jpegtoavi.c:354: error: ‘MAX_RIFF_SZ’ undeclared (first use in this function)



(1) endian.h는 machine/endian.h에 있다.

이를 수정한다.


== WAS ==

#include <endian.h>

#include <sys/types.h>

== IS ==

#include <machine/endian.h>

#include <sys/types.h>


(2) 나머지 에러는 그냥 다음과 같이 하여서 코드에 추가합니다.


#ifndef _OFF64_T_DEFINED

#define _OFF64_T_DEFINED

        typedef long long  off64_t;

#endif


그 후에 컴파일 하면 빌드가 잘 됩니다.



사용법은 간단합니다. 헬프를 치면 금방 알 수 있습니다.


jpg2avi -f fps imagesize jpegfile list > dst.avi


     -f fps : frame per second입니다.

     imagesize : Width , Height를 구분하여 입력합니다.

    그리고 jpeg file 이름을 나열합니다.


좀 황당한것이 avi 파일로 받기 위해서는 파이프를 통하여 받습니다.

파일로 세이브 할 것이지 정말..


하여튼 동작은 잘 합니다.


 ./jpegtoavi -f 1 844 633  IMG_1.jpg IMG_2.jpg IMG_3.jpg IMG_3.jpg IMG_4.jpg IMG_5.jpg IMG_6.jpg IMG_7.jpg IMG_8.jpg IMG_9.jpg > img.avi


첨부 파일은 img.avi를 올렸습니다.




다 올리고 홈피에 올리니,

사파리에서는 동영상이 잘 안보이네요

익스플로어에서는 보이는데,


이러다가 사파리를 고쳐야 할런지도~



'Computer Vision' 카테고리의 다른 글

Rob Hess의 SIFT [7]  (1) 2009.04.30
OpenCV - Alpha Blending cvAddWeighted , cvFillPoly  (2) 2009.04.25
OpenCV - cvSmooth  (2) 2009.04.22
Rob Hess의 SIFT [6]  (0) 2009.04.18
OpenCV - Convert Image  (0) 2009.04.11
Posted by GUNDAM_IM