2014년 12월 17일 수요일

Laplacian edge detection

sobel과 달리 하나의 배열을 가지고 계산함
#include <opencv\cv.h>
#include <opencv\highgui.h>

void main()
{

 IplImage* image = 0;                          // image 선언
    image = cvLoadImage("img.jpg", 1);     //img.jpg파일을 불러옴 1은 컬러로 받아옴, 0은 흑백으로 받아옴(rgb가 없음)
 int imageRatio = 1;

 CvSize size = cvSize(image->width*imageRatio, image->height*imageRatio);
 
 IplImage *tmpImg = cvCreateImage(size,IPL_DEPTH_8U,3);
 
 int width = image->width;
 int height = image->height;
 int index = image->widthStep;
 int avg;
 for(int i=0; i<height;i++){
  for(int j=0; j<width; j++){
   //gray scale
   int index2 = i*image->widthStep + j*3;
   avg = ((unsigned char)image->imageData[index2+0]+(unsigned char)image->imageData[index2+1]+(unsigned char)image->imageData[index2+2])/3;
   for(int k=0;k<3;k++)
    image->imageData[i*index+j*3+k] = avg;
   
  }
 }


 //라플라시안
 int laplacianMask[3][3] = {-1,-1,-1,-1,8,-1,-1,-1,-1};

 int edge;
 for(int i=1;i<height-1;i++){
 for(int j=1;j<width-1;j++){
 edge = 0;   
 for(int x=-1;x<2;x++){
 for(int y=-1;y<2;y++){
 edge += (unsigned char)image->imageData[(i+x)*index+(j+y)*3]*laplacianMask[x+1][y+1];
 }
 }
  
 if(edge >255) edge = 255;
 else if(edge<0) edge = 0;
 for(int k=0;k<3;k++)
 tmpImg->imageData[i*tmpImg->widthStep+j*3+k] = edge; 
 }

 }

 cvSaveImage("out.jpg",image);
 cvSaveImage("edge.jpg",tmpImg);
 
 cvNamedWindow( "original", 1);      // 윈도우 생성
 cvNamedWindow( "edge", 1);      // 윈도우 생성

    cvShowImage( "original", image );  // 이미지를 보여줌
    cvShowImage( "edge", tmpImg );  // 이미지를 보여줌
 
 cvWaitKey(0);                    // 사용자의 키 입력을 기다림
    
 
    cvDestroyWindow( "original" ); 
 cvDestroyWindow( "edge" ); 
 
}



결과


Coin edge detection

edge를 찾을때 G를 계산할때 루트를 씌우지 않았다. 즉, 255*255=65025일 때 픽셀값을 255로 맞추지 않고 여기서는 edge의 임계값을 50000으로 설정하여 세세하게 edge를 찾을 수 있도록 하였다.
 Mask는 convolution을 적용시켜서 값이 대칭이 되도록 초기화하였다.
#include <opencv\cv.h>
#include <opencv\highgui.h>

void main()
{

 IplImage* image = 0;                          // image 선언
    image = cvLoadImage("coins.jpg", 1);     //img.jpg파일을 불러옴 1은 컬러로 받아옴, 0은 흑백으로 받아옴(rgb가 없음)
 int imageRatio = 1;

 CvSize size = cvSize(image->width*imageRatio, image->height*imageRatio);
 
 IplImage *tmpImg = cvCreateImage(size,IPL_DEPTH_8U,3);
 
 int width = image->width;
 int height = image->height;
 int index = image->widthStep;
 int avg;
 for(int i=0; i<height;i++){
  for(int j=0; j<width; j++){
   //gray scale
   int index2 = i*image->widthStep + j*3;
   avg = ((unsigned char)image->imageData[index2+0]+(unsigned char)image->imageData[index2+1]+(unsigned char)image->imageData[index2+2])/3;
   for(int k=0;k<3;k++)
    image->imageData[i*index+j*3+k] = avg;
   
  }
 }

 //sobel edge 
 //배열에서 convolution 됨
 int rSobelMask[3][3] = {-1,0,1,-2,0,2,-1,0,1};
 int cSobelMask[3][3] = {-1,-2,-1,0,0,0,1,2,1};

 int rEdge = 0;
 int cEdge = 0;
 int edgeTHD = 50000;
 for(int i=1;i<height-1;i++){
  for(int j=1;j<width-1;j++){
   rEdge = 0; cEdge = 0;
   for(int x=-1;x<2;x++){
    for(int y=-1;y<2;y++){
     rEdge += (unsigned char)image->imageData[(i+x)*index+(j+y)*3]*rSobelMask[x+1][y+1];
     cEdge += (unsigned char)image->imageData[(i+x)*index+(j+y)*3]*cSobelMask[x+1][y+1];
    }
   }
   int G = (int)sqrt(rEdge*rEdge + cEdge*cEdge);
   if(G > 255) G = 255;
   else G = 0;
   
   for(int k=0;k<3;k++)
    tmpImg->imageData[i*tmpImg->widthStep+j*3+k] = G; 
  }

 }

 cvSaveImage("out.jpg",image);
 cvSaveImage("edge.jpg",tmpImg);
 
 cvNamedWindow( "original", 1);      // 윈도우 생성
 cvNamedWindow( "edge", 1);      // 윈도우 생성

    cvShowImage( "original", image );  // 이미지를 보여줌
    cvShowImage( "edge", tmpImg );  // 이미지를 보여줌
 
 cvWaitKey(0);                    // 사용자의 키 입력을 기다림
    
 
    cvDestroyWindow( "original" ); 
 cvDestroyWindow( "edge" ); 
 
}


결과


Image extension

for구문에서 rgb for구문 안에서 두 개의 for구문을 사용한다 

#include <opencv2\/opencv.hpp>
#include <opencv\cv.h>
#include <stdio.h>
using namespace cv;

void main()
{

  IplImage* image = 0;                          // image 선언
      image = cvLoadImage("img.jpg", 1);     //img.jpg파일을 불러옴 1은 컬러로 받아옴, 0은 흑백으로 받아옴(rgb가 없음)
 
  int width = image->width;
  int height = image->height;
  int index = image->widthStep;
  int ratio = 2;
  CvSize size = cvSize(width*ratio, height*ratio);
  IplImage *newImage = cvCreateImage(size, IPL_DEPTH_8U, 3);//세번째 인자값 1: 1=1채널(rgb가 없음) , 3=3채널
  for(int i=0;i<height;i++)
for(int j=0;j<width;j++){
for(int k=0;k<3;k++){
for(int ii=0;ii<ratio;ii++)
for(int jj=0;jj<ratio;jj++)
newImage->imageData[(i*ratio+ii)*newImage->widthStep+(j*ratio+jj)*3+k] = image->imageData[i*index+j*3+k];
}
}


  cvSaveImage("out.jpg",image);
  cvSaveImage("out2.jpg",newImage);
  
  cvNamedWindow( "openCV", 1);      // 윈도우 생성
  cvNamedWindow( "openCV2", 1);      // 윈도우 생성
      cvShowImage( "openCV", image );  // 이미지를 보여줌
  cvShowImage( "openCV2", newImage );  // 이미지를 보여줌
  cvWaitKey(0);                    // 사용자의 키 입력을 기다림
 
      cvDestroyWindow( "openCV" ); 
  cvDestroyWindow( "openCV2" );
}

결과

gray scale, binarization using opencv

주의할 점은 cvLoadImage함수와 cvCreateImage함수 호출 시 인자 값 설정이다.
cvLoadImage에서 1은 color로 그림을 받아오겠다는 것이고 0은 흑백으로 받아온다는 것이다. 
즉 1로 받아오면 rgb 레이어가 존재하고 0으로 받아오면 rgb레이어가 존재하지 않아서 widthStep으로 index를 계산하면 메모리 엑세스 에러가 떠서 프로그램이 동작하지 않는다.

cvCreateImage 또한 이미지를 생성할때 3을 넣으면 rgb레이어를 사용하는 3채널이고 1을 사용한다면 1채널으로 rgb 레이어가 존재하지 않는 것에 주의해야한다.

#include <opencv2\/opencv.hpp>
#include <opencv\cv.h>
#include <stdio.h>
using namespace cv;

void main()
{

  IplImage* image = 0;                          // image 선언
      image = cvLoadImage("img.jpg", 1);     //img.jpg파일을 불러옴 1은 컬러로 받아옴, 0은 흑백으로 받아옴(rgb가 없음)
 
  int width = image->width;
  int height = image->height;
  int index = image->widthStep;
  int avg;
  int thd = 90;
  CvSize size = cvSize(width, height);
  IplImage *newImage = cvCreateImage(size, IPL_DEPTH_8U, 3);//세번째 인자값 1: 1=1채널(rgb가 없음) , 3=3채널
  IplImage *newImage2 = cvCreateImage(size, IPL_DEPTH_8U, 3);//세번째 인자값 1: 1=1채널(rgb가 없음) , 3=3채널

  for(int i=0;i<height;i++)
for(int j=0;j<width;j++){
int index2 = i*index+j*3;
avg = ((unsigned char)image->imageData[index2+0]+(unsigned char)image->imageData[index2+1]+(unsigned char)image->imageData[index2+2])/3;
int avg2 = avg;
if(thd > avg2) avg2 = 255;
else avg2 = 0;
for(int k=0;k<3;k++)
{
newImage->imageData[index2+k] = avg;//gray scale
newImage2->imageData[index2+k] = avg2;//이진화
}
}


  cvSaveImage("out.jpg",image);
  cvSaveImage("out2.jpg",newImage);
  cvSaveImage("out3.jpg",newImage2);
  
  cvNamedWindow( "openCV", 1);      // 윈도우 생성
  cvNamedWindow( "openCV2", 1);      // 윈도우 생성
  cvNamedWindow( "openCV3", 1);      // 윈도우 생성
    
      cvShowImage( "openCV", image );  // 이미지를 보여줌
  cvShowImage( "openCV2", newImage );  // 이미지를 보여줌
cvShowImage( "openCV3", newImage2 );  // 이미지를 보여줌

  cvWaitKey(0);                    // 사용자의 키 입력을 기다림
 
      cvDestroyWindow( "openCV" ); 
  cvDestroyWindow( "openCV2" );
  cvDestroyWindow( "openCV3" );
}

결과(원본, Gray scale, 이진화)

image read, write using opencv

 opecv의 함수를 이용하여 윈도우 창을 생성하고 이미지를 출력하였다.
 cvNamedWindow, cvShowImage의 이름이 다르다면 cvShowImage에서 내부 이름으로 창을 새로 생성하게 된다.
 cvWaitKey함수는 사용자의 입력을 내부 파라미터 만큼 기다린다. 파라미터값은 ms단위이다. 
(ex: 5000이면 5초)

클래스 함수에서 self의 의미

코드
class FourCal:
def setData(self, first, second):
self.first = first
self.second = second

a = FourCal()
a.setData(4, 2)

함수에서 self의 의미란 무엇일까?

위의 a.setData() 함수에서는 인자값으로 self를 넘겨주지 않는다. 
그렇지만 실제 setData에서는 self로 a라는 인스턴스를 넘겨주어서 인스턴스의 first, second 변수를 초기화해주게 된다.

Instance와 Class 차이

- Class란? 객체를 정의한 것이다.
 Class는 객체를 생성하는데 사용된다. 

- Instance란? 객체가 클래스를 기반으로 실체화 된 것을 말한다. 즉, 클래스로부터 만들어진 객체를 그 클래스의 인스턴스(객체)라 한다.

Instance화란? 클래스로부터 객체를 만드는 과정을 클래스의 인스턴스화라 한다.
ex)
 Cat cat = new Cat();